包开发
介绍
包是向 Laravel 添加功能的主要方式。包可以是任何东西,从处理日期的优秀工具 Carbon,到像 Behat 这样的完整 BDD 测试框架。
当然,包有不同的类型。一些包是独立的,意味着它们可以与任何框架一起使用,而不仅仅是 Laravel。Carbon 和 Behat 都是独立包的例子。任何这些包都可以通过在 composer.json
文件中请求它们来与 Laravel 一起使用。
另一方面,其他包则专门用于 Laravel。在 Laravel 的早期版本中,这些类型的包被称为“捆绑包”。这些包可能具有路由、控制器、视图、配置和迁移,专门用于增强 Laravel 应用程序。由于开发独立包不需要特殊过程,因此本指南主要涵盖 Laravel 特定包的开发。
所有 Laravel 包都通过 Packagist 和 Composer 分发,因此了解这些出色的 PHP 包分发工具是必不可少的。
创建一个包
创建一个新的 Laravel 包的最简单方法是使用 workbench
Artisan 命令。首先,您需要在 app/config/workbench.php
文件中设置一些选项。在该文件中,您会找到 name
和 email
选项。这些值将用于为您的新包生成 composer.json
文件。一旦您提供了这些值,您就可以开始构建工作台包了!
发出工作台 Artisan 命令
php artisan workbench vendor/package --resources
供应商名称是区分您包与其他作者的同名包的一种方式。例如,如果我(Taylor Otwell)要创建一个名为“Zapper”的新包,供应商名称可以是 Taylor
,而包名称将是 Zapper
。默认情况下,工作台将创建与框架无关的包;然而,resources
命令告诉工作台生成具有 Laravel 特定目录的包,例如 migrations
、views
、config
等。
一旦执行了 workbench
命令,您的包将在 Laravel 安装的 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 知道如何正确加载视图、配置和其他资源。通常,您无需更改此行代码,因为它将使用工作台约定设置包。
默认情况下,在注册包后,其资源将使用 vendor/package
的“包”部分访问。然而,您可以将第二个参数传递给 package
方法以覆盖此行为。例如:
// 将自定义命名空间传递给包方法
$this->package('vendor/package', 'custom-namespace');
// 包资源现在通过自定义命名空间访问
$view = View::make('custom-namespace::foo');
服务提供者类没有“默认位置”。您可以将它们放在您喜欢的任何地方,可能在 app
目录中的 Providers
命名空间中组织。文件可以放在任何地方,只要 Composer 的 自动加载设施 知道如何加载类。
如果您更改了包资源的位置,例如配置文件或视图,您应该将第三个参数传递给 package
方法,指定资源的位置:
$this->package('vendor/package', null, '/path/to/resources');
延迟提供者
如果您正在编写一个不注册任何资源(如配置或视图)的服务提供者,您可以选择使您的提供者“延迟”。延迟服务提供者仅在应用程序 IoC 容器实际需要它提供的服务时加载和注册。如果在给定的请求周期中没有需要提供者的服务,则该提供者不会被加载。
要延迟执行您的服务提供者,请将提供者的 defer
属性设置为 true
:
protected $defer = true;
接下来,您应该从基础的 Illuminate\Support\ServiceProvider
类重写 provides
方法,并返回一个包含您提供者添加到 IoC 容器的所有绑定的数组。例如,如果您的提供者在 IoC 容器中注册了 package.service
和 package.another-service
,则您的 provides
方法应如下所示:
public function provides()
{
return array('package.service', 'package.another-service');
}
包约定
在使用包的资源时,例如配置项或视图,通常将使用双冒号语法:
从包加载视图
return View::make('package::view.name');
检索包配置项
return Config::get('package::group.option');
如果您的包包含迁移,请考虑在迁移名称前加上您的包名称,以避免与其他包的潜在类名冲突。
开发工作流
在开发包时,能够在应用程序的上下文中进行开发是很有用的,这样您可以轻松查看和实验您的模板等。因此,要开始,请安装一个新的 Laravel 框架副本,然后使用 workbench
命令创建您的包结构。
在 workbench
命令创建了您的包后,您可以从 workbench/[vendor]/[package]
目录中 git init
并直接从工作台 git push
您的包!这将允许您在应用程序上下文中方便地开发包,而不必被不断的 composer update
命令所困扰。
由于您的包位于 workbench
目录中,您可能想知道 Composer 如何知道自动加载您的包的文件。当 workbench
目录存在时,Laravel 将智能地扫描它以查找包,在应用程序启动时加载它们的 Composer 自动加载文件!
如果您需要重新生成包的自动加载文件,可以使用 php artisan dump-autoload
命令。此命令将为您的根项目以及您创建的任何工作台重新生成自动加载文件。
运行 Artisan 自动加载命令
php artisan dump-autoload
包路由
在 Laravel 的早期版本中,使用 handles
子句来指定包可以响应的 URI。然而,在 Laravel 4 中,包可以响应任何 URI。要为您的包加载路由文件,只需在服务提供者的 boot
方法中 include
它。
从服务提供者包含路由文件
public function boot()
{
$this->package('vendor/package');
include __DIR__.'/../../routes.php';
}
如果您的包使用控制器,您需要确保它们在 composer.json
文件的自动加载部分中正确配置。
包配置
访问包配置文件
一些包可能需要配置文件。这些文件应以与典型应用程序配置文件相同的方式定义。当使用默认的 $this->package
方法在服务提供者中注册资源时,可以使用通常的“双冒号”语法访问:
Config::get('package::file.option');
访问单文件包配置
但是,如果您的包包含单个配置文件,您可以简单地将文件命名为 config.php
。这样做时,您可以直接访问选项,而无需指定文件名:
Config::get('package::option');
手动注册资源命名空间
有时,您可能希望在典型的 $this->package
方法之外注册包资源,例如视图。通常,这仅在资源不在常规位置时进行。要手动注册资源,您可以使用 View
、Lang
和 Config
类的 addNamespace
方法:
View::addNamespace('package', __DIR__.'/path/to/views');
一旦命名空间被注册,您可以使用命名空间名称和“双冒号”语法访问资源:
return View::make('package::view.name');
addNamespace
的方法签名在 View
、Lang
和 Config
类中是相同的。
级联配置文件
当其他开发人员安装您的包时,他们可能希望覆盖某些配置选项。然而,如果他们在您的包源代码中更改值,则在下次 Composer 更新包时将被覆盖。相反,应该使用 config:publish
Artisan 命令:
php artisan config:publish vendor/package
当执行此命令时,您应用程序的配置文件将被复制到 app/config/packages/vendor/package
,开发人员可以安全地修改它们!
开发人员还可以通过将环境特定的配置文件放置在 app/config/packages/vendor/package/environment
中,为您的包创建环境特定的配置文件。
包视图
如果您在应用程序中使用包,您可能偶尔希望自定义包的视图。您可以使用 view:publish
Artisan 命令轻松导出包视图到您自己的 app/views
目录:
php artisan view:publish vendor/package
此命令将把包的视图移动到 app/views/packages
目录。如果该目录尚不存在,则在运行命令时将创建它。一旦视图被发布,您可以根据自己的喜好进行调整!导出的视图将自动优先于包自己的视图文件。
包迁移
为工作台包创建迁移
您可以轻松为任何包创建和运行迁移。要为工作台中的包创建迁移,请使用 --bench
选项:
php artisan migrate:make create_users_table --bench="vendor/package"
为工作台包运行迁移
php artisan migrate --bench="vendor/package"
为已安装包运行迁移
要为通过 Composer 安装到 vendor
目录的完成包运行迁移,您可以使用 --package
指令:
php artisan migrate --package="vendor/package"
包资产
将包资产移动到公共目录
一些包可能有资产,例如 JavaScript、CSS 和图像。然而,我们无法链接到 vendor
或 workbench
目录中的资产,因此我们需要一种方法将这些资产移动到应用程序的 public
目录。asset:publish
命令将为您处理此事:
php artisan asset:publish
php artisan asset:publish vendor/package
如果包仍在 workbench
中,请使用 --bench
指令:
php artisan asset:publish --bench="vendor/package"
此命令将根据供应商和包名称将资产移动到 public/packages
目录。因此,名为 userscape/kudos
的包将其资产移动到 public/packages/userscape/kudos
。使用这种资产发布约定,您可以安全地在包的视图中编写资产路径。
发布包
当您的包准备发布时,您应该将包提交到 Packagist 存储库。如果包特定于 Laravel,请考虑在包的 composer.json
文件中添加 laravel
标签。
此外,标记您的版本是礼貌和有帮助的,这样开发人员在请求包时可以依赖稳定版本。如果稳定版本尚未准备好,请考虑使用 branch-alias
Composer 指令。
一旦您的包发布,您可以继续在 workbench
创建的应用程序上下文中开发它。这是继续方便地开发包的好方法,即使在发布之后。
一些组织选择为自己的开发人员托管自己的私有包存储库。如果您对此感兴趣,请查看 Composer 团队提供的 Satis 项目的文档。