扩展包开发
简介
扩展包是扩增 Laravel 的主要方式。扩展包可以是完成任何功能的数据,比方说处理时间的 Carbon 或是 BDD 测试框架如 Behat。
当然,目前有各式各样的扩展包。有些扩展包是独立运作 (stand-alone) 的,意思是指他们并不相依任何框架,包括 Laravel 。刚提到的 Carbon 及 Behat 就是这种扩展包。要使用这种扩展包只需要在 composer.json
文件里引入它们即可。
另一方面,有些扩展包特别指定要与 Laravel 整合。这种型式的扩展包在上一个版本的 Laravel 里称做 Bundle。这种扩展包可能有路由、控制器、视图、设定以及迁移,目标是增强 Laravel 本身的功能。由于没有特别需求要开发独立运作的扩展包,因此在这份指南里将主要以开发 Laravel 专属的扩展包为目标进行说明。
所有的 Laravel 扩展包都通过 Packagist 及 Composer 进行发布,因此学习如何使用这些美妙的 PHP 发布工具是一个必经的过程。
建立一个扩展包
建立一个新扩展包最简单的方式就是通过 workbench
这个 artisan 命令。首先,您需要先在 app/config/workbench.php
里设定一些选项。在这个文件里,您会找到 name
及 email
这两个选项。这些选项里的值将会被用来产生扩展包里的 composer.json
档。当您设定好这些前置工作后,就已经可以开始打造您的 workbench 扩展包了!
启始一个 workbench artisan 命令
php artisan workbench vendor/package --resources
发行商 (vendor) 名称是为了识别不同作者发行相同名称的扩展包而设计的。 比方说,我 (Taylor Otwell) 建立了一个新的扩展包名称为 "Zapper" ,而发行商的名称就是 Taylor
。默认 workbench 命令会建立框架独立 (framework agnostic) 的扩展包结构。然后,resources
参数则会让 workbench 在产生扩展包结构时,额外针对 Laravel 产生特定的文件夹,包括 migrations
、views
、config
等。
当 workbench
命令被执行后,您的扩展包就可以在 workbench
文件夹内被获取。接着,您需要为您的扩展包注册服务提供者 (ServiceProvider)
。您可以通过在 app/config/app.php
的 providers
数组里新增您扩展包的服务提供者名称进行注册,这个动作将会让 Laravel 启动时载入您的扩展包。服务提供者使用 [Package]ServiceProvider
这种命名惯例来为软件命名,以上述的例子来说,我们将会新增一行 Taylor\Zapper\ZapperServiceProvider
到 providers
数组里。
当提供者被注册后,您就已经完成扩展包开发的前置工作了!不过,建议您在深入开发工作前,先熟悉一下以下章节要接口的扩展包数据结构及开发工作流程。
假如您的服务提供者无法被载入,记得在您的应用程序根目录底下执行 php artisan dump-autoload
命令。
扩展包结构
当使用 workbench
命令后,您的扩展包将依照以下惯例进行初始化,这是为了让您的扩展包能与 Laravel 协同工作:
基本的扩展包结构
/src
/Vendor
/Package
PackageServiceProvider.php
/config
/lang
/migrations
/views
/tests
/public
让我们继续探索下去。src/Vendor/Package
文件夹是存放这个扩展包所有的相关类代码,包括 ServiceProvider
。而 config
、lang
、migrations
、views
文件夹,就如同您预想的一样,存放关于您的扩展包的相关资源,一个扩展包可以包含任何种类的资源,就像「一般」的应用程序一样。
服务提供者
服务提供者就是一个扩展包的启始类。默认来说,他包含两个方法:boot
和 register
。通过这两个方法,您可以做任何您需要做的事,比方说:引入路由文件、注册 IoC 容器、注册事件或是任何其他您想要做的事。
register
这个方法则是当服务提供者被注册时马上被调用,而 boot
命令则是仅当一个请求被路由时才会被执行。所以,假如您的服务提供者相依于其他已经注册的服务提供者,或是您想要重写由其他服务提供者所做的绑定,则您应该使用 boot
方法。
当使用 workbench
新建一个扩展包时, boot
命令就已经包括以下动作:
$this->package('vendor/package');
这个方法让 Laravel 知道如何载入视图、设定及其他您的应用程序所需的资源。在大多数的情况下,跟随这个 workbench 的惯例即可,并不需要特别修改这一行。
在默认的情况下,当注册完扩展包后,其资源就可以通过 vendor/package
取得。然后,您可以通过 package 方法的第二个参数来重写其动作,比方说:
// 将 custom-namespace 传给 package 方法
$this->package('vendor/package', 'custom-namespace');
// 则扩展包资源可通过 custom-namespace 取得
$view = View::make('custom-namespace::foo');
服务提供者类并没有「默认」的存放位置,您可以把它放在任何您喜欢的地方,或许可以将它们统一整理在 Providers
命名空间后,放到您的 app
文件夹里。只要 Composer 知道如何载入它们的话,您就可以把这些文件放在任何地方。
假如您更改了您扩展包资源存放的位置,可能是配置文件或是视图,那您就应该在 package
方法调用时,传入第三个参数来指定您的资源位置:
$this->package('vendor/package', null, '/path/to/resources');
缓载提供者
假如您正在开发的服务提供者并没有注册任何形式的资源如配置文件或视图等,那您就可以考虑将您的服务提供者设定为「缓载」提供者。一个缓载提供者的特性就是只有需要它的功能时才载入,假如在当次的请求循环内不需要这个服务,则这个提供者就不会被载入。
要设定您的服务提供者采用缓载设定,只需要将 defer
属性设定为 true
即可:
protected $defer = true;
接下来您应该从 Illuminate\Support\ServiceProvider
基础类重写 provides 方法,并回传一个数组包含所有您需要绑定到 IoC 容器的服务。举例来说,假如您的提供者注册 package.service
和 package.another-service
给 IoC 容器,您的 provides
方法应该长得像这样:
public function provides()
{
return array('package.service', 'package.another-service');
}