trigger() should be public, there are definitely scenarios where you’d need this
trigger() should be public, there are definitely scenarios where you’d need this
Well, I wouldn’t mind. Just a minor difference.
But could you provide some use cases? The only one that came to my mind after posting were behaviors. There was a feature request, that they should have the possibility to extend the component they are attached to with new events. With the new event system, they could do this easily by calling:
$this->owner->trigger();
If trigger was protected, they had to raise their own event:
$this->trigger();
Now, if you want to hide the fact, that the event comes from an behavior instead of from the host component, the base Behavior class could easily override Component’s trigger() implementation:
class Behavior extends Component
{
protected function trigger( $eventName, $event=null )
{
if ($event instanceof Event)
{
$event->sender = $this->owner;
$event->name = $eventName;
}
}
}
ben - behaviors are the main use case, keep in mind that behaviors cannot override methods that exist in the attached class so I don’t think your example would work, i also posted another specific use case earlier in the thread: http://www.yiiframework.com/forum/index.php/topic/29653-new-event-system-or-not/page__view__findpost__p__142981
Well, you can’t change what happens when the behavior’s host calls trigger(), but you can override Behavior’s trigger() method which it inherited from Component. This way, the event dispatching logic could be modified for all events originating from Behaviors (setting sender to $this->owner instead of to $this).
I needed a second look to understand your example, so just for reference:
You have an article class
You attach different behaviors to the article (your states)
One of the states defines a read-event
You’re trying to register to this event
Because of the current event system, you need to ensure the article is currently in the correct state before registering
Ideally, you don’t want to bother with article’s state, you just want to configure “if it gets read, call this method”. You shouldn’t have to deal with the fact that it can only be read once it is published.
Now, I don’t know how qiang implemented the new event system. Let’s assume that there’s no way to check if a certain event has been declared. Instead,
$article->on( 'read', function(Event $event) {
echo $event->sender->title . ' has been read!';
});
simply creates a new event for article. Let’s also assume that only your attached state triggers the event (can I make this assumption? If yes, trigger() can be protected). The trigger() implementation could look like this:
class Behavior extends Component
{
protected function trigger( $eventName, $event=null )
{
// we should take into account, that Behavior is a Component, and that maybe
// someone attached event handlers to the Behavior itself instead of to the
// host...
parent::trigger( $eventName, $event );
// now, handle the events which this Behavior triggers as extensions in scope
// of its host...
if ($event === null)
{
$event = new Event();
}
else if (is_array($event))
{
$params = $event;
$event = new Event();
$event->params = $params;
}
if ($event instanceof Event)
{
// that's the important part... We're working in scope of our host.
$event->sender = $this->owner;
$event->name = $eventName;
}
else
{
throw new Exception( "Invalid param" );
}
foreach ($this->owner->getEventHandlers($eventName) as $eventHandler)
{
call_user_func( $eventHandler, $event );
}
}
}
So still no reason why trigger() must be public.
But as I’ve said: no big deal if it was.
Shouldn’t really have those circumstances off the top of my head, another option tho is:
$this->widget('Button', array(
'name' => 'submit',
'events' => array(
'click' => function($event) {...}
)
));
a little more complicated but easier to remember than “on click”, can lots of people doing: ‘onClick’, ‘onclick’, ‘click’ etc.
I like this, but if the "on" has a function? There could be, for example, an "off click" command to remove a default event.
that would be bound at the trigger not an event, as in qiang example before:
// 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);
I would probably use ‘connect’ and ‘disconnect’
A slightly different proposal for the configuration array: use an array of form ‘eventName’ => function
$this->widget('Button', array(
'name' => 'submit',
'on' => array(
'click' => function($event) {...},
'otherEvent' => function($event) {...}
)
));