Laravel offers many extension points for you to customize the behavior of the framework's core components, or even replace them entirely. For example, the hashing facilites are defined by a HasherInterface
contract, which you may implement based on your application's requirements. You may also extend the Request
object, allowing you to add your own convenient “helper” methods. You may even add entirely new authentication, cache, and session drivers!
为了方便你自定义框架核心组件,Laravel 提供了大量可以扩展的地方。你甚至可以完全替换掉旧组件。例如:哈希器遵守了HasherInterface
接口,你可以按照你自己应用的需求来重新实现。你也可以扩展Request
对象,添加你自己用的顺手的“helper”方法。你甚至可以添加全新的身份认证、缓存和会话机制!
Laravel components are generally extended in two ways: binding new implementations in the IoC container, or registering an extension with a Manager
class, which are implementations of the “Factory” design pattern. In this chapter we'll explore the various methods of extending the framework and examine the necessary code.
Laravel组件通常有两种扩展方式:在IoC容器里面绑定新实现,或者用Manager
类注册一个扩展,该扩展采用了工厂模式实现。 在本章中我们将探索不同的扩展方式并检查我们都需要些什么代码。
Methods Of Extension 扩展方式
Remember, Laravel components are typically extended in one of two ways: IoC bindings and the
Manager
classes. The manager classes serve as an implementation of the “factory” design pattern, and are responsible for instantiating driver based facilities such as cache and session.要记住Laravel通常有以下两种扩展方式:通过IoC绑定和通过
Manager
类(下文译作“管理类”)。其中管理类实现了工厂设计模式,负责组件的实例化。比如缓存和会话机制。
Laravel has several Manager
classes that manage the creation of driver-based components. These include the cache, session, authentication, and queue components. The manager class is responsible for creating a particular driver implementation based on the application's configuration. For example, the CacheManager
class can create APC, Memcached, Native, and various other implementations of cache drivers.
Laravel有好多Manager
类用来管理基于驱动的组件的生成过程。基于驱动的组件包括:缓存、会话、身份认证、队列组件等。管理类负责根据应用程序的配置,来生成特定的驱动实例。比如:CacheManager
可以创建APC、Memcached、Native、还有其他不同的缓存驱动的实现。
Each of these managers includes an extend
method which may be used to easily inject new driver resolution functionality into the manager. We'll cover each of these managers below, with examples of how to inject custom driver support into each of them.
每个管理类都包含名为extend
的方法,该方法可用于将新功能注入到管理类中。下面我们将逐个介绍管理类,为你展示如何注入自定义的驱动。
Learn About Your Managers 如何了解你的管理类
Take a moment to explore the various
Manager
classes that ship with Laravel, such as theCacheManager
andSessionManager
. Reading through these classes will give you a more thorough understanding of how Laravel works under the hood. All manager classes extend theIlluminate\Support\Manager
base class, which provides some helpful, common functionality for each manager.请花点时间看看Laravel中各个
Manager
类的代码,比如CacheManager
和SessionManager
。通过阅读这些代码能让你对Laravel的管理类机制更加清楚透彻。所有的管理类都继承自Illuminate\Support\Manager
基类,该基类为每一个管理类提供了一些有效且通用的功能。
To extend the Laravel cache facility, we will use the extend
method on the CacheManager
, which is used to bind a custom driver resolver to the manager, and is common across all manager classes. For example, to register a new cache driver named “mongo”, we would do the following:
要扩展Laravel的缓存机制,我们将使用CacheManager
里的extend
方法来绑定我们自定义的缓存驱动。扩展其他的管理类也是类似的。比如,我们想注册一个新的缓存驱动,名叫“mongo”,代码可以这样写:
Cache::extend('mongo', function($app)
{
// Return Illuminate\Cache\Repository instance...
});
The first argument passed to the extend
method is the name of the driver. This will correspond to your driver
option in the app/config/cache.php
configuration file. The second argument is a Closure that should return an Illuminate\Cache\Repository
instance. The Closure will be passed an $app
instance, which is an instance of Illuminate\Foundation\Application
and an IoC container.
extend
方法的第一个参数是你要定义的驱动的名字。该名字对应着app/config/cache.php
配置文件中的driver
项。第二个参数是一个匿名函数(闭包),该匿名函数有一个$app
参数是Illuminate\Foundation\Application
的实例也是一个IoC容器,该匿名函数要返回一个Illuminate\Cache\Repository
的实例。
To create our custom cache driver, we first need to implement the Illuminate\Cache\StoreInterface
contract. So, our MongoDB cache implementation would look something like this:
要创建我们自己的缓存驱动,首先要实现Illuminate\Cache\StoreInterface
接口。所以我们用MongoDB来实现的缓存驱动就可能看上去是这样:
class MongoStore implements Illuminate\Cache\StoreInterface {
public function get($key) {}
public function put($key, $value, $minutes) {}
public function increment($key, $value = 1) {}
public function decrement($key, $value = 1) {}
public function forever($key, $value) {}
public function forget($key) {}
public function flush() {}
}
We just need to implement each of these methods using a MongoDB connection. Once our implementation is complete, we can finish our custom driver registeration:
我们只需使用MongoDB链接来实现上面的每一个方法即可。一旦实现完毕,就可以照下面这样完成该驱动的注册:
use Illuminate\Cache\Repository;
Cache::extend('mongo', function($app)
{
return new Repository(new MongoStore);
}
As you can see in the example above, you may use the base Illuminate\Cache\Repository
when creating custom cache drivers. These is typically no need to create your own repository class.
你可以像上面的例子那样来创建Illuminate\Cache\Repository
的实例。也就是说通常你不需要创建你自己的仓库类(Repository)。
If you're wondering where to put your custom cache driver code, consider making it available on Packagist! Or, you could create an Extensions
namespace within your application's primary folder. For example, if the application is named Snappy
, you could place the cache extension in app/Snappy/Extensions/MongoStore.php
. However, keep in mind that Laravel doesn not have a rigid application structure and you are free to organize your application according to your preferences.
如果你不知道要把自定义的缓存驱动代码放到哪儿,可以考虑放到Packagist里!或者你也可以在你应用的主目录下创建一个Extensions
目录。比如,你的应用叫做Snappy
,你可以将缓存扩展代码放到app/Snappy/Extensions/MongoStore.php
。不过请记住Laravel没有对应用程序的结构做硬性规定,所以你可以按任意你喜欢的方式组织你的代码。
Where To Extend 在哪儿调用Extend方法?
If you're ever wondering where to put a piece of code, always consider a service provider. As we've discussed, using a service provider to organize framework extensions is a great way to organize your code.
如果你还发愁在哪儿放注册代码,先考虑放到服务提供者里吧。我们之前就讲过,使用服务提供者是一种非常棒的管理你应用代码的途径。
Extending Laravel with a custom session driver is just as easy as extending the cache system. Again, we will use the extend
method to register our custom code:
扩展Laravel的会话机制和上文的缓存机制一样简单。和刚才一样,我们使用extend
方法来注册自定义的代码:
Session::extend('mongo', function($app)
{
// Return implementation of SessionHandlerInterface
});
Note that our custom cache driver should implement the SessionHandlerInterface
. This interface is included in the PHP 5.4+ core. If you are using PHP 5.3, the interface will be defined for you by Laravel so you have forward-compatibility. This interface contains just a few simple methods we need to implement. A stubbed MongoDB implementation would look something like this:
注意我们自定义的会话驱动(译者注:原味是cache driver,应该是笔误。正确应为session driver)实现的是SessionHandlerInterface
接口。这个接口在PHP 5.4以上版本才有。但如果你用的是PHP 5.3也别担心,Laravel会自动帮你定义这个接口的。该接口要实现的方法不多也不难。我们用MongoDB来实现就像下面这样:
class MongoHandler implements SessionHandlerInterface {
public function open($savePath, $sessionName) {}
public function close() {}
public function read($sessionId) {}
public function write($sessionId, $data) {}
public function destroy($sessionId) {}
public function gc($lifetime) {}
}
Since these methods are not as readily understandable as the cache StoreInterface
, let's quickly cover what each of the methods do:
这些方法不像刚才的StoreInterface
接口定义的那么容易理解。我们来挨个简单讲讲这些方法都是干啥的:
The open
method would typically be used in file based session store system. Since Laravel ships with a native
session driver that uses PHP's native file storage for sessions, you will almost never need to put anything in this method. You can leave it as an empty stub. It is simply a fact of poor interface design (which we'll discuss later) that PHP requires us to implement this method.
open
方法一般在基于文件的会话系统中才会用到。Laravel已经自带了一个native
的会话驱动,使用的就是PHP自带的基于文件的会话系统,你可能永远也不需要在这个方法里写东西。所以留空就好。另外这也是一个接口设计的反面教材(稍后我们会继续讨论这一点)。
The close
method, like the open
method, can also usually be disregarded. For most drivers, it is not needed.
close
方法和open
方法通常都不是必需的。对大部分驱动来说都不必要实现。
The read
method should return the string version of the session data associated with the given $sessionId
. There is no need to do any serialization or other encoding when retrieving or storing session data in your driver, as Laravel will perform the serialization for you.
read
方法应该根据$sessionId
参数来返回对应的会话数据的字符串形式。在你的会话驱动里,不论读写都不需要做任何数据序列化工作。因为Laravel会负责数据序列化的。
The write
method should write the given $data
string associated with the $sessionId
to some persistent storage system, such as MongoDB, Dynamo, etc.
write
方法应该将$sessionId
对应的$data
字符串放置在一个持久化存储系统中。比如MongoDB,Dynamo等等。
The destroy
method should remove the data associated with the $sessionId
from persistent storage.
destroy
方法应该将$sessionId
对应的数据从持久化存储系统中删除。
The gc
method should destroy all session data that is older than the given $lifetime
, which is a UNIX timestamp. For self-expiring systems like Memcached and Redis, this method may be left empty.
gc
方法应该将所有时间超过参数$lifetime
的数据全都删除,该参数是一个UNIX时间戳。如果你使用的是类似Memcached或Redis这种有自主到期功能的存储系统,那该方法可以留空。
Once the SessionHandlerInterface
has been implemented, we are ready to register it with the Session manager:
一旦SessionHandlerInterface
实现完毕,我们就可以将其注册进会话管理器:
Session::extend('mongo', function($app)
{
return new MongoHandler;
});
Once the session driver has been registered, we may use the mongo
driver in our app/config/session.php
configuration file.
注册完毕后,我们就可以在app/config/session.php
配置文件里使用mongo
驱动了。
Share Your Knowledge 分享你的知识
Remember, if you write a custom session handler, share it on Packagist!
你要是写了个自定义的会话处理器,别忘了在Packagist上分享啊!