A Day In The Boy's Life -13ページ目

A Day In The Boy's Life

とあるエンジニアのとある1日のつぶやき。

Laravelではartisanコマンドを通してコマンドラインから様々な処理を実行することができます。

アプリケーションを作成した場合、全てがWebインターフェースで実装するということは難しい場合もあるので、コマンドラインから実行できるバッチファイルを用意した ほうが便利なことが多かったりします。

ということで、Laravel4.2をベースにしたLaravel上でコマンドを作成する手順のまとめです。



コマンドのテンプレートを作成する


artisanコマンドはlaravelディレクトリの直下に存在し、色んな処理を実行することができます。


$ php artisan list
Laravel Framework version 4.2.18

Usage:
  [options] command [arguments]

Options:
  --help           -h Display this help message
  --quiet          -q Do not output any message
  --verbose        -v|vv|vvv Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
  --version        -V Display this application version
  --ansi              Force ANSI output
  --no-ansi           Disable ANSI output
  --no-interaction -n Do not ask any interactive question
  --env               The environment the command should run under.

Available commands:
  changes                     Display the framework change list
  clear-compiled              Remove the compiled class file
  down                        Put the application into maintenance mode
  dump-autoload               Regenerate framework autoload files
  env                         Display the current framework environment
  help                        Displays help for a command
  list                        Lists commands
  migrate                     Run the database migrations
  optimize                    Optimize the framework for better performance
  routes                      List all registered routes
  serve                       Serve the application on the PHP development server
  tail                        Tail a log file on a remote server
  tinker                      Interact with your application
  up                          Bring the application out of maintenance mode
  workbench                   Create a new package workbench
asset
  asset:publish               Publish a package's assets to the public directory
auth
  auth:clear-reminders        Flush expired reminders.
  auth:reminders-controller   Create a stub password reminder controller
  auth:reminders-table        Create a migration for the password reminders table
cache
  cache:clear                 Flush the application cache
  cache:table                 Create a migration for the cache database table
command
  command:make                Create a new Artisan command
- snip -

この中に自作したコマンドを追加しオプションを指定することでバッチ処理を実行できたりします。

まずは、コマンドファイルを作ることからスタートなのですが、一からコマンドファイルを作成するのも手間なので、そのテンプレートファイルをartisanコマンドを通し て作成することができます。


$ php artisan command:make FooCommand

上記のように実行することでFooCommandファイルを作成することができます。

正常に実行されると、laravel/app/commandsディレクトリ以下に作成されます。


<?php

use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;

class FooCommand extends Command {
    /**
     * The console command name.
     *
     * @var string
     */
    protected $name = 'command:name';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description.';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function fire()
    {
        //
    }

    /**
     * Get the console command arguments.
     *
     * @return array
     */
    protected function getArguments()
    {
        return array(
            array('example', InputArgument::REQUIRED, 'An example argument.'),
        );
    }

    /**
     * Get the console command options.
     *
     * @return array
     */
    protected function getOptions()
    {
        return array(
            array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
        );
    }
}


コマンドを作成する


作成したテンプレートファイルを元に中身を編集していきます。

プロパティの$nameはコマンド名、$descriptionはコマンドの概要を記載しておきます。

この内容はartsanコマンド実行時に表示されるのでコマンドの中身がわかるように編集しておきましょう。

バッチ処理の具体的な中身はfire()メソッドの中に定義します。


public function fire()
{
    $obj = App::make('SomeClass');
    echo "hello" . PHP_EOL;
}

基本的にLaravelと同様の文法が使えるので、パスが通っていれば上記のようにSomeClassのオブジェクトを生成するというようなこともできます。

バッチ処理が書けたらコマンドをartisanコマンドから実行できるように登録します。

登録するには、laravel/app/start/artisan.phpに下記のように追加します。


<?php

Artisan::add(new FooCommand);

これで、再度artisanコマンドを実行してみると


