7月 052015
 

こんにちは。ファガイです。
やっと、サービスプロバイダの知識が付いてきて、既存のクラスにサービスプロバイダを用意し、依存注入ができるようにします。
自分が先日作ったライブラリの解説でもあります。

使用環境

  • PHP 5.6
  • Laravel 5.1

概要

この記事は、自分が以前開発したPHP-VoiceTextを、Laravel用に、Laravel-VoiceTextを作成した話を元にしています。

なので、ソース読んでもらうほうが早く済むかもです。

知っておかなきゃいけないこと

まずServiceProviderを使う上で、知っておくべき知識があります。
DIの基本だけは、先に知っておいてください。おそらく私が以前書いたLaravelのIoCコンテナ、サービスコンテナに関してまとめ -その1が参考になります。
また、gitの基本知識が必要です。

リポジトリのディレクトリを作る

まず、gitリポジトリ用にディレクトリを作って、git initします。

mkdir laravel-voicetext
cd laravel-voicetext
git init

これで、とりあえずgitリポジトリになりました。

composer.jsonを用意する

今回は、私が作っていた物をcomposerから入れたいと思ってます、そして今回作ったものをpackagistにも公開したいので以下を打ちます。

composer init

色々アプリケーション名とか聞かれますがそれっぽく打ってもらえればおっけーです。

Welcome to the Composer config generator

This command will guide you through creating your composer.json config.

Package name (<vendor>/<name>) [user/laravel-voicetext]: fagai/laravel-voicetext{Enter}
Description []:{Enter}
Author [fagai <fagai@example.com>]:{Enter}
Minimum Stability []:{Enter}
License []: MIT{Enter}

Define your dependencies.

Would you like to define your dependencies (require) interactively [yes]?
Search for a package []:{Enter}
Would you like to define your dev dependencies (require-dev) interactively [yes]?{Enter}
Search for a package []:{Enter}

それで、最後の方で、確認メッセージが出ます。


{
    "name": "fagai/laravel-voicetext",
    "license": "MIT",
    "authors": [
        {
            "name": "fagai",
            "email": "fagai@example.com"
        }
    ],
    "require": {

    }
}

Do you confirm generation [yes]?{Enter}
Would you like the vendor directory added to your .gitignore [yes]?{Enter}

こんな感じですねー。

ServiceProviderとかメインのファイル置くディレクトリを作る

とりあえず、srcとでもしましょうか。基本的に新しく書くファイルはsrcの下に追加することとなります。

mkdir src

少しcomposer.jsonをいじります。先程作ったsrcに対応するautoloadを追加します。

"autoload": {
    "psr-4" : {
        "Fagai\\VoiceText\\" : "src/"
    }
}

一応解説ですが、psr-4はpsr-0のオートローダーに関する内容を書きかえるものです。
単純に変わる所は、src直下からFagai\\VoiceText\\の名前空間が始まるということくらいです。psr-0の場合は名前空間でディレクトリを掘る必要がありました。なので、psr-4を使ってます。
また、今回は自分が作っていたライブラリだったこともあり、php-voicetextと同じ名前空間を利用しています。

読み込みの部分は適宜読み替えちゃってください。

configを置くディレクトリを用意する

今回使用するphp-voicetextはクラスを生成する際に、apiキーを指定する必要があります。
この値はconfigで持っておきたいので、そのためにディレクトリを作成します。

作る場所は、srcの中ではなく、ルートディレクトリに追加してください。それだと読めなくない?と思われるかもしれませんが読めなくて良いんです。これを作る目的はLaravelアプリケーションのconfigの中にコピーさせて使わせるのが目的です。

mkdir config

ついでに、今回利用するconfigファイルも仮作成しておきましょう。

cd config
vi voicetext.php

一応中身はこんな感じで。

<?php
return [
    'api-key' => '<your api key.>'
];

使用したいクラスを用意する

では、クラスを用意します。
今回は、composerから導入していますが、自分で用意してもらって構いません。

composer require fagai/voicetext:0.2

これで、入りましたねー。

サービスプロバイダーを作る

では、ServiceProviderを作ってみましょう。
先程のsrcフォルダに、ServiceProvider.phpを作成します。
とりあえず完成品が以下。

<?php namespace Fagai\VoiceText;
class ServiceProvider extends \Illuminate\Support\ServiceProvider
{
    /**
     * 遅延ローディング
     * @var bool
     */
    protected $defer = true;
    public function register()
    {
        $this->mergeConfigFrom($this->configPath(), 'voicetext');
        $this->app->singleton('voicetext', function($app) {
            $config = $app['config'];
            return new VoiceText($config->get('voicetext.api-key'));
        });
    }
    public function boot()
    {
        $this->publishes([$this->configPath() => config_path('voicetext.php')], 'config');
    }
    public function provides()
    {
        return ['voicetext'];
    }
    protected function configPath()
    {
        return __DIR__ . '/../config/voicetext.php';
    }
}

ここで、いくつか説明しておくべきことがあるので、紹介します。

registerとboot。

registerとbootの違いは、それほど大きくなくて、bootはregisterをする前に知っておかなくてはいけない情報等を登録します。
registerはbootに書かなくても良い処理を記述します。

