「12步」制作 Laravel 插件 (一)

1,453 阅读4分钟

在Laravel 开发过程中,用了很多诸如:laravel-admin,Guzzle,Intervention Image 等优秀的插件,看他们的 star 很多,得到很多人的关注,就想着自己能不能写个有价值的插件,共享给大家使用。

今天就让我们来说说如何创建一个简单的插件:「数字转中文大写金额」

具体只需要以下「12」个步骤:

1. 创建 Laravel 5.5 项目

// 下载最新 Laravel

composer global require "laravel/installer"

// 创建项目
Laravel new packagelearning

2. 创建插件文件夹

在 Laravel 项目 vendor 文件夹放的是各种第三方插件,我们随便看看,可以发现这些插件基本遵循下面的文件目录格式:

如,monolog 插件,目录结构为 [VENDOR or CREATOR] / [PACKAGE NAME],而且 src 文件夹基本用于保存插件源代码,还有一个 composer.json 用于配置插件基本信息和引入其它第三方插件等信息。

我们在 packagelearning 项目创建 packages 文件夹:

3. 创建 composer.json

我们可以利用「composer」命令来初始化 composer.json 文件:

输入插件的基本信息后:

4. PSR-4 autoload namespace mapping

在 composer.json 加入 autoload 配置:

5. 创建 Service Providers

正如 Laravel 官网所说:

Service providers are the connection points between your package and Laravel. A service provider is responsible for binding things into Laravel's service container and informing Laravel where to load package resources such as views, configuration, and localization files.

所以我们需要创建一个 Service Provider 来告诉 Laravel 使用该插件是,什么 Controller 被执行了,Routes 和 Views 在哪加载等等。

// 在 Laravel项目根目录执行命令

php artisan make:provider Num2nmbServiceProvider

再将 Num2nmbServiceProvider.php 文件移动到插件 src 文件夹下,并修改namespace 名为:Fanly\Num2nmb

这也正如官网的说明一样,service provider 主要包括两个方法:register 和 boot方法。

A service provider extends the Illuminate\Support\ServiceProvider class and contains two methods: register and boot. The base ServiceProvider class is located in the illuminate/support Composer package, which you should add to your own package's dependencies. To learn more about the structure and purpose of service providers, check out their documentation.

有了 Service Provider,我们可以先加入到 config/app.php 中。

接下来让我们跟常规开发一样,创建功能的 Controller,Route 和 View。

6. 创建 Controller

从网上 copy 了一段「数字金额转中文大写金额」功能,直接上代码:

<?php
/**
 * Created by PhpStorm.
 * User: ye
 * Date: 2018/1/10
 * Time: 下午9:49
 */

namespace Fanly\Num2nmb;


use App\Http\Controllers\Controller;

class Num2nmbController extends Controller {

    public function index($num) {
        $nmb = $this->num2nmb($num);
        return view('num2nmb::nmb', compact('nmb'));
    }

    private function num2nmb($num) {
        $c1 = "零壹贰叁肆伍陆柒捌玖";
        $c2 = "分角元拾佰仟万拾佰仟亿";

        //精确到分后面就不要了,所以只留两个小数位
        $num = round($num, 2);
        //将数字转化为整数
        $num = $num * 100;

        if (strlen($num) > 10) {
            return "金额太大,请检查";
        }
        $i = 0;
        $c = "";
        while(1) {
            if ($i == 0) {
                //获取最后一位数字
                $n = substr($num, strlen($num) - 1, 1);
            } else {
                $n = $num % 10;
            }    //每次将最后一位数字转化为中文
            $p1 = substr($c1, 3 * $n, 3);
            $p2 = substr($c2, 3 * $i, 3);
            if ($n != '0' || ($n == '0' && ($p2 == '亿' || $p2 == '万' || $p2 == '元'))) {
                $c = $p1 . $p2 . $c;
            } else {
                $c = $p1 . $c;
            }
            $i = $i + 1;
            //去掉数字最后一位了
            $num = $num / 10;
            $num = (int) $num;
            //结束循环
            if ($num == 0) {
                break;
            }
        }
        $j = 0;
        $slen = strlen($c);
        while ($j < $slen) {
            //utf8一个汉字相当3个字符
            $m = substr($c, $j, 6);
            //处理数字中很多0的情况,每次循环去掉一个汉字“零”
            if ($m == '零元' || $m == '零万' || $m == '零亿' || $m == '零零') {
                $left = substr($c, 0, $j);
                $right = substr($c, $j + 3);
                $c = $left . $right;
                $j = $j - 3;
                $slen = $slen - 3;
            }
            $j = $j + 3;
        }

        //这个是为了去掉类似23.0中最后一个“零”字
        if (substr($c, strlen($c) - 3, 3) == '零') {
            $c = substr($c, 0, strlen($c) - 3);
        }

        //将处理的汉字加上“整”
        if (empty($c)) {
            return "零元整";
        } else {
            return $c . "整";
        }
    }
}

