编写composer包和发布全攻略
laravel composer 扩展包开发(超详细)
快速发布一个composer扩展包
我之所以想先带大家快速了解一个composer包的发布过程,是因为我打算把二次封装的组件作为composer包发布。我必须了解composer组件怎么发布,有哪些功能。
创建packages
在哪个目录创建packages,我们可以先来看一下vendor。
在上图中,vendor是和app是同一级别的,vendor下存放的是不同的组件。所以我们参照vendor,建立一个packages。我们再来看看包名怎么命名。
- 命名空间(Vendor Name)
通常使用你的公司名、组织名或个人用户名作为命名空间。这有助于区分不同来源的包,并且可以防止命名冲突。命名空间应全部使用小写字母,以保持一致性。 - 包名(Package Name)
包名应该能够清晰地描述包的功能或用途。使用连字符 - 分隔多个单词,而不是下划线 _ 或驼峰命名法。 - 完整的包标识符
vendor-name/package-name
比如
laravel/framework
spatie/laravel-permission
tightenco/ziggy
那我们给我们的包起个名字,linxi/exception-helper
,exception-helper其实就是为了更友好的获取异常信息
下面我们进入到这个目录,并初始化一个composer文件
$ site/packages/linxi/exception-helper
$ composer init
一路敲enter就行了,不用太纠结。因为这个后面是可以改的。
整个包目录就是长这个样子了。
provider
项目根目录下执行php artisan make:provider ExceptionHelperProvider
,生成一个provider文件,并把文件剪切到packages/linxi/exception-helper/src/
目录下。
那么这个provider有什么作用呢,我们具体来看一下
作用
- 注册服务:
服务提供者是注册应用程序服务的主要位置。使用$this->app->bind()
方法可以将服务绑定到服务容器中,使得该服务可以在整个应用中被解析。 - 引导服务:
除了注册服务外,服务提供者还可以用来引导服务。这可能包括加载配置文件、初始化类实例或设置全局状态。例如,很多服务提供者会在这里注册路由、事件监听器或视图组件。 - 发布配置和资源:
使用publishes方法,服务提供者可以为包或自定义模块发布配置文件、视图、迁移文件等资源,以便开发者可以根据需要进行调整。 - 注册命令:
服务提供者可以通过$commands属性来注册Artisan命令。这些命令可以在命令行界面中使用,用于执行各种任务,如数据库迁移、队列处理等。 - 绑定接口到实现:
在服务提供者中,你通常会定义接口与其实现之间的绑定,这样当接口被解析时,就可以得到正确的实现对象。 - 设置别名:
服务提供者可以设置类的别名(Facade),简化代码书写,使开发更加方便。比如Cache::get(‘key’)这样的写法背后其实是对Illuminate\Cache\CacheManager的一个优雅封装。 - 扩展核心组件:
服务提供者允许你扩展Laravel的核心组件,例如添加自定义的验证规则、日志记录通道等。 - 注册事件监听器、中间件、路由等:
服务提供者可以用来注册事件监听器、中间件以及路由,从而控制请求的生命周期和响应逻辑。 - 延迟加载服务:
如果某个服务不是每次请求都需要,那么可以将其标记为延迟加载(Deferred Provider)。这样,只有当服务真正被请求时才会加载它,有助于提高应用性能。
接下来我们来编辑一下provider类
<?php
namespace Linxi\ExceptionHelper;
use Illuminate\Support\ServiceProvider;
class ExceptionHelperProvider extends ServiceProvider
{
/**
* Register services.
*
* @return void
*/
public function register()
{
// 绑定异常处理服务到服务容器
$this->app->singleton('exception.helper', function ($app) {
return new ExceptionHelper();
});
}
public function boot()
{
// 如果需要引导任何服务,可以在这里进行。
// 例如:注册视图组件、事件监听器等。
// 视图目录指定
$this->loadViewsFrom(__DIR__ . '/views', 'Packagetest');
$this->publishes([
// 发布视图目录到resources 下
// __DIR__ . '/views' => base_path('resources/views/vendor/packagetest'),
// 发布配置文件到 laravel 的config 下
__DIR__ . '/config/exception-helper.php' => config_path('exception-helper.php'),
]);
// 发布视图(如果有)
// $this->loadViewsFrom(__DIR__.'/../resources/views', 'exception-helper');
// 注册事件监听器
// \Event::listen(\Illuminate\Auth\Events\Registered::class, \Linxi\ExceptionHelper\Listeners\LogSuccessfulRegistration::class);
// 注册中间件(如果需要)
$router = $this->app['router'];
// $router->aliasMiddleware('custom.middleware', \Linxi\ExceptionHelper\Http\Middleware\CustomMiddleware::class);
// 注册路由(如果需要)
// $this->loadRoutesFrom(__DIR__.'/../routes/web.php');
}
}
里面我只用了发布配置文件的功能,对应的包里面的配置文件是src/config目录的exception-helper.php文件,我们先来创建一下文件。
site/packages/linxi/exception-helper/src/config/exception-helper.php
<?php
return [
'is_dump'=>1,//是否打印异常信息
];
逻辑实现的类
site/packages/linxi/exception-helper/src/ExceptionHelper.php
<?php
namespace Linxi\ExceptionHelper;
use Illuminate\Config\Repository;
use Illuminate\Support\Facades\Log;
class ExceptionHelper
{
protected $config;
public function __construct(Repository $config)
{
$this->config = $config;
}
public function exceptionEcho($msg = '', $data = [], $level = 'INFO')
{
if (!empty($data) && $data instanceof \Exception) {
$data = [
'echoLog报错信息' => $data->getMessage(),
'echoLog报错文件' => $data->getFile(),
'echoLog报错行号' => $data->getLine(),
'文件堆栈' => $data->getTraceAsString(),
];
}
$result['msg'] = $msg;
if (!empty($data)) {
$result['data'] = $data;
}
//记录日志
Log::$level($msg, $result);
//如果是error 级别,则飞书报警
if ($level == 'error') {
//飞书报警
// 发飞书消息
}
if ($this->config->get('exception-helper.is_dump')) {//获取配置参数
echo PHP_EOL . json_encode($result, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL;
}
}
}
创建Facade
在包目录下的src下,创建Facades目录,在目录下创建ExceptionHelper.php
<?php
namespace Linxi\ExceptionHelper\Facades;
use Illuminate\Support\Facades\Facade;
class ExceptionHelper extends Facade
{
protected static function getFacadeAccessor(){
return 'exception-helper';
}
}
注册到config/app.php
'providers' => [ \Linxi\ExceptionHelper\ExceptionHelperProvider::class,
],
'aliases' => [
'ExceptionHelper'=>\Linxi\ExceptionHelper\Facades\ExceptionHelper::class,
]
那么我们这个包怎么让laravel项目识别呢?我们知道,composer是laravel的包管理工具,所以我们就编辑一下laravel目录下的composer.json文件,在autoload项下增加一个属性,对应的是命名空间和包目录。
"autoload": {
"psr-4": {
"App\\": "app/",
"Linxi\\ExceptionHelper\\": "packages/linxi/exception-helper/src/"
}
}
然后执行composer dump-autoload
重新索引一下包的信息就可以了。
发布引导文件
我们创建provider的时候,指定了一些资源文件和目录,我们使用vendor:publish
把文件发布出来
$ php artisan vendor:publish --provider="Linxi\ExceptionHelper\ExceptionHelperProvider"
Copied File [/packages/linxi/exception-helper/src/config/exception-helper.php] To [/config/exception-helper.php]
Publishing complete.
看执行结果,我们的配置文件发布到了项目根目录下的config目录下。
测试
接下来我们简单写一点代码测试一下功能
public function handle()
{
try {
throw new \Exception('测试异常');
}catch (\Exception $e){
ExceptionHelper::exceptionEcho('发短信功能异常',$e,'error');
}
}
查看打印结果
这样我们的功能就完成了。
包的发布
那么我们怎么把我们的包发布出去呢?我们来看一下
1.发布packages的包到github,我们切换到包的目录下
$ cd site/packages/linxi/exception-helper
把包提交到github。并那到github的地址
https://github.com/guofuzhang/exception-helper
2.登录https://packagist.org/
关联github的项目地址并发布
发布之后,我们就可以正常通过require来拉取组件了。
接下来我们把我们的项目恢复一下
- 移出packages目录
- 恢复composer.json包文件
- config/app.php文件恢复
- config目录的配置文件删除
包的安装
- composer安装
composer require linxi/exception-helper
- provider和facade注册到config/app.php
- 发布配置文件
php artisan vendor:publish --provider="Linxi\ExceptionHelper\ExceptionHelperProvider"
- 测试
制品库
我们也可以把我们的包放到制品库里面
配置
在制品库的引导里面设置自己的权限
制作
我们进入package目录下的pusar-client 项目
$ zip -r pulsar-client.zip . -x "./vendor/*"
#注意下面的版本号
$ curl -T pulsar-client.zip -u acurd-com@163.com "https://xxxx/pulsar-client?version=v1.0.1"
推送之后就可以在制品库看到推送的版本
拉取
在项目的根目录下创建auth.json,内容就是拉取配置凭证的内容,有这个auth文件才有权限拉取。注意,这个权限表示针对单个项目的,而是针对制品库的。
然后拉取composer包就行了
php8 /usr/local/bin/composer require dyxc/pulsar-client:v1.0.1 -vvv
参考
laravel composer 扩展包开发(超详细)