Laravel Composer Package 開發簡明教程

Ryan發表於2016-01-22

本文原連結來自我的部落格,地址: Laravel Composer Package 開發實戰 toastr-for-laravel5

在Laravel的文件中有Package Development,對於入門開發人員來說還是比較抽象,因為開發一個包需要了解 Service Providers,Service ProvidersFacade 已經夠抽象的了對剛接觸Laravel的開發人員來說,所以我來寫一個簡單的Laravel 包開發的例項教程吧。

toastr.js是一個很方便的通知效果,最近剛釋出了laravel 5.2,所以就來開發一個toastr for laravel 5的包吧,主要用toastr結合laravel的flash session來實現頁面的一次性訊息提醒,其實這個在我們日常開發中頁面操作提醒還是很常用到的業務。

一般的laravel 包開發過程是這樣的,開發好以後打包push到gitlab,然後在packagist上提交,下面我們就來一步一步實現這個過程。

  • 在新建的laravel專案中建立如下目錄 packages/yuansir/toastr/src ,packages 目錄和 app 目錄同級。我們開發包的程式碼都放在這個src目錄中,yuansir和toastr完全自定義。

  • 修改專案的composer.json,設定PSR-4名稱空間:
    "autoload": {
        "classmap": [
            "database"
        ],
        "psr-4": {
            "App\\": "app/",
            "Yuansir\\Toastr\\": "packages/yuansir/toastr/src/"
        }
    },

別忘了執行autoload

$ cd pacages/yuansir/toastr/src
  • 為我們的包初始化一個composer.json檔案,熟悉composer的應該都知道這玩意是幹嘛的了
$ cd pacages/yuansir/toastr/src

按照提示填寫相關資訊,有些資訊可以不用填寫,後面自己在composer.json中新增就可以了,生成的示例如下:

{
    "name": "ryan/toastr-for-laravel",
    "description": "toastr.js for laravel5",
    "authors": [
        {
            "name": "Ryan",
            "email": "yuansir@live.cn"
        }
    ],
    "require": {}
}
  • 開始開發,新建Service Provider
php artisan make:provider ToastrServiceProvider

將生成的app/Providers/ToastrServiceProvider.php檔案移動到我們的packages/yuansir/toastr/src 目錄下面,並註冊ToastrServiceProviderconfig/app.phpproviders 中。

'providers' => [

        /*
         * Laravel Framework Service Providers...
         */
         ......

        /*
         * Application Service Providers...
         */
         ......
        Yuansir\Toastr\ToastrServiceProvider::class,
    ],
  • 新建packages/yuansir/toastr/src/config/toastr.php 來儲存toastr.js的options,options配置還蠻多的,具體可以看它的demo。
<?php
 return [
     'options' => []
];

關於這個配置在我們包中如何呼叫的,我們過會來說.

  • 新建Toastr類,來實現toastr 的info,success,error,warning的相關實現,程式碼還是很簡單的,packages/yuansir/toastr/src/Toastr.php:
<?php namespace Yuansir\Toastr;

use Illuminate\Session\SessionManager;
use Illuminate\Config\Repository;

class Toastr
{
    /**
     * @var SessionManager
     */
    protected $session;

    /**
     * @var Repository
     */
    protected $config;

    /**
     * @var array
     */
    protected $notifications = [];

    /**
     * Toastr constructor.
     * @param SessionManager $session
     * @param Repository $config
     */
    public function __construct(SessionManager $session, Repository $config)
    {
        $this->session = $session;
        $this->config = $config;
    }

    public function render()
    {
        $notifications = $this->session->get('toastr:notifications');

        if(!$notifications) {
            return '';
        }

        foreach ($notifications as $notification) {
            $config = $this->config->get('toastr.options');
            $javascript = '';
            $options = [];
            if($config) {
                $options = array_merge($config, $notification['options']);
            }

            if($options) {
                $javascript = 'toastr.options = ' . json_encode($options) . ';';
            }

            $message = str_replace("'", "\\'", $notification['message']);
            $title = $notification['title'] ? str_replace("'", "\\'", $notification['title']) : null;
            $javascript .= " toastr.{$notification['type']}('$message','$title');";
        }

        return view('Toastr::toastr', compact('javascript'));
    }

    /**
     * Add notification
     * @param $type
     * @param $message
     * @param null $title
     * @param array $options
     * @return bool
     */
    public function add($type, $message, $title = null, $options = [])
    {
        $types = ['info', 'warning', 'success', 'error'];
        if(!in_array($type, $types)) {
            return false;
        }

        $this->notifications[] = [
            'type' => $type,
            'title' => $title,
            'message' => $message,
            'options' => $options
        ];
        $this->session->flash('toastr:notifications', $this->notifications);
    }

    /**
     * Add info notification
     * @param $message
     * @param null $title
     * @param array $options
     */
    public function info($message, $title = null, $options = [])
    {
        $this->add('info', $message, $title, $options);
    }

    /**
     * Add warning notification
     * @param $message
     * @param null $title
     * @param array $options
     */
    public function warning($message, $title = null, $options = [])
    {
        $this->add('warning', $message, $title, $options);
    }

