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
a421f9f1
Commit
a421f9f1
authored
Apr 05, 2013
by
Qiang Xue
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactored component event.
parent
31777c92
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
107 additions
and
111 deletions
+107
-111
Component.md
docs/api/base/Component.md
+11
-13
Component.php
framework/base/Component.php
+69
-72
Event.php
framework/base/Event.php
+6
-3
ComponentTest.php
tests/unit/framework/base/ComponentTest.php
+21
-23
No files found.
docs/api/base/Component.md
View file @
a421f9f1
...
...
@@ -7,20 +7,20 @@ is triggered (i.e. comment will be added), our custom code will be executed.
An event is identified by a name that should be unique within the class it is defined at. Event names are
*case-sensitive*
.
One or multiple PHP callbacks, called
*event handlers*
, c
ould
be attached to an event. You can call
[
[trigger()
]
] to
One or multiple PHP callbacks, called
*event handlers*
, c
an
be attached to an event. You can call
[
[trigger()
]
] to
raise an event. When an event is raised, the event handlers will be invoked automatically in the order they were
attached.
To attach an event handler to an event, call
[
[on()
]
]:
~~~
$
comment->on('add
', function($event) {
$
post->on('update
', function($event) {
// send email notification
});
~~~
In the above,
we attach an anonymous function to the "add" event of the comment.
Valid event handlers include
:
In the above,
an anonymous function is attached to the "update" event of the post. You may attach
the following types of event handlers
:
-
anonymous function:
`function($event) { ... }`
-
object method:
`array($object, 'handleAdd')`
...
...
@@ -35,8 +35,8 @@ function foo($event)
where
`$event`
is an
[
[Event
]
] object which includes parameters associated with the event.
You can also attach a
n event handler to an event when configuring a component with a configuration array. The syntax is
like the following:
You can also attach a
handler to an event when configuring a component with a configuration array.
The syntax is
like the following:
~~~
array(
...
...
@@ -46,15 +46,13 @@ array(
where
`on add`
stands for attaching an event to the
`add`
event.
You can call
[
[getEventHandlers()
]
] to retrieve all event handlers that are attached to a specified event. Because this
method returns a
[
[Vector
]
] object, we can manipulate this object to attach/detach event handlers, or adjust their
relative orders.
Sometimes, you may want to associate extra data with an event handler when you attach it to an event
and then access it when the handler is invoked. You may do so by
~~~
$handlers = $comment->getEventHandlers('add');
$handlers->insertAt(0, $callback); // attach a handler as the first one
$handlers[] = $callback; // attach a handler as the last one
unset($handlers[0]); // detach the first handler
$post->on('update', function($event) {
// the data can be accessed via $event->data
}, $data);
~~~
...
...
framework/base/Component.php
View file @
a421f9f1
...
...
@@ -7,6 +7,8 @@
namespace
yii\base
;
use
Yii
;
/**
* Component is the base class that provides the *property*, *event* and *behavior* features.
*
...
...
@@ -17,16 +19,16 @@ namespace yii\base;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class
Component
extends
\yii\base\
Object
class
Component
extends
Object
{
/**
* @var
Vector[]
the attached event handlers (event name => handlers)
* @var
array
the attached event handlers (event name => handlers)
*/
private
$_e
;
private
$_e
vents
;
/**
* @var Behavior[] the attached behaviors (behavior name => behavior)
*/
private
$_b
;
private
$_b
ehaviors
;
/**
* Returns the value of a component property.
...
...
@@ -52,7 +54,7 @@ class Component extends \yii\base\Object
}
else
{
// behavior property
$this
->
ensureBehaviors
();
foreach
(
$this
->
_b
as
$behavior
)
{
foreach
(
$this
->
_b
ehaviors
as
$behavior
)
{
if
(
$behavior
->
canGetProperty
(
$name
))
{
return
$behavior
->
$name
;
}
...
...
@@ -87,17 +89,16 @@ class Component extends \yii\base\Object
return
;
}
elseif
(
strncmp
(
$name
,
'on '
,
3
)
===
0
)
{
// on event: attach event handler
$name
=
trim
(
substr
(
$name
,
3
));
$this
->
getEventHandlers
(
$name
)
->
add
(
$value
);
$this
->
on
(
trim
(
substr
(
$name
,
3
)),
$value
);
return
;
}
elseif
(
strncmp
(
$name
,
'as '
,
3
)
===
0
)
{
// as behavior: attach behavior
$name
=
trim
(
substr
(
$name
,
3
));
$this
->
attachBehavior
(
$name
,
$value
instanceof
Behavior
?
$value
:
\
Yii
::
createObject
(
$value
));
$this
->
attachBehavior
(
$name
,
$value
instanceof
Behavior
?
$value
:
Yii
::
createObject
(
$value
));
}
else
{
// behavior property
$this
->
ensureBehaviors
();
foreach
(
$this
->
_b
as
$behavior
)
{
foreach
(
$this
->
_b
ehaviors
as
$behavior
)
{
if
(
$behavior
->
canSetProperty
(
$name
))
{
$behavior
->
$name
=
$value
;
return
;
...
...
@@ -131,7 +132,7 @@ class Component extends \yii\base\Object
}
else
{
// behavior property
$this
->
ensureBehaviors
();
foreach
(
$this
->
_b
as
$behavior
)
{
foreach
(
$this
->
_b
ehaviors
as
$behavior
)
{
if
(
$behavior
->
canGetProperty
(
$name
))
{
return
$behavior
->
$name
!==
null
;
}
...
...
@@ -161,7 +162,7 @@ class Component extends \yii\base\Object
}
else
{
// behavior property
$this
->
ensureBehaviors
();
foreach
(
$this
->
_b
as
$behavior
)
{
foreach
(
$this
->
_b
ehaviors
as
$behavior
)
{
if
(
$behavior
->
canSetProperty
(
$name
))
{
$behavior
->
$name
=
null
;
return
;
...
...
@@ -198,7 +199,7 @@ class Component extends \yii\base\Object
}
$this
->
ensureBehaviors
();
foreach
(
$this
->
_b
as
$object
)
{
foreach
(
$this
->
_b
ehaviors
as
$object
)
{
if
(
method_exists
(
$object
,
$name
))
{
return
call_user_func_array
(
array
(
$object
,
$name
),
$params
);
}
...
...
@@ -213,8 +214,8 @@ class Component extends \yii\base\Object
*/
public
function
__clone
()
{
$this
->
_e
=
null
;
$this
->
_b
=
null
;
$this
->
_e
vents
=
null
;
$this
->
_b
ehaviors
=
null
;
}
/**
...
...
@@ -259,7 +260,7 @@ class Component extends \yii\base\Object
return
true
;
}
else
{
$this
->
ensureBehaviors
();
foreach
(
$this
->
_b
as
$behavior
)
{
foreach
(
$this
->
_b
ehaviors
as
$behavior
)
{
if
(
$behavior
->
canGetProperty
(
$name
,
$checkVar
))
{
return
true
;
}
...
...
@@ -289,7 +290,7 @@ class Component extends \yii\base\Object
return
true
;
}
else
{
$this
->
ensureBehaviors
();
foreach
(
$this
->
_b
as
$behavior
)
{
foreach
(
$this
->
_b
ehaviors
as
$behavior
)
{
if
(
$behavior
->
canSetProperty
(
$name
,
$checkVar
))
{
return
true
;
}
...
...
@@ -337,44 +338,17 @@ class Component extends \yii\base\Object
public
function
hasEventHandlers
(
$name
)
{
$this
->
ensureBehaviors
();
return
isset
(
$this
->
_e
[
$name
])
&&
$this
->
_e
[
$name
]
->
getCount
();
}
/**
* Returns the list of attached event handlers for an event.
* You may manipulate the returned [[Vector]] object by adding or removing handlers.
* For example,
*
* ~~~
* $component->getEventHandlers($eventName)->insertAt(0, $eventHandler);
* ~~~
*
* @param string $name the event name
* @return Vector list of attached event handlers for the event
*/
public
function
getEventHandlers
(
$name
)
{
if
(
!
isset
(
$this
->
_e
[
$name
]))
{
$this
->
_e
[
$name
]
=
new
Vector
;
}
$this
->
ensureBehaviors
();
return
$this
->
_e
[
$name
];
return
!
empty
(
$this
->
_events
[
$name
]);
}
/**
* Attaches an event handler to an event.
*
* This is equivalent to the following code:
*
* ~~~
* $component->getEventHandlers($eventName)->add($eventHandler);
* ~~~
*
* An event handler must be a valid PHP callback. The followings are
* some examples:
*
* ~~~
* function($event) { ... } // anonymous function
* function
($event) { ... } // anonymous function
* array($object, 'handleClick') // $object->handleClick()
* array('Page', 'handleClick') // Page::handleClick()
* 'handleClick' // global function handleClick()
...
...
@@ -383,31 +357,53 @@ class Component extends \yii\base\Object
* An event handler must be defined with the following signature,
*
* ~~~
* function
handlerName($event) {}
* function
($event)
* ~~~
*
* where `$event` is an [[Event]] object which includes parameters associated with the event.
*
* @param string $name the event name
* @param string|array|\Closure $handler the event handler
* @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
function
on
(
$name
,
$handler
)
public
function
on
(
$name
,
$handler
,
$data
=
null
)
{
$this
->
getEventHandlers
(
$name
)
->
add
(
$handler
);
$this
->
ensureBehaviors
();
$this
->
_events
[
$name
][]
=
array
(
$handler
,
$data
);
}
/**
* Detaches an existing event handler from this component.
* This method is the opposite of [[on()]].
* @param string $name event name
* @param string|array|\Closure $handler the event handler to be removed
* @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
function
off
(
$name
,
$handler
)
public
function
off
(
$name
,
$handler
=
null
)
{
return
$this
->
getEventHandlers
(
$name
)
->
remove
(
$handler
)
!==
false
;
$this
->
ensureBehaviors
();
if
(
isset
(
$this
->
_events
[
$name
]))
{
if
(
$handler
===
null
)
{
$this
->
_events
[
$name
]
=
array
();
}
else
{
$removed
=
false
;
foreach
(
$this
->
_events
[
$name
]
as
$i
=>
$event
)
{
if
(
$event
[
0
]
===
$handler
)
{
unset
(
$this
->
_events
[
$name
][
$i
]);
$removed
=
true
;
}
}
if
(
$removed
)
{
$this
->
_events
[
$name
]
=
array_values
(
$this
->
_events
[
$name
]);
}
return
$removed
;
}
}
return
false
;
}
/**
...
...
@@ -420,7 +416,7 @@ class Component extends \yii\base\Object
public
function
trigger
(
$name
,
$event
=
null
)
{
$this
->
ensureBehaviors
();
if
(
isset
(
$this
->
_e
[
$name
])
&&
$this
->
_e
[
$name
]
->
getCount
(
))
{
if
(
!
empty
(
$this
->
_events
[
$name
]
))
{
if
(
$event
===
null
)
{
$event
=
new
Event
;
}
...
...
@@ -429,8 +425,9 @@ class Component extends \yii\base\Object
}
$event
->
handled
=
false
;
$event
->
name
=
$name
;
foreach
(
$this
->
_e
[
$name
]
as
$handler
)
{
call_user_func
(
$handler
,
$event
);
foreach
(
$this
->
_events
[
$name
]
as
$handler
)
{
$event
->
data
=
$handler
[
1
];
call_user_func
(
$handler
[
0
],
$event
);
// stop further handling if the event is handled
if
(
$event
instanceof
Event
&&
$event
->
handled
)
{
return
;
...
...
@@ -447,7 +444,7 @@ class Component extends \yii\base\Object
public
function
getBehavior
(
$name
)
{
$this
->
ensureBehaviors
();
return
isset
(
$this
->
_b
[
$name
])
?
$this
->
_b
[
$name
]
:
null
;
return
isset
(
$this
->
_b
ehaviors
[
$name
])
?
$this
->
_behaviors
[
$name
]
:
null
;
}
/**
...
...
@@ -457,20 +454,20 @@ class Component extends \yii\base\Object
public
function
getBehaviors
()
{
$this
->
ensureBehaviors
();
return
$this
->
_b
;
return
$this
->
_b
ehaviors
;
}
/**
* Attaches a behavior to this component.
* This method will create the behavior object based on the given
* configuration. After that, the behavior object will be attached to
* this component by calling the [[Behavior::attach]] method.
* this component by calling the [[Behavior::attach
()
]] method.
* @param string $name the name of the behavior.
* @param string|array|Behavior $behavior the behavior configuration. This can be one of the following:
*
* - a [[Behavior]] object
* - a string specifying the behavior class
* - an object configuration array that will be passed to [[
\
Yii::createObject()]] to create the behavior object.
* - an object configuration array that will be passed to [[Yii::createObject()]] to create the behavior object.
*
* @return Behavior the behavior object
* @see detachBehavior
...
...
@@ -498,15 +495,15 @@ class Component extends \yii\base\Object
/**
* Detaches a behavior from the component.
* The behavior's [[Behavior::detach]] method will be invoked.
* The behavior's [[Behavior::detach
()
]] method will be invoked.
* @param string $name the behavior's name.
* @return Behavior the detached behavior. Null if the behavior does not exist.
*/
public
function
detachBehavior
(
$name
)
{
if
(
isset
(
$this
->
_b
[
$name
]))
{
$behavior
=
$this
->
_b
[
$name
];
unset
(
$this
->
_b
[
$name
]);
if
(
isset
(
$this
->
_b
ehaviors
[
$name
]))
{
$behavior
=
$this
->
_b
ehaviors
[
$name
];
unset
(
$this
->
_b
ehaviors
[
$name
]);
$behavior
->
detach
();
return
$behavior
;
}
else
{
...
...
@@ -519,12 +516,12 @@ class Component extends \yii\base\Object
*/
public
function
detachBehaviors
()
{
if
(
$this
->
_b
!==
null
)
{
foreach
(
$this
->
_b
as
$name
=>
$behavior
)
{
if
(
$this
->
_b
ehaviors
!==
null
)
{
foreach
(
$this
->
_b
ehaviors
as
$name
=>
$behavior
)
{
$this
->
detachBehavior
(
$name
);
}
}
$this
->
_b
=
array
();
$this
->
_b
ehaviors
=
array
();
}
/**
...
...
@@ -532,8 +529,8 @@ class Component extends \yii\base\Object
*/
public
function
ensureBehaviors
()
{
if
(
$this
->
_b
===
null
)
{
$this
->
_b
=
array
();
if
(
$this
->
_b
ehaviors
===
null
)
{
$this
->
_b
ehaviors
=
array
();
foreach
(
$this
->
behaviors
()
as
$name
=>
$behavior
)
{
$this
->
attachBehaviorInternal
(
$name
,
$behavior
);
}
...
...
@@ -549,12 +546,12 @@ class Component extends \yii\base\Object
private
function
attachBehaviorInternal
(
$name
,
$behavior
)
{
if
(
!
(
$behavior
instanceof
Behavior
))
{
$behavior
=
\
Yii
::
createObject
(
$behavior
);
$behavior
=
Yii
::
createObject
(
$behavior
);
}
if
(
isset
(
$this
->
_b
[
$name
]))
{
$this
->
_b
[
$name
]
->
detach
();
if
(
isset
(
$this
->
_b
ehaviors
[
$name
]))
{
$this
->
_b
ehaviors
[
$name
]
->
detach
();
}
$behavior
->
attach
(
$this
);
return
$this
->
_b
[
$name
]
=
$behavior
;
return
$this
->
_b
ehaviors
[
$name
]
=
$behavior
;
}
}
framework/base/Event.php
View file @
a421f9f1
...
...
@@ -15,12 +15,14 @@ namespace yii\base;
* And the [[handled]] property indicates if the event is handled.
* If an event handler sets [[handled]] to be true, the rest of the
* uninvoked handlers will no longer be called to handle the event.
* Additionally, an event may specify extra parameters via the [[data]] property.
*
* Additionally, when attaching an event handler, extra data may be passed
* and be available via the [[data]] property when the event handler is invoked.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class
Event
extends
\yii\base\
Object
class
Event
extends
Object
{
/**
* @var string the event name. This property is set by [[Component::trigger()]].
...
...
@@ -39,7 +41,8 @@ class Event extends \yii\base\Object
*/
public
$handled
=
false
;
/**
* @var mixed extra custom data associated with the event.
* @var mixed the data that is passed to [[Component::on()]] when attaching an event handler.
* Note that this varies according to which event handler is currently executing.
*/
public
$data
;
}
tests/unit/framework/base/ComponentTest.php
View file @
a421f9f1
...
...
@@ -41,12 +41,12 @@ class ComponentTest extends TestCase
$component
->
attachBehavior
(
'a'
,
$behavior
);
$this
->
assertSame
(
$behavior
,
$component
->
getBehavior
(
'a'
));
$component
->
on
(
'test'
,
'fake'
);
$this
->
assert
Equals
(
1
,
$component
->
getEventHandlers
(
'test'
)
->
count
);
$this
->
assert
True
(
$component
->
hasEventHandlers
(
'test'
)
);
$clone
=
clone
$component
;
$this
->
assertNotSame
(
$component
,
$clone
);
$this
->
assertNull
(
$clone
->
getBehavior
(
'a'
));
$this
->
assert
Equals
(
0
,
$clone
->
getEventHandlers
(
'test'
)
->
count
);
$this
->
assert
False
(
$clone
->
hasEventHandlers
(
'test'
)
);
}
public
function
testHasProperty
()
...
...
@@ -151,34 +151,32 @@ class ComponentTest extends TestCase
public
function
testOn
()
{
$this
->
assert
Equals
(
0
,
$this
->
component
->
getEventHandlers
(
'click'
)
->
getCount
(
));
$this
->
assert
False
(
$this
->
component
->
hasEventHandlers
(
'click'
));
$this
->
component
->
on
(
'click'
,
'foo'
);
$this
->
assertEquals
(
1
,
$this
->
component
->
getEventHandlers
(
'click'
)
->
getCount
());
$this
->
component
->
on
(
'click'
,
'bar'
);
$this
->
assertEquals
(
2
,
$this
->
component
->
getEventHandlers
(
'click'
)
->
getCount
());
$p
=
'on click'
;
$this
->
component
->
$p
=
'foo2'
;
$this
->
assertEquals
(
3
,
$this
->
component
->
getEventHandlers
(
'click'
)
->
getCount
());
$this
->
assertTrue
(
$this
->
component
->
hasEventHandlers
(
'click'
));
$this
->
component
->
getEventHandlers
(
'click'
)
->
add
(
'test'
);
$this
->
assertEquals
(
4
,
$this
->
component
->
getEventHandlers
(
'click'
)
->
getCount
());
$this
->
assertFalse
(
$this
->
component
->
hasEventHandlers
(
'click2'
));
$p
=
'on click2'
;
$this
->
component
->
$p
=
'foo2'
;
$this
->
assertTrue
(
$this
->
component
->
hasEventHandlers
(
'click2'
));
}
public
function
testOff
()
{
$this
->
assertFalse
(
$this
->
component
->
hasEventHandlers
(
'click'
));
$this
->
component
->
on
(
'click'
,
'foo'
);
$this
->
component
->
on
(
'click'
,
array
(
$this
->
component
,
'myEventHandler
'
));
$this
->
assertEquals
(
2
,
$this
->
component
->
getEventHandlers
(
'click'
)
->
getCount
()
);
$result
=
$this
->
component
->
off
(
'click'
,
'foo'
);
$this
->
assertTrue
(
$result
);
$this
->
assertEquals
(
1
,
$this
->
component
->
getEventHandlers
(
'click'
)
->
getCount
()
);
$
result
=
$this
->
component
->
off
(
'click'
,
'foo
'
);
$this
->
assert
False
(
$result
);
$this
->
assertEquals
(
1
,
$this
->
component
->
getEventHandlers
(
'click'
)
->
getCount
()
);
$
result
=
$this
->
component
->
off
(
'click'
,
array
(
$this
->
component
,
'myEventHandler
'
));
$this
->
assertTrue
(
$result
);
$this
->
assert
Equals
(
0
,
$this
->
component
->
getEventHandlers
(
'click'
)
->
getCount
(
));
$this
->
assertTrue
(
$this
->
component
->
hasEventHandlers
(
'click
'
));
$this
->
component
->
off
(
'click'
,
'foo'
);
$this
->
assertFalse
(
$this
->
component
->
hasEventHandlers
(
'click'
));
$this
->
component
->
on
(
'click2'
,
'foo'
);
$this
->
component
->
on
(
'click2'
,
'foo2'
);
$
this
->
component
->
on
(
'click2'
,
'foo3
'
);
$this
->
assert
True
(
$this
->
component
->
hasEventHandlers
(
'click2'
)
);
$this
->
component
->
off
(
'click2'
,
'foo3'
);
$
this
->
assertTrue
(
$this
->
component
->
hasEventHandlers
(
'click2
'
));
$this
->
component
->
off
(
'click2'
);
$this
->
assert
False
(
$this
->
component
->
hasEventHandlers
(
'click2'
));
}
public
function
testTrigger
()
...
...
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