読者です 読者をやめる 読者になる 読者になる

localdisk

PHP とか Java とか Web とか好きなことを書きます。

PHPカンファレンス関西の感想と100万件バッチで死なないLaravel

laravel event

2016年7月16日(土) に開催された PHP カンファレンス関西 2016 に行ってきました。

conference.kphpug.jp

会場は、昨年と同じブリーゼプラザ(大阪西梅田)で行われました。uzulla さんのエントリにあるように綺麗でオシャレ感漂うビルです。

さて、ここからは聞いたセッションの感想等を。

[基調講演] Composerを速くするために必要だったもの

speakerdeck.com

移動の都合で、はじめのほうを聞き逃してしまったんですけど、最高でした。僕はもう Composer ないと生きていけないし、それをより速くしてくれた Hiraku さんには感謝しかない。 本当に必要だったのは問題を向き合うこと という言葉にはしびれました。

大量のデータで困ってませんか?

Google BigQuery のお話。こういうPHPほとんどでてこない話が聞けるというのも、PHPカンファレンスらしくてよいところ。僕は触ったことがないのですが何かしらのデータを分析するときに使ってみたいなぁ。

ORMユーザー対談 〜Laravel/Doctrine/CakePHP3〜

殴り合いを期待して…というのは冗談で普通に和やかな空気でした。で、最後のほうで「100万件バッチどうする?」という話が出ました。ORM使ってるとこういう大量データのバッチ処理が問題になるのですが、カジュアルに Post::all() とかやると死にます。なので今回は死なない方法をここに書いておきます。5.2.33 以上で使えます。

gist.github.com

44行目に注目してください cursor メソッドを使っています。これは 5.2.33 から追加されました*1。内部でジェネレータを使っているのでメモリ不足で死ななくて最高です。

Laravel は 100万件バッチでも死なない。これだけははっきりと真実を伝えたかった。

あ、あと、MySQLのオプションを変えたいときは config/database.phpoption を変えるとよいです。

fideloper.com

追記

100万件とか作るコマンドも貼っておきます。

gist.github.com

php artisan make:post 1000000 とかやればおk。プログレスバーが使えて便利。こんな感じでバルクインサートできます。

ビューのソースコードコンフリクトから解放される、PHPerのための次世代Webアプリケーション開発への道

人がすごかった。演台の前に体育座りで聴いてた人もいた。この時間はスポンサーブース回ったりEC-Cubeの講演をちら見したり。

Laravel と DIコンテナ、コンポーネントの設計

この講演も人気で入れず。残念。あ、そうそう。動画が公開されるらしいですよ。PHPカンファレンス福岡も先日動画を公開したのでよかったらご覧ください。

PHPerに知ってほしいDB設計の話

speakerdeck.com

そーだい さんの講演はなにげに PHPカンファレンス北海道、福岡、やぱちーと全て聴いています。少しずつアップデートされているのがわかって楽しいです。

LT

で、LT。僕も一枠頂いたのでテストで簡単なモックを作りたいときは無名クラスでいいのではないかという話をさせていただきました。

懇親会

飲んだり食べたり。午前2時くらいまでワイワイやってました。

まとめ

楽しかった!また来るぞ!!

追記

id:sasezaki さんよりコメントをいただいたので、軽く計測してみました。

環境

OS: Mac OS X 10.11.6 CPU: Intel Core i5 2.7 GHz メモリ: 16 GB

Vagrant

Laravel Homestead 使用 CPU: 1 メモリ: 2G

posts テーブル

mysql> show columns from posts;
+------------+------------------+------+-----+---------+----------------+
| Field      | Type             | Null | Key | Default | Extra          |
+------------+------------------+------+-----+---------+----------------+
| id         | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| title      | varchar(255)     | NO   |     | NULL    |                |
| body       | text             | NO   |     | NULL    |                |
| created_at | timestamp        | YES  |     | NULL    |                |
| updated_at | timestamp        | YES  |     | NULL    |                |
+------------+------------------+------+-----+---------+----------------+

計測方法

こんな感じに書いてみました。

<?php

class FetchPost extends Command
{

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $start = microtime(true);
        $posts = Post::cursor();
        foreach ($posts as $post) {
            $this->line($post->body);
        }
        $usage          = number_format(memory_get_usage());
        $peakUsage      = number_format(memory_get_peak_usage());
        $processingTime = (microtime(true) - $start) * 1000;

        $this->info(sprintf("\nMemory: %s / %s bytes\nTime: %f ms", $usage, $peakUsage, $processingTime));
    }
}

計測結果

Memory: 8,126,624 / 426,113,968 bytes
Time: 723790.810108 ms

12分くらい。

*1:カジュアルに機能を足しすぎだよなぁとは思う

PHPカンファレンス北海道に行ってきました

4月16日におこなわれた PHPカンファレンス北海道 2016 に行ってきました。ついでにLaravelを布教してきました。

speakerdeck.com

初心者向けというかフレームワークの乗り換えを考えてる方むけにつくりました。参考になれば幸い。15分はあっという間ですね。

