bwoester/yii-static-events-component

在类级别上附加事件。

v1.0.2 2013-10-20 23:31 UTC

This package is not auto-updated.

Last update: 2024-09-24 01:05:43 UTC


README

允许您在类级别上注册事件处理器。

为了实现这一点,该扩展由两部分组成

  1. EventRegistry - 一个应用程序组件,作为注册事件处理器的单一入口点。
  2. EventBridgeBehavior - 一种行为,它监视其所有者并将拦截的事件转发到EventRegistry,该Registry将依次调用已注册的事件处理器。

事件注册允许您将事件处理器静态地附加到事件。这意味着您在类级别而不是在实例级别上附加处理器,就像在Yii中通常所做的那样。您指定“当CActiveRecord调用onAfterConstruct时调用我的事件处理器”而不是“当这个CActiveRecord实例调用onAfterConstruct时调用我的事件处理器”。

当事件注册器接收到由某个对象引发的事件时,它会查找所有已注册的处理器并调用它们。在查找时,它还会考虑继承。这意味着如果有人将事件处理器附加到CActiveRecord::onAfterConstruct,但事件是由MyModel(扩展CActiveRecord)引发的,则附加的事件处理器也将被调用。如果有人将事件处理器附加到MyModel::onAfterConstruct,那么只有在此类(或继承自MyModel的类)引发onAfterConstruct时,他才会被通知。如果事件是由MyModel2(扩展CActiveRecord)引发的,他则不会收到通知。

不幸的是,事件注册器不能监视任意类。相反,它必须与EventBridgeBehavior一起工作。此行为必须附加到您希望以类级别监视的所有类。一些Yii类允许您在配置中附加行为(如CApplicationComponent和CModule,包括其子类CApplication、CConsoleApplication、CWebApplication、CWebModule和GiiModule)。因此,对于这些类来说,确保在创建时附加EventBridgeBehavior很容易。

其他Yii类允许您覆盖名为behaviors()的方法(如CConsoleCommand、CController和CModel,包括其子类)。这些类通常是扩展的,并不直接使用。通常,您会在项目中看到以下内容

public Controller extends CController

public ActiveRecord extends CActiveRecord

并在您的实际控制器和活动记录中扩展这些自定义基类。因此,这可能是一个方便的配置EventBridgeBehavior的位置。

第三组Yii类根本不允许您配置行为(如COutputProcessor或CViewAction),尽管它们定义了一些事件。所以不幸的是,事件桥无法提供帮助。对于这些类,您必须在实例级别上附加行为,因此在类级别上附加事件处理器并追踪实例以附加相应的行为就没有太多意义。相反,您也可以在实例级别上附加事件处理器。

我想到的最后一批Yii类不允许配置行为,但也不提供任何事件。所以我们不必担心它们。

关于EventBridgeBehavior的最后一点:它需要EventInterceptor扩展来捕获其所有者的事件并将其转发到事件注册器。请确保该扩展可用且可自动加载。

// application.config.main
'import' => array(
  // EventInterceptor is required by EventBridgeBehavior
  'ext.components.event-interceptor.*',
),
'behaviors' => array(
  // attach EventBridgeBehavior to application, so we can attach to
  // application events on a per class base.
  'eventBridge' => array(
    'class'  => 'ext.components.static-events.EventBridgeBehavior',
  ),
),
'components' => array(
  'events' => array(
    'class'  => 'ext.components.static-events.EventRegistry',
    'attach' => array(
      // Attach to application events.
      // Again a stupid example. Since there will ever be only one
      // application instance, we could as well use normal per instance
      // event binding like it is done normally in Yii. But it shows how it
      // is meant to be done...
      'CApplication' => array(
        'onBeginRequest' => array(
          function( $event ) {
            Yii::log( 'CApplication::onBeginRequest', CLogger::LEVEL_TRACE );
          },
        ),
        'onEndRequest' => array(
          function( $event ) {
            Yii::log( 'CApplication::onEndRequest - first handler', CLogger::LEVEL_TRACE );
          },
          function( $event ) {
            Yii::log( 'CApplication::onEndRequest - second handler', CLogger::LEVEL_TRACE );
          },
        ),
      ),
    ),
  ),
  'log'=>array(
    'class'=>'CLogRouter',
    'routes'=>array(
      // enable web log route to see what we just logged
      array(
        'class'=>'CWebLogRoute',
      ),
    ),
  ),
),

// or to attach/ detach at runtime:
$events = Yii::app()->events;
$events->attach( 'CActiveRecord', 'onAfterConstruct', $callback );
$events->detach( 'CActiveRecord', 'onAfterConstruct', $callback );