当前位置: 首页 > 后端技术 > PHP

Laravel深度学习7-框架扩展

时间:2023-03-29 14:26:28 PHP

声明:本文非博主原创,而是来自《Laravel 4 From Apprentice to Artisan》阅读的翻译和理解,当然不是原文翻译,能保证90%原创,另外,由于是理解翻译,难免有错误,欢迎指正。欢迎转载,转载请注明出处,谢谢!框架扩展介绍Laravel为我们提供了很多自定义系统组件的扩展点,你甚至可以完全替换它们。比如hash结构是由HasherInterface接口规定的,你可以根据自己的应用实现自己的需求。您还可以扩展自己的Request对象并添加自己的“帮助器”方法。甚至我们完全添加了我们自己的身份验证、缓存和SESSION驱动程序。扩展Laravel组件通常有两种方式:将自己的接口实现绑定到IoC容器;使用“工厂模式”实现的Manager类注册您自己的扩展。本章探讨了扩展框架的各种方法,以及必要的测试代码。扩展方式请记住Laravel组件可以扩展的两种方式:IoC容器绑定和向Manager类注册。类库管理类以工厂模式实现,负责cache、session等驱动的实例化。类库管理类和工厂方法Laravel有许多管理器类库来管理那些基于驱动程序的组件的创建。它包括缓存、会话、身份验证和队列组件。管理类的职责是根据应用程序配置创建特定的驱动程序实例。例如,CacheManager可以创建APC、Memcached、Native和其他缓存驱动系统的实现。所有这些管理器都有一个扩展方法,可以很容易地向它们注入新的驱动程序功能。对于上面的所有管理器,我们使用示例来演示如何注入我们的自定义服务驱动程序。要学习我们自己的Manager,请花一些时间熟悉一下Laravel提供的Manager类库,比如CacheManager和SessionManager。通读代码会让你有更深刻的理解。所有管理器类都继承自IlluminateSupportManager基类,它为每个特定的管理器提供了许多常用的方法。CacheCache我们通过将自定义驱动程序解析器绑定到CacheManager类中的extend方法来扩展Laravel的缓存机制。例如注册一个“mongo”驱动到缓存驱动,代码如下:Cache::extend('mongo',function($app){//ReturnIlluminateCacheRepositoryinstance...});第一个传递给方法method的参数是驱动程序名称。通常匹配app/config/app.php配置文件中的driver选项。第二个参数是一个返回IlluminateCacheRepository实例的闭包。闭包需要传入继承自IlluminateFoundationApplication和IoC容器的实例化对象$app。对于我们自定义的缓存驱动,需要实现IlluminateCacheStoreInterface接口的约定。因此,我们的MongoDB缓存实现代码如下:1){}publicfunctiondecrement($key,$value=1){}publicfunctionforever($key,$value){}publicfunctionforget($key){}publicfunctionflush(){}}我们只需要使用MongoDB连接实现上面类中的各个方法。当上面的实现完成后,我们就可以完成我们自定义驱动的注册了:使用IlluminateCacheRepository直接创建我们自定义的缓存驱动,无需创建我们自己的(Repository)仓库类。如果您不知道将代码放在哪里,请考虑将它放在Packagist中!或者在应用主目录下的Extensions命名空间中创建一个目录用于存放。例如,如果您的应用程序名为Snappy,则可以将此扩展放在app/Snappy/Extensions/MongoStore.php中。Laravel创建的应用程序对各种结构没有硬性要求,只需按照自己的喜好组织即可。在哪里引入扩展如果你还在考虑在哪里引入扩展,不妨继续使用服务提供者。我们已经讨论过这是组织代码的好工具,请明智地使用它。Session扩展Session机制其实和扩展缓存机制一样简单。同样,使用extend方法注册我们自己的驱动程序:Session::extend('mongo',function($app){//ReturnimplementationofSessionHandlerInterface});请注意,我们的自定义驱动程序需要实现SessionHandlerInterface接口。该接口包含在PHP5.4+核心中。如果你使用的是PHP5.3,Laravel也是向前兼容的,Laravel已经为你定义了这个接口。该接口包含一些我们需要实现的方法。一个基于MongoDB的驱动代码如下:sessionId,$data){}publicfunctiondestroy($sessionId){}publicfunctiongc($lifetime){}}这些方法不像StoreInterface接口那么容易理解,让我们快速过一遍这些方法:open方法一般是根据所使用的文件系统来实现的。由于Laravel基于PHP自身的本地存储实现了原生的会话驱动方式,所以你基本上不需要在该方法中添加任何内容。您可以将其留空。PHP的这种界面设计,显然是一种糟糕的设计方式(后面再讨论)。close方法与open方法相同,通常被忽略。大多数司机不需要它。read方法返回一个字符串,该字符串将会话数据与$sessionId变量相关联。这里不需要序列化或者其他类型的转义,Laravel已经帮你处理好了。write方法根据$sessionId关联的session数据,将$data数据写入持久化存储系统,如MongoDB、Dynamo等。gc方法会根据$lifetime指定的UNIX时间戳销毁所有之前的会话数据。对于可以自动删除过期数据的系统,比如Memcached或者Redis,这个方法可以留空。实现SessionHandlerInterface后,我们可以将其注册到Session管理器:Session::extend('mongo',function($app){returnnewMongoHandler;});session驱动注册后,在配置文件app/config/session.php中指定mongo配置,使用我们自定义的session驱动。分享你的结果请记住,如果你实现了自己的会话驱动程序,你可以与Packagist上的每个人分享它!认证类似于缓存和会话扩展,我们继续从方法method开始:Session::extend('mongo',function($app){returnnewMongoHandler;});接口UserProviderInterface的实现是从MySQL、Riak等各种持久化存储系统获取数据,返回接口UserInterface实现的对象。这两个接口让Laravel可以专注于认证本身,而不必关心用户数据的存储实现,以及用户对象代表什么样的类。我们先来看看UserProviderInterface接口:interfaceUserProviderInterface{publicfunctionretrieveById($identifier);公共功能retrieveByCredentials(数组$credentials);公共函数validateCredentials(UserInterface$user,array$credentials);retrieveById方法通常接收的参数是一个唯一标识,比如MySQL数据库中的主键自增索引ID。该方法会获取$identifier对应的数据,返回接口UserInterface实现类的实例化对象。当用户尝试登录系统时,retrieveByCredentials方法接收一个身份验证数组作为参数,它也是传递给Auth::attempt的参数。此方法将“查询”给定的用户身份验证数据,通常,它会运行“查询”条件语句以将数据与$credentials['username']进行匹配。请不要使用此方法进行任何密码验证或验证。validateCredentials方法将通过比较$user和$credentials来验证用户。例如,该方法将比较通过$user->getAuthPassword();获得的字符串;结果由$credentials['password']通过Hash::make加密。上面我们探索了UserProviderInterface中的各种方法,再来看看UserInterface接口。请记住,上述提供程序中的retrieveById和retrieveByCredentials方法返回此接口实现类的实例化对象:interfaceUserInterface{publicfunctiongetAuthIdentifier();publicfunctiongetAuthPassword();}界面非常简单。getAuthIdentifier返回用户的“主键索引”。在MySQL后台存储系统中,指用户表的主键自增索引。getAuthPassword返回用户密码的哈希值。该接口的实现使得认证系统和User类完全分离,可以在各种类型的实现下正常工作,不管我们是使用ORM还是其他存储层实现。在app/models下,Laravel已经实现了这个接口的User类,你可以参考这个类。在实现接口UserProviderInterface之后,我们准备将我们的扩展注册到Authfacade中:Auth::extend('riak',function($app){returnnewRiakUserProvider($app['riak.connection']);});方法注册后,我们可以在app/config/auth.php中切换新的认证驱动。基于IoC容器的扩展Laravel框架中包含的几乎所有服务提供者都作为对象绑定到IoC容器。配置文件app/config/app.php中有详细的列表。如果有时间,最好把源码过一遍。这样就可以了解框架加载了哪些服务,也就是容器中绑定的各种服务。例如,PaginationServiceProvider将分页器绑定到容器,它对应于IlluminatePaginationEnvironment的一个实例。您可以轻松地通过扩展覆盖这些类并将它们重新绑定到容器中。作为另一个例子,让我们扩展基本的环境类:namespaceSnappyExtensionsPagination;classEnvironmentextendsIlluminatePaginationEnvironment{//}扩展完成后,新建一个SnappyPaginationProvider服务提供者,并在boot方法中替换原来的paginator:classSnappyPaginationProviderextendsPaginationServiceProvider{publicfunctionboot(){App::bind('paginator',function(){returnnewSnappyExtensionsPaginationEnvironment;}parent::boot();}}注意这个类继承的PaginationServiceProvider不是默认的ServiceProvider,扩展完成后记得在app/中替换成自己的扩展名config/app.php.这是扩展已经绑定在容器中的核心类库的方式,其实所有的核心类库都可以用这种方式重写,深入阅读源码可以帮助你知道Laravel是如何将各个部分组织在一起的。请求的扩展是因为在每个请求的生命周期中很早就实例化了请求。mos之一t的基本部分,所以Request的扩展会略有不同。首先,像往常一样实现一个子类:namespaceQuickBillExtensions;classRequestextendsIlluminateHttpRequest{//此处自定义,有用的方法...}然后,打开bootstrap/start.php,这是请求到达应用程序时包含的最早文件。注意,这里执行的第一个动作是创建Laravel实例化对象$app:$app=newIlluminateFoundationApplication;创建对象时,还会创建一个IlluminateHttpRequest实例,并使用请求键将其绑定到IoC容器。在这里,我们应该另辟蹊径,实现一个类作为“默认”请求类型吧?幸运的是,requestClass方法可以帮助我们实现它!所以我们需要在bootstrap/start.php文件的开头添加这一行:useIlluminateFoundationApplication;Application::requestClass('QuickBillExtensionsRequest');添加自定义请求类后,Laravel可以在任何地方使用我们的自定义Request实例,这使得我们定义请求类的实现实例可用,即使在单元测试中也是如此。