こんにちは、hacktkです。
今回はLaravelでCDNを使うときの小技を書こうと思います。
※ LaravelからCDNにファイルを置くとかではなく、URL使い分けの話です。
背景
CDNを使う場合、サイトのドメインと異なるドメインを使うかと思います。
例1:ドメインの使い分け
サイトのドメイン | CDNのドメイン |
---|---|
www.example.com | cdn.example.com |
しかしLaravelのassetヘルパーはこのドメイン部分を変更できません。
お手軽にやりたいだけなのに・・・。
解決策は用意されている
とりあえずassetヘルパーの実装を見てみると、こうなっています。
vendor/laravel/framework/src/Illuminate/Foundation/helpers.php
<?php if (! function_exists('asset')) { /** * Generate an asset path for the application. * * @param string $path * @param bool $secure * @return string */ function asset($path, $secure = null) { return app('url')->asset($path, $secure); } }
他のヘルパー関数と同様に、シンプルな処理です。
ではURLファサードのassetメソッドはというと、こうです。
vendor/laravel/framework/src/Illuminate/Routing/UrlGenerator.php
<?php /** * Generate the URL to an application asset. * * @param string $path * @param bool|null $secure * @return string */ public function asset($path, $secure = null) { if ($this->isValidUrl($path)) { return $path; } // Once we get the root URL, we will check to see if it contains an index.php // file in the paths. If it does, we will remove it since it is not needed // for asset paths, but only for routes to endpoints in the application. $root = $this->getRootUrl($this->getScheme($secure)); return $this->removeIndex($root).'/'.trim($path, '/'); }
コメントに書いてある通り、 getRootUrl
メソッドでroot URLが取得されています。
このgetRootUrlメソッド、実は仮引数が1つではありません。
vendor/laravel/framework/src/Illuminate/Routing/UrlGenerator.php
<?php /** * Get the base URL for the request. * * @param string $scheme * @param string $root * @return string */ protected function getRootUrl($scheme, $root = null) { if (is_null($root)) { if (is_null($this->cachedRoot)) { $this->cachedRoot = $this->forcedRoot ?: $this->request->root(); } $root = $this->cachedRoot; } $start = Str::startsWith($root, 'http://') ? 'http://' : 'https://'; return preg_replace('~'.$start.'~', $scheme, $root, 1); }
はい、どうやら第2引数の $root
に任意の文字列を渡せば、それが使われそうですね。
そしてその用途を想定した assetFrom
というメソッドがちゃんと用意されています。
vendor/laravel/framework/src/Illuminate/Routing/UrlGenerator.php
<?php /** * Generate the URL to an asset from a custom root domain such as CDN, etc. * * @param string $root * @param string $path * @param bool|null $secure * @return string */ public function assetFrom($root, $path, $secure = null) { // Once we get the root URL, we will check to see if it contains an index.php // file in the paths. If it does, we will remove it since it is not needed // for asset paths, but only for routes to endpoints in the application. $root = $this->getRootUrl($this->getScheme($secure), $root); return $this->removeIndex($root).'/'.trim($path, '/'); }
これを使ったヘルパー関数でも実装すれば良さそうですね。
ちなみに、このassetFromメソッドは5.1で追加されたもののようです。 github.com
余談:ヘルパーの追加
Laravelのプロジェクトにヘルパー関数を追加する時ってみなさんどうやっているのでしょう?
私は app/Helpers/helpers.php
に実装を置いて、composer.jsonで読み込ませました。
app/Helpers/helpers.php
<?php if (! function_exists('cdn')) { /** * CDNのURLを生成する * * @param string $path * @param bool $secure * @return string */ function cdn($path, $secure = null) { $root = config('project.cdn_url'); // 環境ごとのCDNパスを指定 return app('url')->assetFrom($root, $path, $secure); } }
composer.json
"autoload": { "classmap": [ "database" ], "files": [ "app/Helpers/helpers.php" ], "psr-4": { "App\\": "app/" } },
他に良い方法があればぜひ知りたいです。
余談2
webエンジニア募集中です!