Chapter 17 - Extending Symfony
==============================
Eventually, you will need to alter symfony's behavior. Whether you need to modify the way a certain class behaves or add your own custom features, the moment will inevitably happen--all clients have specific requirements that no framework can forecast. As a matter of fact, this situation is so common that symfony provides a mechanism to extend existing classes at runtime, beyond simple class inheritance. You can even replace the core symfony classes on your own, using the factories settings. Once you have built an extension, you can easily package it as a plug-in, so that it can be reused in other applications--or by other symfony users.
Events
------
Among the current limitations of PHP, one of the most annoying is you can't have a class extend more than one class. Another limitation is you can't add new methods to an existing class or override existing methods. To palliate these two limitations and to make the framework truly extendable, symfony introduces an *event system*, inspired by the Cocoa notification center, and based on the Observer design pattern ([http://en.wikipedia.org/wiki/Observer_pattern](http://en.wikipedia.org/wiki/Observer_pattern)).
### Understanding Events
Some of the symfony classes "notify an event" at various moments of their life. For instance, when the user changes its culture, the user object notifies a `change_culture` event. This event is like a shout in the project's space, saying: "I'm doing that. Do whatever you want about it".
You can decide to do something special when an event is fired. For instance, you could save the user culture to a database table each time the `change_culture` event is notified, to remember the user prefered culture. In order to do so, you need to *register an event listener*, which is a complicated sentence to say that you must declare a function to be called when the event occurs. Listing 17-1 shows how to register a listener on the user's `change_culture` event.
Listing 17-1 - Registering an Event Listener
[php]
$dispatcher->connect('user.change_culture', 'changeUserCulture');
function changeUserCulture(sfEvent $event)
{
$user = $event->getSubject();
$culture = $event['culture'];
// do something with the user culture
}
All events and listener registrations are managed by a special object called the *event dispatcher*. This object is available from everywhere in symfony by way of the `sfContext` singleton, and most symfony objects offer a `getDispatcher()` method to get direct access to it. Using the dispatcher's `connect()` method, you can register any PHP callable (either a class method or a function) to be called when an event occurs. The first argument of `connect()` is the event identifier, which is a string composed of a namespace and a name. The second argument is a PHP callable.
Once the function registered in the event dispatcher, it sits and waits until the event is fired. The event dispatcher keeps a record of all event listeners, and knows which ones to call when an event is notified. When calling these methods or functions, the dispatcher passes them an `sfEvent` object as parameter.
The event object stores information about the notified event. The event notifier can be retrieved thanks to the `getSubject()` method, and the event parameters are accessible by using the event object as an array (for example, `$event['culture']` can be used to retrieve the `culture` parameter passed by `sfUser` when notifying `user.change_culture`).
To wrap it up, the event system allows you to add abilities to an existing class or modify its methods at runtime, without using inheritance.
>**NOTE**: In version 1.0, symfony used a similar system but with a different syntax. You may see calls to static methods of an `sfMixer` class to register and notify events in symfony 1.0 code, instead of calls to methods of the event dispatcher. `sfMixer` calls are deprecated, yet they still work in symfony 1.1.
### Notifying an Event
Just like symfony classes notify events, your own classes can offer runtime extensibility and notify events at certain occasions. For instance, let's say that your application requests several third-party web services, and that you have written a `sfRestRequest` class to wrap the REST logic of these requests. A good idea would be to notify an event each time this class makes a new request. This would make the addition of logging or caching capabilities easier in the future. Listing 17-2 shows the code you need to add to an existing `fetch()` method to make it notify an event.
Listing 17-2 - Notifying an Event
[php]
class sfRestRequest
{
protected $dispatcher = null;
public function __construct(sfEventDispatcher $dispatcher)
{
$this->dispatcher = $dispatcher;
}
/**
* Makes a query to an external web service
*/
public function fetch($uri, $parameters = array())
{
// Notify the beginning of the fetch process
$this->dispatcher->notify(new sfEvent($this, 'rest_request.fetch_prepare', array(
'uri' => $uri,
'parameters' => $parameters
)));
// Make the request and store the result in a $result variable
// ...
// Notify the end of the fetch process
$this->dispatcher->notify(new sfEvent($this, 'rest_request.fetch_success', array(
'uri' => $uri,
'parameters' => $parameters,
'result' => $result
)));
return $result;
}
}
The `notify()` method of the event dispatcher expects an `sfEvent` object as argument; this is the very same object that is passed to the event listeners. This object always carries a reference to the notifier (that's why the event instance is initialized with `this`) and an event identifier. Optionally, it accepts an associative array of parameters, giving listeners a way to interact with the notifier's logic.
>**TIP**
>Only the classes that notify events can be extended by way of the event system. So even if you don't know whether you will need to extend a class in the future or not, it is always a good idea to add notifications in the key methods.
### Notifying an Event Until a Listener handles it
By using the `notify()` method, you make sure that all the listeners registered on the notified event are executed. But in some cases, you need to allow a listener to stop the event and prevent further listeners from being notified about it. In this case, you should use `notifyUntil()` instead of `notify()`. The dispatcher will then execute all listeners until one returns `true`, and then stop the event notification. In other terms, `notifyUntil()` is like a shout in the project space saying: "I'm doing that. If somebody cares, then I won't tell anybody else". Listing 17-3 shows how to use this technique in combination with a magic `__call()` method to add methods to an existing class at runtime.
Listing 17-3 - Notifying an Event Until a Listener Returns True
[php]
class sfRestRequest
{
// ...
public function __call($method, $arguments)
{
$event = $this->dispatcher->notifyUntil(new sfEvent($this, 'rest_request.method_not_found', array(
'method' => $method,
'arguments' => $arguments
)));
if (!$event->isProcessed())
{
throw new sfException(sprintf('Call to undefined method %s::%s.', get_class($this), $method));
}
return $event->getReturnValue();
}
}
An event listener registered on the `rest_request.method_not_found` event can test the requested `$method` and decide to handle it, or pass to the next event listener callable. In Listing 17-4, you can see how a third party class can add `put()` and `delete()` methods to the `sfRestRequest` class at runtime with this
没有合适的资源?快使用搜索试试~ 我知道了~
symfony1.2.1版本
共2918个文件
php:2011个
dat:248个
yml:175个
5星 · 超过95%的资源 需积分: 9 22 下载量 42 浏览量
2008-12-25
17:42:07
上传
评论
收藏 5.47MB ZIP 举报
温馨提示
symfony 的1.2.1版本 是一个为 PHP5 项目开发而编制的 web application framework
资源推荐
资源详情
资源评论
收起资源包目录
symfony1.2.1版本 (2918个子文件)
LICENSE.Agavi 1KB
propel-gen.bat 1KB
symfony.bat 1KB
pear-propel-gen.bat 1KB
CHANGELOG 23KB
COPYRIGHT 2KB
main.css 7KB
calendar-system.css 6KB
theme.css 6KB
default.css 5KB
default.css 5KB
screen.css 3KB
global.css 2KB
global.css 2KB
input_auto_complete_tag.css 442B
main.css 379B
main.css 379B
main.css 379B
main.css 220B
ie.css 58B
ie6.css 0B
main.css 0B
ko.dat 58KB
en.dat 56KB
it.dat 56KB
zh.dat 56KB
ja.dat 56KB
pt.dat 55KB
fi.dat 54KB
sv.dat 54KB
da.dat 51KB
uk.dat 50KB
bg.dat 48KB
zh_Hant.dat 48KB
el.dat 47KB
fr.dat 46KB
nl.dat 46KB
es.dat 45KB
ru.dat 43KB
nb.dat 43KB
is.dat 41KB
hu.dat 41KB
cs.dat 40KB
de.dat 40KB
tr.dat 39KB
ga.dat 38KB
pl.dat 36KB
sk.dat 35KB
mk.dat 31KB
hr.dat 28KB
mt.dat 27KB
fa.dat 22KB
th.dat 20KB
sr.dat 19KB
ta.dat 17KB
id.dat 17KB
hi.dat 17KB
ar.dat 17KB
he.dat 16KB
mime_types.dat 16KB
eo.dat 14KB
sr_Latn.dat 13KB
ca.dat 13KB
sl.dat 12KB
am.dat 12KB
lt.dat 11KB
lv.dat 11KB
vi.dat 11KB
ro.dat 11KB
et.dat 11KB
hy.dat 10KB
nn.dat 10KB
root.dat 10KB
ms.dat 10KB
kok.dat 9KB
mr.dat 8KB
bn.dat 7KB
sq.dat 7KB
fa_AF.dat 6KB
af.dat 6KB
fo.dat 6KB
ps.dat 5KB
eu.dat 5KB
so.dat 5KB
sw.dat 4KB
pt_PT.dat 3KB
gu.dat 2KB
kn.dat 2KB
te.dat 2KB
pa.dat 2KB
be.dat 2KB
kk.dat 2KB
ml.dat 2KB
ti_ER.dat 1KB
ti.dat 1KB
or.dat 1KB
kl.dat 1KB
gl.dat 1KB
om.dat 1KB
gv.dat 1KB
共 2918 条
- 1
- 2
- 3
- 4
- 5
- 6
- 30
资源评论
- 沉意2012-11-12老版本了,不过还是下下来重新温习哈
wangunix
- 粉丝: 1
- 资源: 6
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功