bootでのconfigの設定

大抵の場合、registerだけで済みますが、少し凝った内容を行う場合はbootも必要です。
このライブラリの場合は、apiの文字列をconfigに持っておきたいので、元のライブラリのconfigの場所から対象のパスにコピーさせるための情報を記述しておきます。

$this->publishes([$this->configPath() => config_path('voicetext.php')], 'config');

ですが、展開するとこんな感じです。

$this->publishes([
__DIR__'/../config/voicetext.php' => Laravelのconfigのpath.'voicetext.php'
], 'config');

先程のconfig/voicetext.phpをLaravelのconfigのpathのvoicetext.phpと対応付けさせておく設定です。
publishesは、artisan vendor:publishコマンドを打った際に使用されます。また、第2引数にconfigと記載していますが、これはタグ付けです。
artisan vendor:publish --tag=config と打ったらこの第2引数の値がconfigの物だけpublishされます。

一応付けなくてもいいのですが、付けなかったら全部publishされるのでconfigとだけ名前をつけています。(実際は上書きとかされないので大丈夫らしいですが)

※vendor:publishはLaravel5から追加されていて、Laravel4では、config:publishという名前でした。

registerでのconfigの設定

また、このconfigは使用する際に、デフォルトの値とマージさせたいのでregisterメソッドに以下の記述があります。

$this->mergeConfigFrom($this->configPath(), 'voicetext');

registerの時点で、すでにpublish済みのconfigはロードされているので、第2引数はConfig::getで取得する文字列です。
これでデフォルトの値とのマージがされるので、記載されていないconfigがあったとしても問題なく動作させることが出来ます。

サービスコンテナへの登録

そして、ServiceProviderでも一番重要な箇所であるサービスコンテナへの登録です。
今回のクラスは、それほどクラスを毎回生成しなくても問題無い感じなので、シングルトンで管理します。

以前までは$this->app->shareというメソッドがよく使われていましたが、singletonでも普通に代用出来るので、singletonで書いちゃいましょう。

$this->app->singleton('voicetext', function($app) {
    $config = $app['config'];
    return new VoiceText($config->get('voicetext.api-key'));
});

何も難しいこともやってないので、こんな感じです。configからapi-keyを取得してnewして返してます。

deferプロパティ

deferをtrueに設定すると、Laravelの起動時には対象のクラスのインスタンスを作成しません。(遅延ロード)
app('voicetext') の様に、DIを呼ぶことで対象のクラスが生成されます。

そして、deferをtrueにすると、voicetextという文字列がどのサービスプロバイダに依存しているのか把握が出来ないので、 providers メソッドを利用して、利用しているDIの文字列を使ってる分だけ記述する必要があります。

public function provides()
{
    return ['voicetext'];
}

このメソッドはdeferをtrueにしない限り通常は記述しなくても大丈夫です。

細かい話をしなければ、一応ServiceProviderの作成はここまでですね。

Facadeの作成

Facadeの作成ですが、なにもないので、とりあえずファイルだけ。
srcの中にFacade.phpを作成します。

<?php namespace Fagai\VoiceText;
class Facade extends \Illuminate\Support\Facades\Facade
{
    protected static function getFacadeAccessor()
    {
        return 'voicetext';
    }
}

getFacadeAccessorに先程のsingletonのコンテナの文字列を記入しておくだけ。
あとは、app.phpにエイリアス書いておけばコンストラクタインジェクションとか使えるようになります。ただ、今回はsingletonなのであんまりこれ意味無いです。

とりあえず用意しているだけです。

Packagistに公開

あとはgitにpushして、packagistに公開するだけです。
ここは、難しくない&躓いても記事がちゃんとあるので説明しません。

後の利用と、ローカルでのpush前の確認について

ここは一応書いておこうかな。ローカルでgithubに上げる前に先に確認がしたいということがあると思います。

まずは、Laravelが入っているアプリケーションを用意してください。バージョンに対応したアプリケーションを用意しましょう。
ルートにcomposer.jsonがあると思うので、そこにこのような記述をします。

packagistに公開済みで、packagistから取得する場合は、この記述は必要ないです。

"repositories": [
    {
        "type" : "vcs",
        "url" : "/home/user/laravel-voicetext"
    }
]

typeはvcs(バージョンコントロールシステム)、urlに対象の場所のパスを入れます。urlはリモートのファイルでも行けます。
あとは、requireに以下を追加するだけですね。

"require": {
    "fagai/laravel-voicetext" : "dev-master"
}

これで、あとはcomposer installすればおっけーです。
バージョン指定をしたい場合は、tagを基本的に見てます。composerのドキュメントに確か認識出来る名前一覧があったと思います。

まとめ。

以前書いた分離するための記事で、ServiceProviderでの分離がよく分からないという話が出てたと思うので今回書きました。
今回の記事は、既存のライブラリであるlaravel-debugbarとかlaravel-ide-helperとかの中身を見て理解しながら書いてます。

以外と書いてみたら簡単なので、みなさんもやって、どんどん便利なライブラリを増やしていきましょうー。

Pocket

 Posted by at 5:56 PM

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>


*