Yii Framework Forum: Events in 2.0 - Yii Framework Forum

Jump to content

  • (2 Pages)
  • +
  • 1
  • 2
  • You cannot start a new topic
  • You cannot reply to this topic

Events in 2.0

#1 User is offline   phpnode 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 141
  • Joined: 18-April 11

Posted 09 March 2012 - 06:03 AM

I was wondering how events will work in 2.0, the current implementation requires quite a lot of boiler plate code (beforeSave(), onBeforeSave()). It might be better to approach events partly in the same way jQuery does

$model = new User;
$model->on("beforeSave", function($event) { $event->isValid = false; } );
// or
$model->on("beforeSave", array("myClass", "myMethod"));

// in the save method
if (!$this->trigger("beforeSave", array("someParam" => "someValueToBePassedToEachEventHandler")) {
    return false
}


This approach considerably reduces the boiler plate, and i don't really see any disadvantages, it also means that you can create new events and listen for them on the fly, without having to change the component's code. The only problem is how to document the events. Perhaps we could use a php doc tag in the class definition:
/**
 * @event beforeSave invoked before a record is saved
 * @event afterSave invoked after a record is saved
 */

0

#2 User is offline   PoL 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 506
  • Joined: 05-November 08
  • Location:Buenos Aires, Argentina

Posted 09 March 2012 - 06:21 AM

This will also allow to use "namespaced" events. For example
$model->on("beforeSave.edit", function() {});
$model->on("beforeSave.create", function() {});


But this also requires a pool of events (per object??)...

Interesting....
Don't say what you think, think what you say
The problem is communication! Excess of communication!
0

#3 User is offline   phpnode 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 141
  • Joined: 18-April 11

Posted 09 March 2012 - 07:26 AM

it would also be interesting to allow application wide events, that are invoked after the local events fire, so you could do something like:
Yii::app()->onGlobal("CActiveRecord", "beforeSave", function($event) { echo "This is triggered before any model saves"; });

0

#4 User is offline   qiang 

  • Yii Project Lead
  • Yii
  • Group: Yii Dev Team
  • Posts: 5,874
  • Joined: 04-October 08
  • Location:DC, USA

Posted 09 March 2012 - 11:04 AM

One of the main reasons for the current event design (i.e. using an on-method to declare an event) is to make event declaration more explicit and better documented (such as what the event parameter would be). And because of this explicit declaration, it also allows events to be bound like a property (i.e. you can use configuration array to initialize a component).

Event binding should be similar here:
// your version
$model->on("beforeSave", function($event) { $event->isValid = false; } );
// current Yii version
$model->onBeforeSave = function($event) { $event->isValid = false; } ;


@PoL: What is the benefit of having namespaced events?
0

#5 User is offline   samdark 

  • Having fun
  • Yii
  • Group: Yii Dev Team
  • Posts: 3,333
  • Joined: 17-January 09
  • Location:Russia

Posted 09 March 2012 - 11:38 AM

@Qiang, I believe he's talking about signal-slot model where you can use events w/o declaring these and just calling Event::raise('some.name', $arguments) and components are using Event::subscribe('some.name', function($arguments){…}). So it's quite different.

@everyone, here's a good overview of common component interaction methods including different ways to bind/handle events: http://blog.ircmaxel...ins-in-php.html
Yii 1.1 Application Development Cookbook

Enjoying Yii? Star us at github: 1.1 and 2.0.
0

#6 User is offline   PoL 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 506
  • Joined: 05-November 08
  • Location:Buenos Aires, Argentina

Posted 09 March 2012 - 11:43 AM

@qiang: May be an extension can only react to events declared by that extension only. Declaring and raising events with it's own namespace.
Don't say what you think, think what you say
The problem is communication! Excess of communication!
0

#7 User is offline   phpnode 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 141
  • Joined: 18-April 11

Posted 09 March 2012 - 11:43 AM

@qiang - you could still allow this, in a slightly different way:
$config = array(
    "class" => "myClass",
    "eventHandlers" => array(
        "beforeSave" => function ($event) { foo(); },
        "afterSave" => function ($event) { bar(); },
    )
);
$component = Yii::createComponent($config);

$component->on("beforeSave", function($event) { echo "before save"; });
$conponent->eventHandlers["afterSave"] = function($event) { echo "after save"; });


The main benefit is that we can add new events to existing classes, without having to edit their source or extend them.
0