午前一発目の発表だったので、他のセッションも色々見ることができました。以下聞いたセッションの簡単な紹介です。

HerokuでPHPのココが便利

HerokuでPHPのココが便利 mimemo スライドモードがついてるの便利だ。

フリープランが制限されてしまった Heroku ですが、カジュアルに動かせる魅力は相変わらず。Terraform便利っぽい。

クラウド時代だからこそ見直したい
PHPアプリケーションのパフォーマンスチューニング

www.slideshare.net

インフラの話多め。ここらへん強くないので非常に参考になった。スライド見ていただけるとボリュームがかなりあって、時間が足りなくなって大変そうでした。

お昼ごはん

今回は、美味しいお弁当を用意していただきました。唐揚げ弁当美味しかったです。で、お弁当食べながらランチョンスポンサーセッションを聞きました。

PHPer人生、一度はフレームワークを作っておこう!

speakerdeck.com

オレオレフレームワークのすすめ。独自のグルーヴ感と、そのトークを支える技術力。圧巻の一言。このスライドを作るためにオレオレフレームワークを3つ作成してて、熱意がすごい。

PSRを活用するフレームワーク開発

残念。内容は PSR の内容を追っていきながら実際はどのように実装されているのかという話でした。あとミドルウェア。スライドの内容もミドルウェア

PHPerに知ってほしいRDBの事

speakerdeck.com

これも良かったですね。インデックス・実行計画etc…。MySQL は高速・シンプルだが、それを活かすためには設計力が問われるというくだりがよかった。

あとMySQL Workbench で実行計画をグラフィカルに見れるの知らなかった。

漢(オトコ)のコンピュータ道: MySQLでVisual Explain

PHPer にイマイチ PostgreSQL 人気ないの単純に縁がないからなんですよね。WordPress とかそもそも MySQL じゃないと動かないので。PostgreSQL の Window 素敵。

PSR が分かってきた

スライド見つからず。PSR を0から説明していく感じでした。こちらも時間が足りなくなってて、気がついたら徳丸さんの講演が始まってました。

『例えば、PHPを避ける』以降PHPはどれだけ安全になったか

www.slideshare.net

途中からですが素晴らしいプレゼンでした。

  • 検証環境の数驚きの205個
    • Docker でほしい
    • この環境を使って、デモをされてました
  • 「夜遅くに攻撃者の気持ちになってですね…」などおもしろワードが飛び交ってた

振り返って

4年ぶりとの開催とのことでしたが、ブランクを感じさせない素晴らしい内容でした。運営者視点でみると色々参考になることも多く、取り入れたい要素がたくさんありました。懇親会も楽しかった!

次は 5/21 に開催する PHPカンファレンス福岡2016 です。まだまだ参加者を募集しておりますのでお早めにどうぞ。

最後に…今年は PSR の年

なのではないかと思います。北海道でも PSR をネタにした方が3人おり、来月行われる PHPカンファレンス福岡2016 でも同様です。北海道の後、福岡・関西と続きますので東京で総括してくれると楽しいことになると思います(願望)

Laravel 5.2 でセッションがNULLになる時はミドルウェアを疑え

あけましておめでとうございます。今年もよろしくお願いします。

まずはこちらのエントリを参照してみてください。

Laravel 5.2 socialite twitter認証で$this->request->getSession()がnull | Romantique 76

はい、タイトルまんま。Laravel 5.2 でミドルウェアグループという機能ができました。複数ミドルウェアに名前をつけて登録できるというものです。で、この機能が実装されたため、5.1 でグローバルミドルウェアとして登録されていたものが web という名前のミドルウェアグループになってます(グローバルミドルウェアに登録されているのはメンテナンスチェックのみ)。

コードだと App\Http\Kernel クラスがそれになります。 アドベントカレンダーに書いてなくて申し訳ない。

https://github.com/laravel/laravel/blob/master/app/Http/Kernel.php#L26

そんなわけで、今までどおり書いてしまうとセッション等のミドルウェアを通過しなくなるので、なぜかセッションが作られない…どういうことなの…? となります注意してくださいね。下記のように書けばOKです。

<?php

Route::group(['middleware' => ['web']], function () {
    Route::get('/', function () {
        if (! Auth::check()) {
            return Redirect::to('github/authorize');
        }
    });

    Route::get('{provider}/authorize', function ($provider) {
        // ソーシャルログイン処理
        return Socialite::with($provider)->redirect();
    });

    Route::get('{provider}/login', function ($provider) {
        // ユーザー情報取得
        $userData = Socialite::with($provider)->user();
        dd($userData);
    });
});

RateLimit とか MultiAuth とか、書いてない新機能もありますので近いうちに書きます。

デプロイツールを使ってLaravelをデプロイする

メリークリスマス!!この記事は Laravelリファレンス発売記念!販売促進!! Advent Calendar 2015 - Adventar の 12/19 分です。メリークリスマス!!

親方!Capistrano に Laravel プラグインが!

f:id:localdisk:20151206205015p:plain
A remote server automation and deployment tool written in Ruby.