$ php artisan
-snip-
Foo
  Foo:echoHello               hello出力バッチ
  changes                     Display the framework change list
  clear-compiled              Remove the compiled class file
-snip-

というようにコマンドが登録されています。

余談にはなりますが、「Laravelでサブシステム用のディレクトリを分離する 」に書いたような独自のディレクトリ構成をとった場合は、サービスプロバイダー用 のファイルからコマンドを追加することも出来ます。


public function boot()
{
    \ClassLoader::addDirectories(array(
        __DIR__ . '/../Commands',
    ));
    require __DIR__ . '/../routes.php';
}

public function register()
{
    $this->commands('FooCommand');
}

コマンドを実行するには


$ php artisan Foo:echoHello
hello

というように実行できます。

コマンドには引数とオプションを指定できます。

それぞれ、コマンドファイルのgetArguments()、getOptions()にて指定でき必須の引数などを指定できます。


protected function getArguments()
{
    return array(
        array('name', InputArgument::REQUIRED, 'your name'),
    );
}

protected function getOptions()
{
    return array(
        array('test', 't', InputOption::VALUE_OPTIONAL, 'run test mode', 'false'),
    );
}

上記の場合、引数の名前を必須とし、オプションとしてtestを用意しています。

fire()を少し変更してみます。


public function fire()
{
    if ($this->option('test') === 'true') {
        echo "run test mode" . PHP_EOL;
    }
    echo "hello " . $this->argument('name') . PHP_EOL;
}

オプションにtestが指定された場合はテストモードでの実行であることを表示し、引数nameに指定された名前を結合して出力するようにしています。

これで、下記のように実行してみると


$ php artisan Foo:echoHello itboy --test=true                                  
run test mode
hello itboy

のような結果が出力されます。

この状態では引数が必須(REQUIRED)となっているため、引数を指定しない場合は下記のようなエラーがでます。


$ php artisan Foo:echoHello
  [RuntimeException]
  Not enough arguments.

Foo:echoHello [--test[="..."]] name

引数を任意にしたい場合は


array('name', InputArgument::OPTIONAL, 'your name'),

とします。

オプションは動かし方に好みがあったりするのですが、オプション自体に値を指定したくない場合(--testでテストモード扱いにしたい)は、値を受け取らないこともできます。


array('test', 't', InputOption::VALUE_NONE, 'run test mode', null),

この場合、fire()の中では


if ($this->option('test') === TRUE) {
    echo "run test mode" . PHP_EOL;
}

のようにすることでオプションが指定されたかどうかだけで判別ができるようになります。

また、getOptions()で戻している配列の第2引数は短縮系を表すのでシンプルに


$ php artisan Foo:echoHello -t

というような実行も出来ます(--testまたは-tの両方が利用可能)。

あとは、コマンド実行スクリプトをCronなりジョブ管理ツールなどに登録するなりで定期的に実行すればいいかもしれません。





アナウンスされているとおり、Google Code が今月の2016年1月でサービスを停止するようです。

このブログではAmebloのフリープラグインのJavaScriptをGoogle codeにホストしたよ に書いたように、ソースコードを整形して表示してくれるSyntaxHighlighterや、Twitterなどのシェアボタンの設置をするためのJavaScriptのコードをGoogle Codeにホストしていたのですが、サービス終了に伴い別のホスティングサービスに移行する必要が出てきました。


まぁ、ホスティングサービスと言っても、Google CodeのSVNの公開リポジトリ上のソースのパスを読み込ませていただけなので、同様のことができるサービスがないかを探していてBitbucket というサービスを使ってみることにしました。
今時、ソース管理するならGitHubでしょってのはあるのですけれども、GitHubはプライベートリポジトリが無料だと持てないのと、特にほかに公開しているソースとかもないのでBitbucketで十分かなと思い選択してみました。



Google CodeのソースをBitbucketにインポートする