    /**
     * Add success notification
     * @param $message
     * @param null $title
     * @param array $options
     */
    public function success($message, $title = null, $options = [])
    {
        $this->add('success', $message, $title, $options);
    }

    /**
     * Add error notification
     * @param $message
     * @param null $title
     * @param array $options
     */
    public function error($message, $title = null, $options = [])
    {
        $this->add('error', $message, $title, $options);
    }

    /**
     * Clear notifications
     */
    public function clear()
    {
        $this->notifications = [];
    }
}
  • 我們看到view(‘Toastr::toastr’, compact(‘javascript’));,那麼就是需要一個檢視檔案了,關於Toastr::toast是什麼鬼我們過會來說,新建 packages/yuansir/toastr/src/views/toastr.blade.php 檢視檔案:
<link href="http://cdn.bootcss.com/toastr.js/latest/css/toastr.min.css" rel="stylesheet">
<script src="http://cdn.bootcss.com/toastr.js/latest/js/toastr.min.js"></script>
<script type="text/javascript">{!! $javascript !!}</script>
  • 建立Facade,新建packages/yuansir/toastr/src/Facades/Toastr.php 就是引入了tastr外掛,輸出我們render方法中的$javascript
<?php namespace Yuansir\Toastr\Facades;

use Illuminate\Support\Facades\Facade;

class Toastr extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'toastr';
    }
}
  • 修改ToastrServiceProvider:
<?php namespace Yuansir\Toastr;

use Illuminate\Support\ServiceProvider;

class ToastrServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        $this->loadViewsFrom(__DIR__ . '/views', 'Toastr');

        $this->publishes([
            __DIR__.'/views' => base_path('resources/views/vendor/toastr'),
            __DIR__.'/config/toastr.php' => config_path('toastr.php'),
        ]);
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app['toastr'] = $this->app->share(function ($app) {
            return new Toastr($app['session'], $app['config']);
        });
    }

    /**
     * Get the services provided by the provider.
     *
     * @return array
     */
    public function provides()
    {
        return ['toastr'];
    }
}

$this->loadViewsFrom( DIR . ‘/views’, ‘Toastr’); 就是表示Toastr名稱空間的檢視檔案衝當前目錄的views目錄中渲染,所以我們上面用 return view(‘Toastr::toastr’, compact(‘javascript’));

$this->publishes 在執行php artisan vendor:publish 時會將對應的目錄和檔案複製到對應的位置

10.測試下是否可行,修改 config/app.php 新增如下:

   /*
    |--------------------------------------------------------------------------
    | Class Aliases
    |--------------------------------------------------------------------------
    |
    | This array of class aliases will be registered when this application
    | is started. However, feel free to register as many as you wish as
    | the aliases are "lazy" loaded so they don't hinder performance.
    |
    */

    'aliases' => [
        ......

        'Toastr' => Yuansir\Toastr\Facades\Toastr::class,

    ],

寫個控制器放進去試試:

<?php

namespace App\Http\Controllers;

use App\Http\Requests;
use Illuminate\Http\Request;
use Toastr;

class HomeController extends Controller
{
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        //略
    }

    /**
     * Show the application dashboard.
     *
     * @return \Illuminate\Http\Response
     */
    public function index(Request $request)
    {
        Toastr::error('你好啊','標題');
        return view('home');
    }
}

到此結束,大功告成,這樣一個Laravel 的 composer 包就開發完成了。 反正我測試是OK了,就不截圖了!!

  • 修改名稱空間到包的composer.json,因為別人安裝這個包的時候不可能也去改專案composer.json的PSR-4的autoload,所以我們把PSR-4的名稱空間加到這個包的composer.json中去,修改packages/yuansir/toastr/src/composer.json 如下:
{
    "name": "ryan/toastr-for-laravel",
    "description": "toastr.js for laravel5",
    "authors": [
        {
            "name": "Ryan",
            "email": "yuansir@live.cn"
        }
    ],
    "require": {},
    "autoload": {
        "psr-4": {
            "Yuansir\\Toastr\\": "src/"
        }
    }
}

12.建立Github專案

將程式碼push到專案中去:

$ cd packages/yuansir/toastr/

$ git init

$ git add .

$ git commit -m "add package source files."

$ git remote add origin git@github.com:yuansir/toastr-for-laravel5.git

$ git push -u origin master

$ git tag -a 1.0.0 -m "version 1.0.0"

$ git push --tags
  • 提交到Packagist,開啟到 packagist.org,登陸後點選右邊上角的 submit,並填入git的專案地址git@github.com:yuansir/toastr-for-laravel5.git 點選 check 就OK了

到此結束,大功告成,這樣一個Laravel 的 composer 包就開發完成了。

這個教程的原始碼和這個包的安裝使用方法詳見github https://github.com/yuansir/toastr-for-laravel5

如有問題歡迎指正!

轉載請註明: 轉載自Ryan是菜鳥 | LNMP技術棧筆記

如果覺得本篇文章對您十分有益,何不 打賞一下

謝謝打賞

相關文章