喜び勇んで リポジトリ を参照してみたところ…最終更新が2年前。Laravel 5 対応の PR が5月にされていますが、マージされいない…。解散(白目

ちなみに Ruby の環境を整えてたら2時間くらい吹っ飛んでた。

Deployer を使おう

はい、というわけで Deployer 使ってみましょうか。Rocketeer より簡単ですし、PHPわかんなくても shell がわかればなんとかなります。

Deployer のインストール

TOPページにある Download deployer.phar をクリックして deployer.phar をダウンロードしましょう。これは phar をそのままプロジェクトルートに置くもよし、/usr/local/bin あたりに mv するもよしです。Jenkins さんにデプロイを任せてたいのであれば後者がよいでしょう。

chmod +x depoyer.phar して実行権限をつけておきましょう。詳しいことは公式ドキュメントを読もう。

使ってみる

では、ダウンロードした deployer.phar を叩いてみましょう。

➜  deploy  php deployer.phar
Deployer version 3.0.10

Usage:
  command [options] [arguments]

Options:
  -h, --help            Display this help message
  -q, --quiet           Do not output any message
  -V, --version         Display this application version
      --ansi            Force ANSI output
      --no-ansi         Disable ANSI output
  -n, --no-interaction  Do not ask any interactive question
  -f, --file[=FILE]     Specify Deployer file.
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Available commands:
  help         Displays help for a command
  list         Lists commands
  self-update  Updates deployer.phar to the latest version
  worker       Deployer uses workers for parallel deployment.

なるほど、この時点で実行できるのは help, list, self-update, worker コマンドのみですね。では deploy.php を作って以下のように書いてみましょう。

<?php

require 'recipe/common.php';

でもう一度実行。

➜  deploy  php deployer.phar
Deployer version 3.0.10

Usage:
  command [options] [arguments]

Options:
  -h, --help            Display this help message
  -q, --quiet           Do not output any message
  -V, --version         Display this application version
      --ansi            Force ANSI output
      --no-ansi         Disable ANSI output
  -n, --no-interaction  Do not ask any interactive question
  -f, --file[=FILE]     Specify Deployer file.
      --tag[=TAG]       Tag to deploy.
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Available commands:
  cleanup             Cleaning up old releases
  current             Show current release.
  help                Displays help for a command
  list                Lists commands
  rollback            Rollback to previous release
  self-update         Updates deployer.phar to the latest version
  worker              Deployer uses workers for parallel deployment.
 deploy
  deploy:copy_dirs    Copy directories
  deploy:prepare      Preparing server for deploy
  deploy:release      Prepare release
  deploy:shared       Creating symlinks for shared files
  deploy:symlink      Creating symlink to release
  deploy:update_code  Updating code
  deploy:vendors      Installing vendors
  deploy:writable     Make writable dirs

お、実行できるタスクが随分増えました。これは、deployer はデフォルトで deploy.php が探す*1のと recipe/common.php にあらかじめ便利そうなタスク群が組み込まれているためです。

ついでに説明しておきますと、Deployerは使う分には学習コストがほとんどかからないことです。半日くらいいじっていれば大体なんとかなります。

deployer
├── bin
├── recipe
├── src
└── test

上記が deployer のディレクトリ構成なんですが、bin のなかの dep というファイルがコマンドを受け付けるエンドポイント。recipeディレクトリがフレームワークや著名なプロダクト(WrodPressとかDrupalとか)のデプロイタスクとか。大事なのは common.php で、他の各タスクもこの common.phprequire してます。

タスクがどんな処理をやってるかはソースコードみれば大体わかります。php よりも shell の知識があったほうがよいくらいです。

各タスクがなにやってるのか

全ては網羅してませんが、だいたいこんな感じです。

あとはリリースをひとつ前に戻す rollback とか大体揃ってる感じです。

サーバーとの接続

こんな感じ。server 関数を使います。第1引数は任意の名前、第2引数がホスト名あるいはIPアドレス、第3引数がポート。user 関数はログインユーザー、identityFilessh の key を指定します。今回は ssh 使ってますが、password 関数もあるのでそういう認証も可能。stage 関数はデプロイ対象サーバーがたくさんある場合に意味が出てきます。今回は割愛。で、env 関数でデプロイするディレクトリを指定。

詳しく知りたい場合は Deployer — Servers を熟読しよう。

<?php

require 'recipe/laravel.php';

server('test', '127.0.0.1', 2222)
    ->user('vagrant')
    ->identityFile('public key path', 'private key path')
    ->stage('test')
    ->env('deploy_path', '/home/vagrant/deploy_test');


set('repository', 'https://github.com/laravel/laravel');

で、 php deployer.phar deploy -vvv test とやればOK。test はサーバーで指定した名前、-vvv とやるとログが詳細にでるので便利。この例では Laravel のレシピを使ってますが、実際使うときは 最新レシピを使ったほうがいいかもですが、これでも色々足りなかったり(optimizeとか)cleanup してたりする(cleanup されたら rollback 不可)ので自分でタレ作ったほうがよいです。年内に僕のタレをここに載せておきます(このエントリも複数日に分けて書いてます)。 載せました。

gist.github.com

カスタマイズとか

recipe を読むと捗ります。ローカルから直接アップロードとか。functions.php を見ておくとはかどります。自分でタスク作ったりとかそういうやつです。migrate したり optimize したり等々。あとサードパーティのレシピも参考になります。

では、よいクリスマスを!

*1:他のファイル名にしたいときは-f=ファイル名をつける

Laravel を高速化というか最適化する

laravel

この記事は Laravelリファレンス発売記念!販売促進!! Advent Calendar 2015 - Adventar 12/5 分の記事です。

Laravel について「遅い」とか言われるたびに、「ちゃんと最適化してる?」って思ってたので良い機会なのでここらへんちゃんと書いておこうと思います。

まずは、アプリケーションのコードを一切変えないお手軽な方法から。

コードを修正しないお手軽な方法

optimize コマンド

これ、デプロイ時は必須です。やってくることは

注意点としては config/app.phpdebugtrue だと clear-compiled が走るだけで終了するので、本番時はちゃんと false を設定しよう。

route:cache コマンド

ルート定義をキャッシュします。実際何してるかというと、ルート定義をシリアライズして base64_encode したものを /bootstrap/cache/routes.php に出力しています。

注意点としては、routes.phpクロージャを書いている場合はシリアライズできなくてエラーになる。以下の様なルート定義はダメということです。

Route::get('home', function(){
    return view('home');
});

キャッシュしたければコントローラーを作ってルート定義しよう。

config:cache コマンド

設定ファイルをキャッシュします。実際何してるかというと、すべての設定値を var_export して /bootstrap/cache/config.php に出力しています。

これらのコマンドは使って困ることはないので、デプロイ時には必ず実行させましょう。

番外

これは Laravel に限らないのですが

とかね。早くなりますよ。PHP 7 はともかく OPcache は必ず有効にしましょう。

コードを変更して早くする方法

ここからはコードを少し変更して最適化を目指します。

不要なミドルウェアの削除

App\Http\Kernel クラスにはグローバルミドルウェアとして幾つかのミドルウェアがあらかじめ登録されています。使わないものを削除してしまいましょう。

  • CheckForMaintenanceMode
    • メンテナンスモードかどうかをチェックする。メンテナンスモードだったら 503 を返す。
  • EncryptCookies
    • クッキーの暗号化。
  • AddQueuedCookiesToResponse
    • クッキー使わなければいらない(APIサーバーとか)
  • StartSession
    • セッション使わなければいらない(APIサーバーとか)
  • ShareErrorsFromSession
    • セッションに errors という名前で登録された内容をすべてのビューで共有している
  • VerifyCsrfToken
    • CRSF チェック。

不要なサービスプロバイダ/ファサードを削除

Laravel は多機能なフレームワークなので、要件には必要のない機能もあると思います。必要のないものは config/app.php から削除してしまいましょう。

ファサードを使わない

必要なインスタンスファサードを経由するのではなく、コンストラクタメソッドの引数としてインジェクションしたり、コンテナから直接引っ張ってくればファサードは必要なくなります。config/app.phpaliases の配列をごっそり削除すれば初期処理は早くなります。

ここらへんは 12/15 に @ex_takezawa さんが詳しく解説してくれると思います。

利便性とトレードオフですが、難易度はさほど高くありません。

Eloquent を使わない

すべての処理を QueryBuilder に任せる方法です。Eloquent はマジックメソッドを多用しているので、使用しないことで若干のパフォーマンス上昇が望めると思います。 こちらはファサードを使わないよりも難易度が高くなると思います。Eloquent を使わないということは…

  • リレーション
  • Eagerローディング
  • マスアサインメント
  • 論理削除
  • クエリースコープ
  • モデルイベント
  • アクセサ / ミューテーター
  • シリアライズ

の機能が使えないということなので、慎重に検討する必要があります。僕はたぶん無理。

結論

そこまで頑張るんだったら Lumen 使おう。

まとめ

いろいろ最適化の手法を紹介しましたが、いかがでしたでしょうか? まぁ、うん、それでも満足できない場合は Go とか Java 使ったほうがいいと思います。

宣伝

よろしくお願いします!

www.amazon.co.jp

Laravel Socialite の独自ドライバを実装する

この記事は Laravelリファレンス発売記念!販売促進!! Advent Calendar 2015 - Adventar の3日目の記事です。

ちょうど1年前にこんな記事を書きました。

qiita.com

ドライバの独自実装

今書いています。ごめんなさい。更新したら通知するようにしますのでストックしてくれていいのよ?(チラチラ http://qiita.com/localdisk/items/2e2724f31864fd49b675

気がついたら一年経ってたよ…。というわけでドライバの実装をしてみたいと思います。現在 Socialite で実装されているドライバは

となります。一年前と比較すると LinkedIn と BItbucket が増えましたね。今回は折角なので はてなのOAuth ドライバを実装したいと思います。自分はてなーなので。

はてなの OAuth のバージョン

調べてみるとはてなの OAuth のバージョンは1のようです。Socialite だと一緒なのは Twitter と Bitbucket ですね。ソースコードを読んでみると2つクラスを作る必要があるようです。

ですね。まずは、app/Socialite ディレクトリを作成しましょう。

HatenaProvider

空でOK。

<?php

namespace App\Socialite;

use Laravel\Socialite\One\AbstractProvider;

class HatenaProvider extends AbstractProvider
{

}

親クラスの Laravel\Socialite\One\AbstractProvider ですが、abstract class なのに abstract method がない(困惑)のでこれでよいです。

HatenaServer

<?php

namespace App\Socialite;


use Laravel\Socialite\One\User;
use League\OAuth1\Client\Server\Server;
use League\OAuth1\Client\Credentials\TokenCredentials;

class HatenaServer extends Server
{
    /**
     * {@inheritDoc}
     */
    public function urlTemporaryCredentials()
    {
        $scopes = implode(',', config('services.hatena.scope'));

        return "https://www.hatena.com/oauth/initiate?scope={$scopes}";
    }

    /**
     * {@inheritDoc}
     */
    public function urlAuthorization()
    {
        return 'https://www.hatena.ne.jp/oauth/authorize';
    }

    /**
     * {@inheritDoc}
     */
    public function urlTokenCredentials()
    {
        return 'https://www.hatena.com/oauth/token';
    }

    /**
     * {@inheritDoc}
     */
    public function urlUserDetails()
    {
        return 'http://n.hatena.com/applications/my.json';
    }

    /**
     * {@inheritDoc}
     */
    public function userDetails($data, TokenCredentials $tokenCredentials)
    {
        $user = new User();

        $user->uid      = $data['url_name'];
        $user->nickname = $data['display_name'];
        $user->name     = $data['url_name'];
        $user->imageUrl = $data['profile_image_url'];
        $user->email    = '';

        $used = ['url_name', 'display_name', 'profile_image_url'];

        foreach ($data as $key => $value) {
            if (strpos($key, 'url') !== false) {
                if (!in_array($key, $used)) {
                    $used[] = $key;
                }

                $user->urls[$key] = $value;
            }
        }

        // Save all extra data
        $user->extra = array_diff_key($data, array_flip($used));

        return $user;
    }

    /**
     * {@inheritDoc}
     */
    public function userUid($data, TokenCredentials $tokenCredentials)
    {
        return $data['url_name'];
    }

    /**
     * {@inheritDoc}
     */
    public function userEmail($data, TokenCredentials $tokenCredentials)
    {
        return;
    }

    /**
     * {@inheritDoc}
     */
    public function userScreenName($data, TokenCredentials $tokenCredentials)
    {
        return $data['name'];
    }

}

メソッドの説明

urlTemporaryCredentials

Request token の取得。はてなの場合、ここが特殊で scope というパラメータ名で "承認を求める操作名" を渡す必要があります(複数の場合はカンマ区切りで渡す)。

  • read_public
  • write_public
  • read_private
  • write_private

この情報を渡すために今回は config/services.php に"承認を求める操作名"を定義しています。

<?php

return [
    'hatena' => [
        'client_id'     => 'XXX',
        'client_secret' => 'XXX',
        'redirect'      => 'http://localhost:8000/hatena/login',
        'scope'         => ['read_public', 'write_public']
    ],
];

urlAuthorization

リダイレクトする認証用URLを返します。はてなの場合は PC / スマホ / 携帯電話 用にそれぞれ違うURLが用意されているので真面目に作る場合はデバイス判定が必要です。

urlTokenCredentials

Access token を取得するURLを返します。

urlUserDetails

ユーザー情報を取得するURLを返します。

userDetails

ユーザー取得APIを叩いた結果をオブジェクトに詰めています。

userUid / userEmail / userScreenName

継承元のメソッドはこれらのメソッドをコールした時に通信してるので、そうしないようにオーバーライドしています。Socialite の実装を参考に書いただけはあんまり深い意味はないです。

AuthServiceProvider に登録

独自ドライバを実装したら使えるように登録します。AuthServiceProviderboot メソッドにこんな感じで。

<?php
class AuthServiceProvider extends ServiceProvider
    public function boot(GateContract $gate)
    {
        $this->registerPolicies($gate);

        \Socialite::extend('hatena', function($app) {
            $setting = $app['config']['services.hatena'];
            $config  = array_merge([
                'identifier'   => $setting['client_id'],
                'secret'       => $setting['client_secret'],
                'callback_uri' => $setting['redirect'],
            ], $setting);
            return new HatenaProvider($app['request'], new HatenaServer($config));
        });
    }
}

使ってみる。

<?php
// routes.php
// view にはこんな感じで書く

// <p><a href="{{ url('github/ahthorize') }}">github login</a></p>
// <p><a href="{{ url('hatena/ahthorize') }}">hatena login</a></p>


Route::get('{provider}/ahthorize', function ($provider) {
    return Socialite::with($provider)->redirect();
});

Route::get('{provider}/login', function ($provider) {
    /** @var \Laravel\Socialite\Contracts\User $data */
    $data           = Socialite::with($provider)->user();
    dd($data);
});

シンプル!

参考

Consumer key を取得して OAuth 開発をはじめよう - Hatena Developer Center

宣伝

よろしくおねがいします!

www.amazon.co.jp

リリース間近!5.2 の新機能と変更点

この記事は Laravelリファレンス発売記念!販売促進!! Advent Calendar 2015 - Adventar の 12/1 ぶんの記事です。

注意

長いので、ブックマークでもして後で読むといいのではと思います。せっかちな人のためにまずは結論から。

リリースはいつ頃?

まもなくでしょう。昨日(11/30) symfony 2.8 / 3.0 がリリースされました。この両バージョンはAPIの互換性があるようで、Laravelの各 composer.json には "symfony/http-kernel": "2.8.*|3.0.*", のように書かれています。

移行すべき?

5.1 のユーザーであれば特に必要を感じないかな…というのが僕の感想です。ただ、非推奨・削除されたクラス・メソッド・関数等がそれなりにあるのでキャッチアップしておかないと、バージョンアップで苦労しそうです。

試してみたい

https://github.com/laravel/laravel.gitgit clone して branch を develop に切り替えてください。その後に composer install すれば完了です。

新機能

さて、5.2 の新機能を紹介していきましょう。今回のバージョンアップでは破壊的なものはないので「バージョンあげたいが…ぐぬぬ…」となるようなこともないでしょう。

Implicit model binding

ルートを解決して処理を行う前にパラメータを精査してモデルを findOrFail あるいは find した状態でインジェクションする機能です。

<?php

// http://localhost:8000/test/1
Route::get('test/{user}', function(\App\User $user) {
    // find された値が入っている
    dd($user);
});

// http://localhost:8000/users/1
Route::get('users/{user}', 'UserController@index');

注意点としては、ルートパラメーターの名前をモデルの名前と合わせる。test/{user} の部分ですね。もうひとつは引数にデフォルト値をつけないと findOrFail が実行されるということです。モデルが見つからない場合でも例外を起こしたくない場合は

<?php

// http://localhost:8000/test/1
Route::get('test/{user}', function(\App\User $user = null) {
    // find された値が入っている
    dd($user);
});

のように引数にデフォルト値をつける必要があります。

Appending output from scheduled tasks

スケジュールの出力を任意のファイルに出せるようになりました。これ 5.2 の新機能として紹介されていますが 5.1 にも入ってます。

Collections Wildcards

Collection でワイルドカードが使えるようになりました。Eloquent 等でリレーションを使うときに便利だと思います。

[5.2] Add support for nested indexed arrays to array_pluck and data_get by JosephSilber · Pull Request #10709 · laravel/framework · GitHub

使い方としてはテストコードが参考になるかと思います。ここらへんとか

Form Array Validation

上記Collections Wildcardsが入ったのもあって Validation で配列を使用する例が楽になっています。

Database Session Driver

データベースにセッションを保存するときのテーブルに user_id, ip_address, user_agent の項目が増えました。互換性を保つために lagacy_database というドライバが増えています。このドライバは5.2で非推奨となっており、おそらく 5.3 で削除されるでしょう。

新機能はざっくりと以上です。次は変更点を。長いです

削除されたもの

5.1 で非推奨になったものが削除されました

非推奨

  • Strクラスの randomBytes メソッドが非推奨に
    • php7 の random_bytes を視野に?
    • 5.3 は php7 か?
  • Route::controller / Route::controllers が非推奨(5.3で削除)
  • Collection の lists メソッドが非推奨に
  • array_build が非推奨

小さな変更

  • Facade クラスの getFacadeAccessor が abstract メソッド
  • Seeder クラスの run メソッドが abstract メソッド
  • guzzlehttp/guzzle ~6.0
  • php7 の Throwable サポート
  • validateSame/validateDifferent が型までチェックするようになった

現場からは以上です。

宣伝

一番大事なこと忘れてた…

www.amazon.co.jp

発売されます!よろしくおねがいします!

他のフレームワークでも使える Laravel-Elixir

laravel

今日の記事は www.adventar.org のフライングです。12/2 分になります。

rails-assets サポート終了?

先日 Rails 界隈このような話題がTLを賑やかせていました。 github.com

僕自身はPHPerなので横目で見ていたのですが「Laravel-Elixir便利なので、他のフレームワーク使いの人にもおすすめしたいなぁ」と思いたち、来月の Advent Calendar をフライングしている次第。

Laravel-Elixir とは

gulp のタスク群を使いやすくまとめたものと思ってくださって結構です。Laravel という PHP フレームワークの1ツールとして作られているので初期設定はLaravelに最適化されていますが、変更可能(後述)なのでRailsや他のフレームワークにも適用できると思います。

Laravel-Elixir で何ができるのか?

いわゆる asset 管理と言われるものはたいていできます。

欲しいものは大体揃ってるんじゃないかなと思います。あとはテスト支援としてテストファイルを監視して

の実行が可能です。

Laravel-Elixir のインストール

インストールする前に Node.js と Gulp のインストールを済ませておいてください。PHP は必要ないです。

僕は以下の環境で動かしています

$ node -v
v5.1.0
$ npm -v
3.3.12

多分 node のバージョンは ver.4 でも動くと思います。

以下のような package.json を用意してください。

{
  "private": true,
  "devDependencies": {
    "gulp": "^3.8.8"
  },
  "dependencies": {
    "laravel-elixir": "^3.0.0"
  }
}

で、

$ npm install

ちょっと時間がかかる(5分程度)ので作業の合間にやっておくのがおすすめです。

ディレクトリ構成

ディレクトリ構成はこんな感じ。ディレクトリはだいたい変更可能。

project
 ├── gulpfile.js   // Laravel-Elixir でやりたいことを書く
 ├── node_modules  // いろいろはいってる
 ├── package.json   
 ├── public
 │   ├── build  // バージョン指定した場合の出力先
 │        ├── css
 │        └── js
 │   ├── css   // CSS の出力先
 │   └── js    // JavaScript の出力先
 ├── resources
     └── assets
         ├── coffee  // CoffeeScript 書くところ
         ├── css     // CSS 書くところ
         └── js      // Javascript 書くところ
         ├── less    // LESS 書くところ
         ├── sass    // Sass 書くところ

使ってみる

では、使ってみましょう。まず resources/assets/sassapp.scss というファイルを作って CSS を書きます。それから gulpfile.js

var elixir = require('laravel-elixir');

elixir(function(mix) {
    mix.sass('app.scss');
});

と書いて gulp コマンドを打つと…

➜  laravel-elixir  gulp
[20:24:46] Using gulpfile ~/Projects/laravel-elixir/gulpfile.js
[20:24:46] Starting 'default'...
[20:24:46] Starting 'sass'...

Fetching Sass Source Files...
   - resources/assets/sass/app.scss


Saving To...
   - public/css/app.css

[20:24:46] Finished 'default' after 344 ms
[20:24:47] gulp-notify: [Laravel Elixir] Sass Compiled!
[20:24:47] Finished 'sass' after 474 ms

簡単ですね。ちなみに gulp watch しておくと、ファイル監視してくれるので保存されるタイミングでコンパイルが走ります。便利。Minify したい場合は gulp --production とすれば Minify されます。デプロイする際はこのオプションを付けておきたいですね。

バージョン(フィンガープリンティング)

あとはバージョンについて触れてみます。先ほどの gulpfile.js を以下のように編集してみましょう。

var elixir = require('laravel-elixir');

elixir(function(mix) {
    mix.sass('app.scss')
       .version('css/app.css'); // ここを追加
});

すると…

➜ laravel-elixir  gulp
[20:35:20] Using gulpfile ~/NetBeansProjects/laravel-elixir/gulpfile.js
[20:35:20] Starting 'default'...
[20:35:20] Starting 'sass'...

Fetching Sass Source Files...
   - resources/assets/sass/app.scss


Saving To...
   - public/css/app.css

[20:35:20] Finished 'default' after 340 ms
[20:35:20] gulp-notify: [Laravel Elixir] Sass Compiled!
[20:35:20] Finished 'sass' after 474 ms
[20:35:20] Starting 'version'...

Fetching Version Source Files...
   - public/css/app.css


Saving To...
   - public/build

[20:35:20] Finished 'version' after 52 ms

version というタスクが実行されました。この結果 public/build/cssapp-6ac487d735.css というファイルが出力されます。app- から先の乱数の部分は実行するたびに変化します。で、ここからが肝ですが version タスク実行時、public/buildrev-manifest.json というファイルが出力されます。このファイルを見てみると…

{
  "css/app.css": "css/app-6ac487d735.css"
}

となっています。このファイルを読み込んで HTMLlink 要素や script 要素を書けばよいわけですね。PHPの人は Illuminate/Foundation/helpers.phpelixir 関数をパクっちゃえばおk。他の言語の人はヘルパーメソッドを作ればいけるはずです。

<?php
if (! function_exists('elixir')) {
    /**
     * Get the path to a versioned Elixir file.
     *
     * @param  string  $file
     * @return string
     *
     * @throws \InvalidArgumentException
     */
    function elixir($file)
    {
        static $manifest = null;

        if (is_null($manifest)) {
            $manifest = json_decode(file_get_contents(public_path('build/rev-manifest.json')), true);
        }

        if (isset($manifest[$file])) {
            return '/build/'.$manifest[$file];
        }

        throw new InvalidArgumentException("File {$file} not defined in asset manifest.");
    }
}

framework/helpers.php at 5.1 · laravel/framework · GitHub

設定の変更

他のフレームワークを使っている人はこのディレクトリ構成がきっと合わないと思います。Laravel-Elixir はディレクトリの設定を設定ファイルに外出ししてるので自由に変更することができます。設定値は node_modules/laravel-elixir/Config.js にあります。この設定を gulpfile.js で上書きしてやると良い感じになります。とりあえずディレクトリ周りだけ、抜き出しておきます。

設定 初期値
elixir.config.assetsPath resources/assets
elixir.config.publicPath public
elixir.config.appPath app
elixir.config.css.folder css
elixir.config.css.outputFolder css
elixir.config.sass.folder sass
elixir.config.less.folder less
elixir.config.js.folder js
elixir.config.js.outputFolder js
elixir.config.coffee.folder coffee
elixir.config.versioning.buildFolder build

多分ですが、Rails だとこんな感じ?(全然自信ない)

var elixir = require('laravel-elixir');

// 設定値を上書き
elixir.config.assetsPath = 'app/assets/';
elixir.config.js.folder  = 'javascripts'

elixir(function(mix) {
    mix.sass('app.scss')
       .babel('app.js');
});

最後に

いかがでしたでしょうか? 僕が好んで使っている Laravel-Elixir の魅力が他の人に少しでも伝われば幸いです。他の機能は Laravel Elixir 5.1 Laravel を見てください。いろいろできますよ。メソッドチェインでさらさら書けるのはやはりよいものです。

最後に自分が使ってる gulpfile.js を例に出しておきます。

var elixir = require('laravel-elixir');

elixir(function(mix) {
    mix.sass('app.scss')
        .browserify('app.js')
        .copy(
        'node_modules/font-awesome/fonts',
        'public/build/fonts'
        ).version(['css/app.css', 'js/app.js']);
        .browserSync({proxy: 'works.dev'});
});

こんな感じ。やってることを軽く説明すると

  • resources/assets/sass/app.scss を sass コンパイル
  • resources/assets/js/app.js を browserify. この時 babelifypartialify も走ってるっぽい
  • font-awesome の font ファイル一式を public/build/fonts にコピー
  • public/css/app.csspublic/js/app.js をバージョン化
  • 最後に BrowserSync*1

参考

宣伝

年明けに Laravel の本が出ます。LTS である 5.1 を対象にして書いています。とても良い本に仕上がってると思います。よろしくお願いします。

www.amazon.co.jp

で、この本の出版記念というか販促も兼ねてと言うか 12/2 19:30 から Fukuoka.php Vol.16 で喋らせて頂きます。内容としては、出版間近の本の内容とリリース間近っぽい 5.2 の新機能の解説をします。こちらもよろしくお願いします

*1:実は最近使ってなかったり…。待ちきれずF5押してしまう

Lumen の設定を上書きする方法

laravel lumen

こういう時は .env を…。あれ…ない。では、config ディレクトリ…ない。

まぁ答えは Configuration にあります。Lumen の設定はデフォルトでは vendor/laravel/lumen-framework/config にあります。今回の場合は database.php ですね。大体の場合は .env に書けばいいのですが*1今回の例のように .env では上書きが不可能なときはプロジェクトのルートに config ディレクトリを作成し vendor/laravel/lumen-framework/config/database.php をコピーして変更したい部分を修正すれば OK です。

以上 Laravel(Lumenも) 答えるマンでした。Laravel 答えるマンは Laravel/Lumen に関する質問を随時お待ちしております。

*1:bootstrap/app.php の Dotenv::load(DIR.'/../'); のコメントを外すのを忘れないように。僕はしょっちゅう忘れてます。てかこれはデフォルトで外れててほしい。

Laravel 本がでますよ

明けましておめでとうございます。今年もよろしくお願いします。

…半年くらいブログ書いてないんですね。どうなってるんだ。

それはともかくとして、今年はじめから一生懸命書いていた Laravel 本が 4/21 に出版されます!

Laravelエキスパート養成読本[モダンな開発を実現するPHPフレームワーク!] (Software Design plus)

Laravelエキスパート養成読本[モダンな開発を実現するPHPフレームワーク!] (Software Design plus)

Laravel エキスパート養成読本というタイトルですが、対象者は初〜中級者でしょうか。怖くないので買ってください。

目次はこんな感じです。

Chapter1. Laravel をはじめよう
Chapter2. MVC モデルが基礎からわかる
Chapter3. IoC コンテナ、ファサード、サービスプロバイダ、Eloquent
Chapter4. Laravel 5 新機能紹介!
Special. PHP フレームワーク最新事情
Chapter5. 実践!REST API アプリケーション

僕は、Chapter3 を担当しました。Laravel を始めた人がハマりがちであったりピンと来ない箇所である IoCコンテナ*1やサービスプロバイダ、ファサードについてと Eloquent について解説させていただきました。

本を書くのは初めてだったのですが、ブログ書くのと違って本書くのは大変だなぁと思いました。楽しかったのですが、仕事が忙しかったのもあってヒィヒィいってました。編集を担当して下さった @ghtakaya さんにはご迷惑をお掛けしました…。

内容としては Laravel4 を中心に Laravel 5 での変更点を付記してあるという感じです。

Laravel 5 については Chapter4 で一章割いているのでそちらでキャッチアップできるかと思います。@ex_takezawa さん担当なのでバッチリだと思います。

とうわけでよろしくお願いします。予約も始まってますよ!あと、電子書籍も出るみたいです。

追記(2015/04/30)

正誤表が出来ました。こちらのレビューが甘くて申し訳ないです…。

あと電子版も発売されました!まだの方はぜひ!

Laravelエキスパート養成読本[モダンな開発を実現するPHPフレームワーク!]:書籍案内|技術評論社

*1:Laravel5 からサービスコンテナに名前が変わりました