#8 User is offline   Rodrigo Coelho 

  • Master Member
  • PipPipPipPip
  • Yii
  • Group: Members
  • Posts: 664
  • Joined: 05-August 10
  • Location:Rio de Janeiro, Brazil

Posted 09 March 2012 - 01:11 PM

View Postphpnode, on 09 March 2012 - 11:43 AM, said:

The main benefit is that we can add new events to existing classes, without having to edit their source or extend them.


Maybe I didn't get it, but here's my question anyway: if you add an event to a class without editing or extending it, where/how is the event raised?
2

#9 User is offline   qiang 

  • Yii Project Lead
  • Yii
  • Group: Yii Dev Team
  • Posts: 5,874
  • Joined: 04-October 08
  • Location:DC, USA

Posted 09 March 2012 - 01:46 PM

@phpnode: could you please explain the use cases that would need to add new events to existing classes?
0

#10 User is offline   phpnode 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 141
  • Joined: 18-April 11

Posted 09 March 2012 - 01:46 PM

View Postmentel, on 09 March 2012 - 01:11 PM, said:

Maybe I didn't get it, but here's my question anyway: if you add an event to a class without editing or extending it, where/how is the event raised?


Via a behavior, or from another event (beforeSave could raise beforeRegister on a user model if the user model is new), or from elsewhere in your application. Behaviors are the main use case I think.
1

#11 User is offline   qiang 

  • Yii Project Lead
  • Yii
  • Group: Yii Dev Team
  • Posts: 5,874
  • Joined: 04-October 08
  • Location:DC, USA

Posted 09 March 2012 - 02:01 PM

Thanks for your explanation. I will consider your suggestion.

Namespaced events seem to be only meaningful for global events. I'm not sure whether or not we need global event yet.
0

#12 User is offline   Rodrigo Coelho 

  • Master Member
  • PipPipPipPip
  • Yii
  • Group: Members
  • Posts: 664
  • Joined: 05-August 10
  • Location:Rio de Janeiro, Brazil

Posted 09 March 2012 - 03:26 PM

View Postphpnode, on 09 March 2012 - 01:46 PM, said:

Via a behavior, or from another event (beforeSave could raise beforeRegister on a user model if the user model is new), or from elsewhere in your application. Behaviors are the main use case I think.


Understood. And interesting.

View Postphpnode, on 09 March 2012 - 01:46 PM, said:

or from elsewhere in your application


But, in this case, I don't think that the event is indeed of the class it's been attached to.
If another class is raising the event, shouldn't the event be of this class?
0

#13 User is offline   samdark 

  • Having fun
  • Yii
  • Group: Yii Dev Team
  • Posts: 3,333
  • Joined: 17-January 09
  • Location:Russia

Posted 10 March 2012 - 05:14 AM

@phpnode was your suggestion inspired by backbone.js?
Yii 1.1 Application Development Cookbook

Enjoying Yii? Star us at github: 1.1 and 2.0.
0

#14 User is offline   phpnode 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 141
  • Joined: 18-April 11

Posted 10 March 2012 - 06:59 AM

