Development

Documentation/vi_VN/UsingTheSymfonyEventSystem

You must first sign up to be able to contribute.

Trong bài này tôi sẽ hướng dẫn bạn cách sử dụng hệ thống event có sẵn trong symfony. Hãy tưởng tượng bạn có một website mà người dùng có thể bầu chọn cho bức ảnh của những người khác trong hệ thống. Mỗi khi người dùng bầu chọn một bức ảnh, một số hành động xảy ra dựa vào business rule:

  • Tăng điểm cho người dùng ở database
  • Cập nhật số ảnh người dùng đã bầu chọn ở session
  • Xóa cache của template hiển thị số ảnh mà người dùng bầu chọn

Chúng ta có thể override phương thức Image::save() để thêm một hook, khi đó mỗi khi người dùng bầu chọn một bức ảnh 3 hành động này sẽ được thực thi. Điều này có thể đem lại một số hệ quả ko mong muốn: nếu người dùng upload một bức ảnh, chúng ta lưu thông tin vào database nhưng sẽ ko cần xóa cache và chứa thông tin ở session. Tương tự, nếu chúng ta quản lý ảnh ở backend, mỗi khi admin sửa lại một bức ảnh phương thức save() sẽ được gọi kèm theo tất cả các hành động chúng ta đã thêm.

Sử dụng Symfony Event System

Từ version 1.1, symfony cung cấp event notification system. Thông thường, các lớp của framework gửi đi sự kiện ở thời điểm nào đó trong thời gian chạy ứng dụng. Chúng ta có thể đăng kí listener để lắng nghe các event. Chúng ta cũng có thể tự tạo các event của riêng mình.

Bạn có thể tìm hiểu thêm về symfony event system ở các link sau:

Trong ví dụ này, chúng ta sẽ gắn hành động bầu chọn ảnh của người dùng với sự kiện do chúng ta tạo ra.

Ở action rateImage chúng ta thêm dòng sau:

[php]
public function executeRateImage(sfWebRequest $request)
{
 // code for processing the image rate here ...

 $this->dispatcher->notify(new sfEvent($this, 'images.image_rated'));
}

Event images.image_rated sẽ được gắn với action rateImage. Phương thức khởi tạo sfEvent nhận 3 tham số theo thứ tự: event subject, event name và mảng các option của event handler. Do sfEvent implement ArrayAccess interface nên chúng ta có thể gọi các parameter đơn giản như sau: $event['my_parameter'].

TIP Về ArrayAccess interface bạn có thể tìm hiểu trong tài liệu PHP.

Bước tiếp theo là thực hiện việc lắng nghe event này. Chúng ta có thể thêm listeners ở một số chỗ trong ứng dụng symfony. Trong ví dụ này chúng ta sẽ thêm vào trong file cấu hình của application. Thực hiện việc đăng kí listeners như sau:

[php]
class frontendConfiguration extends sfApplicationConfiguration
{
 public function configure()
 {
 // ...

 // Register our listeners
 $this->dispatcher->connect('images.image_rated', array('UsersManager', 'addPointsToUser'));
 $this->dispatcher->connect('images.image_rated', array('UsersManager', 'updateSessionPoints'));
 $this->dispatcher->connect('images.image_rated', array('UsersManager', 'clearRatePartial'));
 }
}

Như bạn có thể thấy, lớp cấu hình application có thể tham chiếu đến symfony event dispatcher. Chúng ta thêm code để notify khi sự kiện images.image_rated xảy ra. Bây giờ, chúng ta tạo lớp UsersManager cung cấp các phương thức để lắng nghe sự kiện. Trước khi đi vào code lớp UsersManager chúng ta sẽ nói về lớp sfEventDispatcher.

Từ symfony book chúng ta biết rằng lớp này cung cấp cơ chế để thêm/xóa listener và notify event. Hãy xem một số phương thức public của sfEventDispatcher:

public function connect($name, $listener)

Chúng ta sử dụng phương thức này trong lớp frontendConfiguration để đăng kí listeners với sự kiện chúng ta tạo ra. Tham số đầu tiên là tên sự kiện (ở đây là images.image_rated) tham số thứ 2 listener là biến kiểu PHP callback.

TIP Chi tiết về PHP callback trong tài liệu PHP.

public function disconnect($name, $listener)

Các tham số của phương thức này giống như phương thức trên, nhưng ở đây chúng ta dùng để xóa một listener. Nếu một module nào đó trong ứng dụng của chúng ta ko cần lắng nghe sự kiện, chúng ta có thể thêm file config.php vào trong thư mục config của module với đoạn code sau:

[php]
$this->dispatcher->disconnect('images.image_rated', array('UsersManager', 'clearRatePartial'));

public function hasListeners($name)

Phương thức này trả về true nếu sự kiện đã đăng kí listeners.

public function getListeners($name)

Nếu chúng ta cần lấy các listener đã đăng kí của một sự kiện, chúng ta có thể sử dụng phương thức này.

Bây giờ đến mã nguồn của UsersManager

[php]
class UsersManager
{
 static public function addPointsToUser(sfEvent $event)
 {
 UserPeer::updateUserPoints($event->getSubject()->getUser()->getPoints() + sfConfig::get('app_points_for_rating'));
 }

 static public function updateSessionPoints(sfEvent $event)
 {
 $user = $event->getSubject()->getUser();
 $user->setPoints($user->getPoints() + sfConfig::get('app_points_for_rating'));
 }

 static public function clearRatePartial(sfEvent $event)
 {
 if ($cache = $event->getSubject()->getContext()->getViewCacheManager())
 {
 $cache->remove('user/points?id='.$event->getSubject()->getUser()->getId());
 }
 }
}

Ở phương thức addPointsToUser(), chúng ta lấy về số điểm hiện tại của người dùng từ session, cộng thêm điểm và chứa vào database.

Phương thức updateSessionPoints() bên dưới hoạt động tương tự nhưng chúng ta cập nhật session.

Note Nếu bạn quan tâm đến cách chúng ta truy cập symfony session user, câu trả lời nằm trong symfony events system. Symfony cung cấp instance của action hiện tại dưới dạng subject của sự kiện chúng ta tạo ra . Trong symfony, action có thể truy cập session user bằng cách gọi $this->getUser(), như chúng ta đã làm trong ví dụ.

Event listener cuối cùng mà chúng ta đăng kí là UsersManager::clearRatePartial(), là một instance của View Cache Manager, thực hiện việc xóa cache tương ứng.

Kết luận

Symfony event system cung cấp cho ứng dụng của bạn những khả năng mới. Nó có thể được dùng để xây dựng các hệ thống highly decouple, leaving away glue code. Sử dụng công nghệ này, bạn có thể dễ dàng xây dựng slim controllers để tận dụng tối đa sức mạnh của MVC.

huu2uan [at] gmail [dot] com