7. 创建 View

这个很简单了,从 welcome.blade.php 直接 copy 过来,放在 src/views/nmb.blade.php:

<!doctype html>
<html lang="{{ app()->getLocale() }}">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Laravel</title>

    <!-- Fonts -->
    <link href="https://fonts.googleapis.com/css?family=Raleway:100,600" rel="stylesheet" type="text/css">

    <!-- Styles -->
    <style>
        html, body {
            background-color: #fff;
            color: #636b6f;
            font-family: 'Raleway', sans-serif;
            font-weight: 100;
            height: 100vh;
            margin: 0;
        }

        .full-height {
            height: 100vh;
        }

        .flex-center {
            align-items: center;
            display: flex;
            justify-content: center;
        }

        .position-ref {
            position: relative;
        }

        .top-right {
            position: absolute;
            right: 10px;
            top: 18px;
        }

        .content {
            text-align: center;
        }

        .title {
            font-size: 84px;
        }

        .links > a {
            color: #636b6f;
            padding: 0 25px;
            font-size: 12px;
            font-weight: 600;
            letter-spacing: .1rem;
            text-decoration: none;
            text-transform: uppercase;
        }

        .m-b-md {
            margin-bottom: 30px;
        }
    </style>
</head>
<body>
<div class="flex-center position-ref full-height">
    <div class="content">
        <div class="title m-b-md">
            {{ $nmb }}
        </div>
        <div class="links">
            <a href="https://laravel.com/docs">fanly</a>
        </div>
    </div>
</div>
</body>
</html>

8. 添加 Route

在 src目录下,创建 routes.php 文件

Route::get('num2nmb/{num}', 'Fanly\Num2nmb\Num2nmbController@index');

9. 配置 Service Provider

有了 controller、view 和路由,直接在 Num2nmbServiceProvider 配置相关信息即可:

在 boot 函数中,加入代码:

$this->loadViewsFrom(__DIR__.'/views', 'num2nmb');

在 register 函数加入代码:

10. 测试

如图:

11. Publishing the Views

最后,view 层是高度自定义层,所以有必要将 views 试图 publish 到项目中,我们就可以改动显示效果,而不至于去变化插件中 views 的代码了,而且这本身也是不允许的。

可以在 boot 函数中加入代码:

$this->publishes([
            __DIR__.'/views' => base_path('resources/views/num2nmb'),
        ]);

最后,执行命令:

12. 使用「包自动发现」

Laravel 5.5 增加了一个新的功能 「Package Auto Discovery」。这个功能使得 Laravel 能更容易地对包进行安装和启用的管理。

包的开发者可以在 composer.json 文件中添加一个新的部分,用来告诉框架应该注册哪些服务提供器或者它们的外观。

我们可以试试这个功能,在插件的 composer.json 中加入如下代码:

"extra": {
        "laravel": {
            "providers": [
                "Barryvdh\\Debugbar\\ServiceProvider"
            ]
        }
    }

注: 有关「Package Auto Discovery」功能的说明和使用,可以参考:

1. 深入了解 Laravel 5.5 Package Auto Discovery zhuanlan.zhihu.com/p/27518011

2. Laravel 5.5 支持包自动发现(新功能早知道)laravel-china.org/articles/49…

3. Laravel Package Auto-Discovery laravel-news.com/package-aut…

4. Package Auto-Discovery In Laravel 5.5 medium.com/@taylorotwe…

总结

下一步,我们需要将做好的插件包提交服务器,供其他人使用。

「未完待续」


coding01 期待您继续关注

qrcode