Laravel 包编写(三)-服务提供者实现

在这一篇我们将实现一个简单的关于文章分类的包(gru\tag),该包将会尽量涉及到包开发的各个方面

  1. 在一个Laravel项目的根目录下面创建一个名为packages, 然后在package目录下面创建一个gru文件夹, 最后在gru文件夹下面创建一个tag文件,创建完成以后,结构如下

    -Root
        --gru
            --tag
              --src
    

    之所以这样布局是因为相同作者的包,使用composer管理以后将统一放到一个目录下,而src将会作为我们代码放置的地方

  2. 在tag目录下,使用composer初始化包,初始化以后我们就可以得到一个composer.json文件,由于该项目没有依赖其他的包,所以这里添加依赖

        {
            "name": "gru/tag",
            "description": "this is demo about package write",
            "type": "library",
            "license": "MIT",
            "require": {}
        }
    

    如果不熟悉,composer可以参考composer中文网提供的文档

  3. 模拟自动加载,为了更好的在Laravel项目中进行包的开发与测试,我们需要在项目的根目录(注意:不是tag下面)下面添加命名psr-4的加载规则

        "psr-4": {
            "App\\": "app/",
            "Gru\\Tag\\": "packages/gru/tag/src"
        }
    

    添加完成以后需要执行composer dumpautoload来使配置生效,生效后,我们包的命名空间就会变成Gru\Tag

  4. 创建服务提供者GruTagServiceProvider

    php artisan make:provider GruTagServiceProvider
    

    创建完成以后,需要将该文件迁移到packages/gru/tag/src目录下,并修改其命名空间为Gru\Tag

  5. 将创建的服务注册到config/app.php文件的providers数组中

    Gru\Tag\GruTagServiceProvider::class,
    
  6. 创建数据迁移文件

    php artisan make:migration create_table_tags --create=tags
    

    然后将文件迁移到我们包的src目录下,

  7. 创建模型,并迁移到src目录下,注意变更模型的命名空间

    php artisan make:model Tag
    
  8. 创建资源控制器,并迁移到src目录下,注意变更模型的命名空间

    php artisan make:controller --resource TagController
    

    这里需要注意的是,处理变更命名空间,还需要引入基础控制器类

    use App\Http\Controllers\Controller;
    
  9. 添加路由文件src\routes.php

    <?php
    
    Route::resource("tags", "Gru\Tag\TagController");
    
  10. 添加路由文件到GruServiceProvider.php文件的boot方法中

    <?php
    public function boot()
    {
        $routeFile = __DIR__ . '/routes.php';
        $this->loadRoutesFrom($routeFile);
    }
    
  11. TagController类中的index方法中,添加如下代码,测试当前路由几控制器是否可用

    <?php
     public function index()
    {
        return response()->json(['state' => 'route, controller work']);
    }
    
  12. 通过路由访问you_domain/tags,如果看到

    {"state":"route, controller work"}
    

    则表明,路由和控制器已经正常工作

  13. src目录下创建配置文件tag.php,并添加一点内容

    <?php
    return [
        'tag' => 'this is tag config'
    ];
    
  14. GruServiceProvider的boot方法中加载配置

    <?php
    public function boot()
    {
        .....
    
        $configFile = __DIR__ . '/tag.php';
        $this->mergeConfigFrom($configFile, 'tag');
    }
    

    然后就可以在任何地方通过config(tag.xx)的形式进行访问配置文件

  15. 执行迁移文件, 在GruServiceProvider类的boot方法中,增加迁移文件的路径

    <?php
        //加载迁移文件
        $migratePath = __DIR__ . '/';
        $this->loadMigrationsFrom($migratePath);
    

    然后在项目的根目录下执行迁移

    php artisan migrate
    
  16. 视图的使用,在src目录下,增加增加一个名为create.blade.php的文件,在这里将用来创建tag

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>Tag create</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
    </head>
    <body>
        <form action="{{url('tags')}}" method="post">
            <input type="text" name="name">
            <input type="submit" value="提交">
        </form>
    </body>
    </html>
    
  17. GruServiceProvider类的boot方法中,添加视图加载路径

    <?php
        //加载视图文件
        $viewPath = __DIR__ . '/';
        $this->loadViewsFrom($viewPath, 'Gru\Tag');
    
  18. 然后在控制的create方法中,增加视图的返回

    <?php
    public function create()
    {
        return view('Gru\Tag::create');
    }
    

    在这里需要注意的是,这里的视图加载需要使用到loadViewsFrom中的命名空间来指定视图的地址

  19. 最后在控制器的store方法中,添加标签保存的逻辑处理,这里为了简化操作,去除了必要的校验处理

    <?php
    public function store(Request $request)
    {
        $name = $request->get("name");
        $tag = new Tag;
        $tag->name = $name;
        $tag->save();
    }
    

至此一个包的创建过程基本就完成了,由于这里我们没有提供特别的服务类, 因此没有在register中注册服务,如果有的话,注册的代码如下:

<?php
// 服务注册
$this->app->singleton(MyPackage::class, function () {
    return new MyPackage();
});

// 别名注册
$this->app->alias(MyPackage::class, 'my-package');

不足

  1. 一个完整的包,离不开测试,这里我们没有进行代码的测试,在实际的包开发中,应该补充包测试,以及使用文档

  2. 这里我们为了方便,没有对包的目录结构进行设计,实际上应该依据自己的需要,调整包各个模块的结构

参考资料