とりあえずBitbucketにアカウントを作成したら、リポジトリのインポートメニューからGoogle CodeのソースをBitbucket上のリポジトリへインポートします。


Bitbucket-menu

インポート対象となるソースの選択肢にGoogle Codeがあるのでインポート自体は難しくはありません。

Google Codeのプロジェクト名を指定して、リポジトリのタイプ(自分の場合はSubversionで管理してたので)を選択し、リポジトリのインポートボタンから取り込めます。


bitbucket-import


ポイントはリポジトリ名(Repository name)に「ユーザー名.bitbucket.org」と指定することです。
こうすることで、このリポジトリ名がそのまま公開されるURLとしてホストしている各ファイルへアクセスすることが可能となります。


ただ、そのままやると下記のようにインポート時にエラーが出てしまいました。


-snip-
17:10:39 Subversion checkout successful
17:10:39 Creating new git repository...
17:10:39 Initialized empty Git repository in itboy/itboy/bb_tmp/.git/
17:10:40 Done
17:10:42 Done
17:10:42 fatal: No existing author found with 'itboy (itboy)'
17:10:42 Unable to convert svn checkout to git
17:10:42 Svn checkout failed: <class 'bitbucket.apps.async.tasks.ImportException'>: Command failed. Return value: 128

理由は、Gitへのインポート時にauthorの情報が正しくないというもので、しばらくはまりましたがBitbucket上のプロファイルを下記のように編集することでうまくインポートできるようになります。

(プロファイルの編集は、右上の人のアイコンからSettingsを選択)


bitbucket-settings
要は、姓名の欄にユーザー名とメールアドレスを指定してGitのauthorの形式に合わせてあげることでうまくインポートすることができます。


リポジトリへのインポートが完了すれば、先ほどのリポジトリ名で指定したURLでアクセスが可能となります。

例えば、foo.jsをリポジトリに登録した場合は、


http://itboy.bitbucket.org/foo.js


というURLで公開されますので、後はこのJSファイルをブログに読み込ませるということで完了です。



※ この記事はLaravel4.2を対象にしています。


Laravelのコントローラからリダイレクトをかけたり、Viewにて特定のURLへリンクしたりということは良くありますが、Laravelは現在の通信の状況をみてアクセス先の URLスキームを決めているようです。

つまり、HTTPで通信していた場合、デフォルトではリダイレクト先やリンク先もHTTPとみなされたりします。

まぁ、これはもちろんオプションが用意されているのでSSLでPOSTやGETするといったことをオプションによって区別させることができます。

例えばBladeの中で、form内の遷移先のURLを指定する際にURL::toメソッドを使う場合に第3引数をtrueとすることでHTTPSのURLを指定することができます。


{{ Form::open(array('url' => URL::to('/path/to/next', array(), true), 'name'=>'formName', 'id'=>'formId')) }}
-snip-
{{ Form::close() }}

実は、URL::toをSSL通信に特化させたければ


URL::secure('/path/to/next', array())

なんてメソッドもあるみたいなんですけど、書き方が統一されていなければ保守性が落ちそうです。

(link_to()ヘルパーをSSLに強制させるlink_to_secure()なんてヘルパーもあるみたいですけど)

ってことで、いまどきのサービスだと全通信をSSL化するみたいなのが当たり前になっていますし、アプリケーション側でオプションをつけるようなやり方をしているとミ スったと気に穴がでそうなので、統一する方法がないかなと調べてたどり着いた答えが下記です。


URL::forceSchema('https');

アプリケーション起動時に呼び出されるstart.phpの設定ファイル上にURL::forceSchema()にてhttpsを指定しています。

これでURL::toやlink_to()などのヘルパー関数も含めてリンク先のスキームがHTTPSとなります。

リンク先がHTTP/HTTPSでばらけるという場合はヘルパーなどは使わずに直接リンクタグとか書いたほうが便利かもしれません。