@samdark not backbone specifically, they follow a similar convention to jQuery (or jQuery follows them, I'm not sure which came first), but I think this approach, and the syntax: on(), off(), trigger() are quite common, and self explanatory.
0

#15 User is offline   yiqing95 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 586
  • Joined: 27-December 10
  • Location:china

Posted 16 March 2012 - 08:49 AM

View Postqiang, on 09 March 2012 - 02:01 PM, said:

Thanks for your explanation. I will consider your suggestion.

Namespaced events seem to be only meaningful for global events. I'm not sure whether or not we need global event yet.

@qiang : it 's very useful , like jquery 's global ajax event . we can listen the global event to make sure some functionality(similar functionality) handling go together but scatter to everywhere .

by the way i think it 's useful too introduce another event mechanism as symfony ' event dispatcher (don't need declare the event first(pseudo code ) : $eventDispatcher->raiseEvent('anyStringAsEventId',array(../*eventObj or some customer data */)); you should register your eventListener before the raiseEvent : $eventDispatcher->listen('someEvent',array(/*php callable here */)) ; another way is search the event listener in raiseEvent method ,thus we can raise any event in any module ,listening event is the same .when search the event listener we should obey some convention eg: events dir for listening event from anther modules ).
0

#16 User is offline   qiang 

  • Yii Project Lead
  • Yii
  • Group: Yii Dev Team
  • Posts: 5,874
  • Joined: 04-October 08
  • Location:DC, USA

Posted 27 March 2012 - 10:47 PM

I have implemented the proposed new event system in 2.0. Below are some usage examples:

// attach an anonymous function to the 'click' event
$button->on('click', function($event) { ... });
// trigger the 'click' event
$button->trigger('click', new Event($this));
// detaches $callback from 'click'
$button->off('click', $callback);
// returns event handlers of 'click' as a vector object so that we can manipulate it
$handlers = $button->getEventHandlers('click');


It is also possible to attach an event handler in a configuration array:
$this->widget('Button', array(
    'name' => 'submit',
    'on click' => function($event) {...}
));


Other proposals are not implemented until we see enough evidence they are useful.
4

#17 User is offline   phpnode 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 141
  • Joined: 18-April 11

Posted 28 March 2012 - 04:04 AM

View Postqiang, on 27 March 2012 - 10:47 PM, said:

I have implemented the proposed new event system in 2.0. Below are some usage examples:

// attach an anonymous function to the 'click' event
$button->on('click', function($event) { ... });
// trigger the 'click' event
$button->trigger('click', new Event($this));
// detaches $callback from 'click'
$button->off('click', $callback);
// returns event handlers of 'click' as a vector object so that we can manipulate it
$handlers = $button->getEventHandlers('click');


It is also possible to attach an event handler in a configuration array:
$this->widget('Button', array(
    'name' => 'submit',
    'on click' => function($event) {...}
));


Other proposals are not implemented until we see enough evidence they are useful.


Great news, thanks!
0

#18 User is offline   Jaggi 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 90
  • Joined: 05-September 11

Posted 28 March 2012 - 04:06 AM

View Postqiang, on 27 March 2012 - 10:47 PM, said:

It is also possible to attach an event handler in a configuration array:
$this->widget('Button', array(
    'name' => 'submit',
    'on click' => function($event) {...}
));


Other proposals are not implemented until we see enough evidence they are useful.


could we drop the on bit in the widget array to make it simplier?
See my development site @ www.CodeTheInter.net (BETA)

Posted Image Posted Image

Quote

If you make it idiot proof, they'll build a better idiot
0

#19 User is offline   phpnode 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 141
  • Joined: 18-April 11

Posted 28 March 2012 - 04:15 AM

View PostJaggi, on 28 March 2012 - 04:06 AM, said:

could we drop the on bit in the widget array to make it simplier?


That won't work if you have properties with the same name as the event, i think qiang's implementation is absolutely fine. One thing though, the second parameter to trigger() should be optional, it should just raise a new default event with the object as the sender if it isn't specified
1

#20 User is offline   Ben 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 266
  • Joined: 15-March 09

Posted 28 March 2012 - 07:38 AM

View Postqiang, on 27 March 2012 - 10:47 PM, said:

// attach an anonymous function to the 'click' event
$button->on('click', function($event) { ... });
// trigger the 'click' event
$button->trigger('click', new Event($this));
// detaches $callback from 'click'
$button->off('click', $callback);
// returns event handlers of 'click' as a vector object so that we can manipulate it
$handlers = $button->getEventHandlers('click');



Just curious: is "trigger" really public? Or was this just for demonstration purpose? I implemented it as protected, because I can't see a reason why events should be triggered from outside.

Can you please include the event name in the "Event" object when it gets triggered? Would be helpful in cases where one event handler is attached to several events.

Third, I think the second parameter of trigger can be made optional:

class Button extends Component
{
  public function foo()
  {
    $this->trigger('fooEvent');
  }

  public function bar()
  {
    $this->trigger('barEvent', new DerivedEvent);
  }

  public function baz()
  {
    $this->trigger('bazEvent', array(
      'eventParamKey' => 'eventParamValue',
    ));
  }
}

class Component
{
  protected function trigger( $eventName, $event=null )
  {
    if ($event === null)
    {
      $event = new Event();
    }
    else if (is_array($event))
    {
      $params = $event;
      $event = new Event();
      $event->params = $params;
    }

    if ($event instanceof Event)
    {
      $event->sender = $this;
      $event->name = $eventName;
    }
    else
    {
      throw new Exception( "Invalid param" );
    }

    // Event prepared, start your event dispatching logic.
  }
}


Maybe not even hard code the "Event" class, but provide a way to configure the default event class that will be created (must derive from Event).
Don't like ads in my sig...
0

Share this topic:


  • (2 Pages)
  • +
  • 1
  • 2
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users