Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yii2
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
PSDI Army
yii2
Commits
8b00693a
Commit
8b00693a
authored
Oct 30, 2013
by
Qiang Xue
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fixes #1025: Implemented support for class-level events.
parent
0ee120f5
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
229 additions
and
4 deletions
+229
-4
Component.php
framework/yii/base/Component.php
+4
-3
Event.php
framework/yii/base/Event.php
+132
-0
ComponentTest.php
tests/unit/framework/base/ComponentTest.php
+0
-1
EventTest.php
tests/unit/framework/base/EventTest.php
+93
-0
No files found.
framework/yii/base/Component.php
View file @
8b00693a
...
...
@@ -358,13 +358,13 @@ class Component extends Object
public
function
hasEventHandlers
(
$name
)
{
$this
->
ensureBehaviors
();
return
!
empty
(
$this
->
_events
[
$name
]);
return
!
empty
(
$this
->
_events
[
$name
])
||
Event
::
hasHandlers
(
$this
,
$name
)
;
}
/**
* Attaches an event handler to an event.
*
*
An
event handler must be a valid PHP callback. The followings are
*
The
event handler must be a valid PHP callback. The followings are
* some examples:
*
* ~~~
...
...
@@ -374,7 +374,7 @@ class Component extends Object
* 'handleClick' // global function handleClick()
* ~~~
*
*
An
event handler must be defined with the following signature,
*
The
event handler must be defined with the following signature,
*
* ~~~
* function ($event)
...
...
@@ -455,6 +455,7 @@ class Component extends Object
}
}
}
Event
::
trigger
(
$this
,
$name
,
$event
);
}
/**
...
...
framework/yii/base/Event.php
View file @
8b00693a
...
...
@@ -45,4 +45,136 @@ class Event extends Object
* Note that this varies according to which event handler is currently executing.
*/
public
$data
;
private
static
$_events
=
[];
/**
* Attaches an event handler to a class-level event.
*
* When a class-level event is triggered, event handlers attached
* to that class and all parent classes will be invoked.
*
* For example, the following code attaches an event handler to `ActiveRecord`'s
* `afterInsert` event:
*
* ~~~
* Event::on([ActiveRecord::className, ActiveRecord::EVENT_AFTER_INSERT], function ($event) {
* Yii::trace(get_class($event->sender) . ' is inserted.');
* });
* ~~~
*
* The handler will be invoked for EVERY successful ActiveRecord insertion.
*
* For more details about how to declare an event handler, please refer to [[Component::on()]].
*
* @param string $class the fully qualified class name to which the event handler needs to attach
* @param string $name the event name
* @param callback $handler the event handler
* @param mixed $data the data to be passed to the event handler when the event is triggered.
* When the event handler is invoked, this data can be accessed via [[Event::data]].
* @see off()
*/
public
static
function
on
(
$class
,
$name
,
$handler
,
$data
=
null
)
{
self
::
$_events
[
$name
][
ltrim
(
$class
,
'\\'
)][]
=
[
$handler
,
$data
];
}
/**
* Detaches an event handler from a class-level event.
*
* This method is the opposite of [[on()]].
*
* @param string $class the fully qualified class name from which the event handler needs to be detached
* @param string $name the event name
* @param callback $handler the event handler to be removed.
* If it is null, all handlers attached to the named event will be removed.
* @return boolean if a handler is found and detached
* @see on()
*/
public
static
function
off
(
$class
,
$name
,
$handler
=
null
)
{
$class
=
ltrim
(
$class
,
'\\'
);
if
(
empty
(
self
::
$_events
[
$name
][
$class
]))
{
return
false
;
}
if
(
$handler
===
null
)
{
unset
(
self
::
$_events
[
$name
][
$class
]);
return
true
;
}
else
{
$removed
=
false
;
foreach
(
self
::
$_events
[
$name
][
$class
]
as
$i
=>
$event
)
{
if
(
$event
[
0
]
===
$handler
)
{
unset
(
self
::
$_events
[
$name
][
$class
][
$i
]);
$removed
=
true
;
}
}
if
(
$removed
)
{
self
::
$_events
[
$name
][
$class
]
=
array_values
(
self
::
$_events
[
$name
][
$class
]);
}
return
$removed
;
}
}
/**
* Returns a value indicating whether there is any handler attached to the specified class-level event.
* Note that this method will also check all parent classes to see if there is any handler attached
* to the named event.
* @param string|object $class the object or the fully qualified class name specifying the class-level event
* @param string $name the event name
* @return boolean whether there is any handler attached to the event.
*/
public
static
function
hasHandlers
(
$class
,
$name
)
{
if
(
empty
(
self
::
$_events
[
$name
]))
{
return
false
;
}
if
(
is_object
(
$class
))
{
$class
=
get_class
(
$class
);
}
else
{
$class
=
ltrim
(
$class
,
'\\'
);
}
do
{
if
(
!
empty
(
self
::
$_events
[
$name
][
$class
]))
{
return
true
;
}
}
while
((
$class
=
get_parent_class
(
$class
))
!==
false
);
return
false
;
}
/**
* Triggers a class-level event.
* This method will cause invocation of event handlers that are attached to the named event
* for the specified class and all its parent classes.
* @param string|object $class the object or the fully qualified class name specifying the class-level event
* @param string $name the event name
* @param Event $event the event parameter. If not set, a default [[Event]] object will be created.
*/
public
static
function
trigger
(
$class
,
$name
,
$event
=
null
)
{
if
(
empty
(
self
::
$_events
[
$name
]))
{
return
;
}
if
(
$event
===
null
)
{
$event
=
new
self
;
}
$event
->
handled
=
false
;
$event
->
name
=
$name
;
if
(
is_object
(
$class
))
{
$class
=
get_class
(
$class
);
}
else
{
$class
=
ltrim
(
$class
,
'\\'
);
}
do
{
if
(
!
empty
(
self
::
$_events
[
$name
][
$class
]))
{
foreach
(
self
::
$_events
[
$name
][
$class
]
as
$handler
)
{
$event
->
data
=
$handler
[
1
];
call_user_func
(
$handler
[
0
],
$event
);
if
(
$event
instanceof
Event
&&
$event
->
handled
)
{
return
;
}
}
}
}
while
((
$class
=
get_parent_class
(
$class
))
!==
false
);
}
}
tests/unit/framework/base/ComponentTest.php
View file @
8b00693a
...
...
@@ -302,7 +302,6 @@ class ComponentTest extends TestCase
$component
->
detachBehaviors
();
$this
->
assertNull
(
$component
->
getBehavior
(
'a'
));
$this
->
assertNull
(
$component
->
getBehavior
(
'b'
));
}
}
...
...
tests/unit/framework/base/EventTest.php
0 → 100644
View file @
8b00693a
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace
yiiunit\framework\base
;
use
yii\base\Component
;
use
yii\base\Event
;
use
yiiunit\TestCase
;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class
EventTest
extends
TestCase
{
public
$counter
;
public
function
setUp
()
{
$this
->
counter
=
0
;
Event
::
off
(
ActiveRecord
::
className
(),
'save'
);
Event
::
off
(
Post
::
className
(),
'save'
);
Event
::
off
(
User
::
className
(),
'save'
);
}
public
function
testOn
()
{
Event
::
on
(
Post
::
className
(),
'save'
,
function
(
$event
)
{
$this
->
counter
+=
1
;
});
Event
::
on
(
ActiveRecord
::
className
(),
'save'
,
function
(
$event
)
{
$this
->
counter
+=
3
;
});
$this
->
assertEquals
(
0
,
$this
->
counter
);
$post
=
new
Post
;
$post
->
save
();
$this
->
assertEquals
(
4
,
$this
->
counter
);
$user
=
new
User
;
$user
->
save
();
$this
->
assertEquals
(
7
,
$this
->
counter
);
}
public
function
testOff
()
{
$handler
=
function
(
$event
)
{
$this
->
counter
++
;
};
$this
->
assertFalse
(
Event
::
hasHandlers
(
Post
::
className
(),
'save'
));
Event
::
on
(
Post
::
className
(),
'save'
,
$handler
);
$this
->
assertTrue
(
Event
::
hasHandlers
(
Post
::
className
(),
'save'
));
Event
::
off
(
Post
::
className
(),
'save'
,
$handler
);
$this
->
assertFalse
(
Event
::
hasHandlers
(
Post
::
className
(),
'save'
));
}
public
function
testHasHandlers
()
{
$this
->
assertFalse
(
Event
::
hasHandlers
(
Post
::
className
(),
'save'
));
$this
->
assertFalse
(
Event
::
hasHandlers
(
ActiveRecord
::
className
(),
'save'
));
Event
::
on
(
Post
::
className
(),
'save'
,
function
(
$event
)
{
$this
->
counter
+=
1
;
});
$this
->
assertTrue
(
Event
::
hasHandlers
(
Post
::
className
(),
'save'
));
$this
->
assertFalse
(
Event
::
hasHandlers
(
ActiveRecord
::
className
(),
'save'
));
$this
->
assertFalse
(
Event
::
hasHandlers
(
User
::
className
(),
'save'
));
Event
::
on
(
ActiveRecord
::
className
(),
'save'
,
function
(
$event
)
{
$this
->
counter
+=
1
;
});
$this
->
assertTrue
(
Event
::
hasHandlers
(
User
::
className
(),
'save'
));
$this
->
assertTrue
(
Event
::
hasHandlers
(
ActiveRecord
::
className
(),
'save'
));
}
}
class
ActiveRecord
extends
Component
{
public
function
save
()
{
$this
->
trigger
(
'save'
);
}
}
class
Post
extends
ActiveRecord
{
}
class
User
extends
ActiveRecord
{
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment