如何開發一個 Notadd 模組

依劍聽雨發表於2017-03-07

模組程式碼結構請參考專案 https://github.com/notadd/content

模組將包含如下幾個部分:

  • 模組注入
  • 路由注入
  • 門面注入
  • CSRF注入

模組安裝

對於模組的安裝,目前 Notadd 支援的安裝方式,僅為在 根專案 中對 模組 進行依賴。

例如,需要安裝模組 notadd/content ,可以修改根專案的檔案 composer.json,參考程式碼如下:

{
    "name": "notadd/notadd",
    "description": "The Notadd Framework.",
    "keywords": [
        "notadd",
        "cms",
        "foundation",
        "framework"
    ],
    "homepage": "https://notadd.com",
    "license": "Apache-2.0",
    "type": "project",
    "authors": [
        {
            "name": "twilroad",
            "email": "269044570@qq.com"
        }
    ],
    "autoload": {
        "classmap": [
            "storage/databases"
        ]
    },
    "require": {
        "php": ">=7.0",
        "notadd/content": "0.1.*",
        "wikimedia/composer-merge-plugin": "dev-master"
    },
    "require-dev": {
        "fzaninotto/faker": "~1.4",
        "mockery/mockery": "0.9.*",
        "phpunit/phpunit": "~5.0",
        "symfony/css-selector": "3.1.*",
        "symfony/dom-crawler": "3.1.*"
    },
    "config": {
        "preferred-install": "dist"
    },
    "scripts": {
        "post-create-project-cmd": [
            "php notadd key:generate"
        ],
        "post-install-cmd": [
            "Notadd\\Foundation\\Composer\\ComposerScripts::postInstall",
            "php notadd optimize"
        ],
        "post-update-cmd": [
            "Notadd\\Foundation\\Composer\\ComposerScripts::postUpdate",
            "php notadd optimize"
        ]
    },
    "extra": {
        "merge-plugin": {
            "include": [
                "extensions/*/*/composer.json"
            ],
            "recurse": true,
            "replace": false,
            "merge-dev": false
        }
    }
}

更新檔案 composer.json 後,執行 composer update 即可完成對模組的安裝。

完整示例程式碼,請參考專案 https://github.com/notadd/notadd

目錄結構

目錄結構如下:

module                                             模組目錄
    resources                                      資源目錄
        translations                               翻譯檔案目錄
        views                                      檢視目錄
    src                                            原始碼目錄
        ModuleServiceProvider.php                  模組服務提供者定義檔案
    composer.json                                  Composer 配置檔案

一個 Notadd 的模組,是一個符合 composer 規範的包,所以,模組對第三方程式碼有依賴時,可以在 composer.json 中的 require 節點中新增第三方的包。

而作為一個符合 Notadd 模組定義規範的包,composer.json 需擁有如下資訊:

  • type 必須為 notadd-module
  • require 中必須新增包 notadd/installers

程式碼參考如下(來自擴充套件根目錄下的檔案 composer.json, 檔案中不應該包含 // 的註釋資訊,此處僅作為說明)

{
    "name": "notadd/content",
    "description": "Notadd's Content Module.",
    "keywords": [
        "notadd",
        "cms",
        "framework",
        "content"
    ],
    "homepage": "https://notadd.com",
    "license": "Apache-2.0",
    "type": "notadd-module",                                                          // type 必須設定為 notadd-module
    "authors": [
        {
            "name": "Notadd",
            "email": "notadd@ibenchu.com"
        }
    ],
    "require": {
        "php": ">=7.0",
        "notadd/installers": "0.1.*"                                                  // 必須依賴包 notadd/installers
    },
    "autoload": {
        "psr-4": {
            "Notadd\\Content\\": "src/"
        }
    }
}

模組注入

所謂 模組注入 ,是 Notadd 在載入模組的時候,會檢索模組目錄下的類 ModuleServiceProvider,此類必須命名為 ModuleServiceProvider,且需放在原始碼根目錄中,且名稱空間必須為 composer.json 的中 autoload 節點定義的符合 psr-4 規範的名稱空間,否則 Notadd 將不能正確載入模組!

類 ModuleServiceProvider 的父類必須為 Illuminate\Support\ServiceProvider ,且必須包含 boot 方法。相關服務提供者的概念可以參考 Laravel 文件。

類 ModuleServiceProvider 的程式碼參考如下:


<?php
/**
 * This file is part of Notadd.
 *
 * @author TwilRoad <269044570@qq.com>
 * @copyright (c) 2016, iBenchu.org
 * @datetime 2016-10-08 17:12
 */
namespace Notadd\Content;

use Illuminate\Events\Dispatcher;
use Illuminate\Support\ServiceProvider;
use Notadd\Content\Listeners\RouteRegister;

/**
 * Class Module.
 */
class ModuleServiceProvider extends ServiceProvider
{
    /**
     * Boot service provider.
     */
    public function boot()
    {
        $this->app->make(Dispatcher::class)->subscribe(RouteRegister::class);                // 訂閱事件 RouteRegister
    }
}

路由注入

由於 Notadd 的路由注入,需要實現事件 RouteRegister,並在事件監聽中新增 路由 。

所以,所謂的路由注入,實際是在類 ModuleServiceProvider 實現事件 RouteRegister 的訂閱,並在事件訂閱類中註冊模組所需要的路由。

類 ModuleServiceProvider 的程式碼參考如下:

<?php
/**
 * This file is part of Notadd.
 *
 * @author TwilRoad <269044570@qq.com>
 * @copyright (c) 2016, iBenchu.org
 * @datetime 2016-10-08 17:12
 */
namespace Notadd\Content;

use Illuminate\Support\ServiceProvider;

/**
 * Class Module.
 */
class ModuleServiceProvider extends ServiceProvider
{
    /**
     * Boot service provider.
     */
    public function boot()
    {
    }
}

事件訂閱類 RouteRegister 的程式碼參考如下:

<?php
/**
 * This file is part of Notadd.
 *
 * @author TwilRoad <269044570@qq.com>
 * @copyright (c) 2016, iBenchu.org
 * @datetime 2016-10-08 18:30
 */
namespace Notadd\Content\Listeners;

use Notadd\Content\Controllers\Api\Article\ArticleController as ArticleApiController;
use Notadd\Foundation\Routing\Abstracts\RouteRegistrar as AbstractRouteRegistrar;

/**
 * Class RouteRegister.
 */
class RouteRegister extends AbstractRouteRegistrar
{
    /**
     * Handle Route Registrar.
     */
    public function handle()
    {
        $this->router->group(['middleware' => ['cross', 'web']], function () {               // 路由的註冊
            $this->router->group(['prefix' => 'api/article'], function () {
                $this->router->post('find', ArticleApiController::class . '@find');
                $this->router->post('fetch', ArticleApiController::class . '@fetch');
            });
        });
    }
}

門面注入

門面,是 Laravel 的一個功能特色,可以透過門面呼叫對應 IoC 容器的例項,所以 Notadd 必然會保留這一功能。

所謂的路由注入,實際是在類 ModuleServiceProvider 實現事件 FacadeRegister 的訂閱,並在事件訂閱類中註冊模組所需要的路由。

類 ModuleServiceProvider 的程式碼參考如下:

<?php
/**
 * This file is part of Notadd.
 *
 * @author TwilRoad <269044570@qq.com>
 * @copyright (c) 2016, iBenchu.org
 * @datetime 2016-10-08 17:12
 */
namespace Notadd\Content;

use Illuminate\Events\Dispatcher;
use Illuminate\Support\ServiceProvider;
use Notadd\Content\Listeners\FacadeRegister;

/**
 * Class Module.
 */
class ModuleServiceProvider extends ServiceProvider
{
    /**
     * Boot service provider.
     */
    public function boot()
    {
        $this->app->make(Dispatcher::class)->subscribe(FacadeRegister::class);
    }
}

事件訂閱類 FacadeRegister 的程式碼參考如下:

<?php
/**
 * This file is part of Notadd.
 *
 * @author TwilRoad <269044570@qq.com>
 * @copyright (c) 2017, iBenchu.org
 * @datetime 2017-01-22 12:20
 */
namespace Notadd\Content\Listeners;

use Notadd\Foundation\Event\Abstracts\EventSubscriber;
use Notadd\Foundation\Facades\FacadeRegister as FacadeRegisterEvent;

/**
 * Class FacadeRegister.
 */
class FacadeRegister extends EventSubscriber
{
    /**
     * Name of event.
     *
     * @throws \Exception
     * @return string|object
     */
    protected function getEvent()
    {
        return FacadeRegisterEvent::class;
    }

    /**
     * Event handler.
     *
     * @param $event
     */
    public function handle(FacadeRegisterEvent $event)
    {
        $event->register('Log', 'Illuminate\Support\Facades\Log');
    }
}

CSRF注入

所謂的CSRF注入,實際是在類 ModuleServiceProvider 實現事件 CsrfTokenRegister 的訂閱,並在事件訂閱類中註冊模組所需要的路由。

類 ModuleServiceProvider 的程式碼參考如下:

<?php
/**
 * This file is part of Notadd.
 *
 * @author TwilRoad <269044570@qq.com>
 * @copyright (c) 2016, iBenchu.org
 * @datetime 2016-10-08 17:12
 */
namespace Notadd\Content;

use Illuminate\Events\Dispatcher;
use Illuminate\Support\ServiceProvider;
use Notadd\Content\Listeners\CsrfTokenRegister;

/**
 * Class Module.
 */
class ModuleServiceProvider extends ServiceProvider
{
    /**
     * Boot service provider.
     */
    public function boot()
    {
        $this->app->make(Dispatcher::class)->subscribe(CsrfTokenRegister::class);
    }
}

事件訂閱類 CsrfTokenRegister 的程式碼參考如下:

<?php
/**
 * This file is part of Notadd.
 *
 * @author TwilRoad <269044570@qq.com>
 * @copyright (c) 2017, iBenchu.org
 * @datetime 2017-02-10 11:04
 */
namespace Notadd\Content\Listeners;

use Notadd\Foundation\Event\Abstracts\EventSubscriber;
use Notadd\Foundation\Http\Events\CsrfTokenRegister as CsrfTokenRegisterEvent;

/**
 * Class CsrfTokenRegister.
 */
class CsrfTokenRegister extends EventSubscriber
{
    /**
     * Name of event.
     *
     * @throws \Exception
     * @return string|object
     */
    protected function getEvent()
    {
        return CsrfTokenRegisterEvent::class;
    }

    /**
     * Register excepts.
     *
     * @param $event
     */
    public function handle(CsrfTokenRegisterEvent $event)
    {
        $event->registerExcept('api/article*');
        $event->registerExcept('api/category*');
        $event->registerExcept('api/content*');
        $event->registerExcept('api/page*');
    }
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章