- 投稿日:2019-11-29T21:06:20+09:00
【Laravel】独自のDB用クエリ関数を実装する
この記事でやりたいこと
こんな独自のクエリ関数を実装する手順です。
\DB::canConnection(); //(1) \Schema::getColumnDefinitions('user'); //(2) User::getColumnDefinitions(); //(3) \DB::table('user')->getColumnDefinitions(); //(4)はじめに
以下のような関数は、Laravelですでに用意されています。
\DB::statement('drop table users'); \Schema::hasTable('testTable');上記のような形式の、独自の関数を追加する方法です。
実装方法
それでは早速実装してみましょう。
なお、「この記事で書きたいこと」で書いた(1)~(4)の関数ですが、厄介なことに定義する場所は、それぞれ異なります。その点を考慮しておいてください。今回作成するコードのフォルダ構成は、以下のようになります。
ServiceProvider.php
Database/
├ MySqlConnection.php
├ Eloquent/
│ └ MySqlBuilder.php
├ Query/
│ ├ MySqlBuilder.php
│ ├ Grammars
│ │ └ MySqlGrammar.php
│ └ Processors
│ └ MySqlGrammar.php
└ Schema/
├ MySqlBuilder.php
└ Grammars
└ MySqlGrammar.php
Model/
└ CustomBuilderTrait.php※今回はMySQL前提で作成していきます。MySQL以外のデータベースを使用したい場合、複数のクラスを作成してください。
※今回の例では、以下の3つの関数を作成します。
- データベースに接続できるかを判定する関数「canConnection」
- データベースのバージョンを取得する関数「getVersion」
- 指定のテーブルの列の定義を一覧取得する関数「getColumnDefinitions」
実装
- ServiceProviderに、独自のMySqlConnectionを呼び出すための処理を追加します。
<?php namespace CustomBuilder; use Illuminate\Support\ServiceProvider; use Illuminate\Database\Connection; class CustomBuilderServiceProvider extends ServiceProvider { /** * Bootstrap the application services. * * @return void */ public function boot() { // 追加 Connection::resolverFor('mysql', function (...$parameters) { return new Database\MySqlConnection(...$parameters); }); } /** * Register the application services. * * @return void */ public function register() { // } }
- Database\MySqlConnectionを作成します。
この関数では、継承した「MySqlGrammar」などの定義、ならびに「\DB::XXXXXX」形式で呼び出す関数の定義を行います。<?php namespace CustomBuilder\Database; use CustomBuilder\Database\Query\Grammars\MySqlGrammar as QueryGrammar; use CustomBuilder\Database\Schema\Grammars\MySqlGrammar as SchemaGrammar; use CustomBuilder\Database\Schema\MySqlBuilder; use CustomBuilder\Database\Query\MySqlBuilder as QueryBuilder; use CustomBuilder\Database\Eloquent\MySqlBuilder as EloquentBuilder; use CustomBuilder\Database\Query\Processors\MySqlProcessor; use Illuminate\Database\MySqlConnection as BaseConnection; class MySqlConnection extends BaseConnection { /** * Get a schema builder instance for the connection. * * @return Builder */ public function getSchemaBuilder() { if (is_null($this->schemaGrammar)) { $this->useDefaultSchemaGrammar(); } return new MySqlBuilder($this); } /** * Get the default schema grammar instance. * * @return MySqlGrammar */ protected function getDefaultSchemaGrammar() { return $this->withTablePrefix(new SchemaGrammar); } /** * Get the default query grammar instance. * * @return QueryGrammar */ protected function getDefaultQueryGrammar() { return $this->withTablePrefix(new QueryGrammar); } /** * Get the default post processor instance. * * @return MySqlProcessor */ protected function getDefaultPostProcessor() { return new MySqlProcessor; } /** * Get a new query builder instance. * * @return \Illuminate\Database\Query\Builder */ public function query() { return new QueryBuilder( $this, $this->getQueryGrammar(), $this->getPostProcessor() ); } /** * Get a new eloquent query builder instance. * * @return \Illuminate\Database\Eloquent\Builder */ public function eloquentBuilder($query) { return new EloquentBuilder($query); } // \DB::XXXXXX()関数はここで記載 ------------------------------------------- public function canConnection() { try { $this->getSchemaBuilder()->getTableListing(); return true; } catch (\Exception $ex) { return false; } } /** * Get database version. * * @return void */ public function getVersion() { return $this->getSchemaBuilder()->getVersion(); } }
- Database\Schema\MySqlBuilderを作成します。
このクラスに、\Schema::XXXXXX()で呼び出す関数の定義を行います。<?php namespace CustomBuilder\Database\Schema; use Illuminate\Database\Schema\MySqlBuilder as BaseBuilder; class MySqlBuilder extends BaseBuilder { // \Schema::XXXXXX()関数の形式 ------------------------------------------- /** * Get database version. * * @return void */ public function getVersion() { $results = $this->connection->selectFromWriteConnection($this->grammar->compileGetVersion()); return $this->connection->getPostProcessor()->processGetVersion($results); } /** * Get the table listing * * @return array */ public function getTableListing() { $results = $this->connection->selectFromWriteConnection($this->grammar->compileGetTableListing()); return $this->connection->getPostProcessor()->processTableListing($results); } /** * Get column difinitions * * @return array */ public function getColumnDefinitions($table) { $baseTable = $table; $table = $this->connection->getTablePrefix().$table; $results = $this->connection->selectFromWriteConnection($this->grammar->compileColumnDefinitions($table)); return $this->connection->getPostProcessor()->processColumnDefinitions($baseTable, $results); } }
- Database\Schema\Grammars\MySqlGrammarを作成します。
このクラスで、主に独自クラスで実行するSQLを定義します。<?php namespace CustomBuilder\Database\Schema\Grammars; use Illuminate\Database\Schema\Grammars\MySqlGrammar as BaseGrammar; class MySqlGrammar extends BaseGrammar { /** * Compile the query to get version * * @return string */ public function compileGetVersion() { return "select version()"; } /** * Compile the query to show tables * * @return string */ public function compileGetTableListing() { return "show tables"; } /** * Compile the query to get column difinitions * * @return string */ public function compileColumnDefinitions($tableName) { return "show columns from {$this->wrapTable($tableName)}"; } }
- Database\Schema\Grammars\MySqlGrammarを作成します。
このクラスで、主に独自クラスで実行するSQLを定義します。<?php namespace CustomBuilder\Database\Schema\Grammars; use Illuminate\Database\Schema\Grammars\MySqlGrammar as BaseGrammar; class MySqlGrammar extends BaseGrammar { /** * Compile the query to get version * * @return string */ public function compileGetVersion() { return "select version()"; } /** * Compile the query to show tables * * @return string */ public function compileGetTableListing() { return "show tables"; } /** * Compile the query to get column difinitions * * @return string */ public function compileColumnDefinitions($tableName) { return "show columns from {$this->wrapTable($tableName)}"; } }
- Database\Query\Processors\MySqlProcessorを作成します。
このクラスで、SQLを実行して取得した結果を、配列やCollectionに加工するなどを行います。
また、このクラス内の関数によって、各データベース種類(MySQL、SQL Serverなど)によって列名などが異なるものを、すべて揃える目的があります。<?php namespace CustomBuilder\Database\Query\Processors; use Illuminate\Database\Query\Processors\MySqlProcessor as BaseMySqlProcessor; class MySqlProcessor extends BaseMySqlProcessor { /** * Process the results of a get version. * * @param array $results * @return array */ public function processGetVersion($results) { $versionArray = $this->versionAray($results); return $versionArray[0]; } protected function versionAray($results) { $version = collect(collect($results)->first())->first(); return explode('-', $version); } /** * Process the results of a table listing query. * * @param array $results * @return array */ public function processTableListing($results) { return array_map(function ($result) { return collect((object) $result)->first(); }, $results); } /** * Process the results of a Column Definitions query. * * @param array $results * @return array */ public function processColumnDefinitions($tableName, $results) { return collect($results)->map(function ($result) use ($tableName) { return [ 'table_name' => $tableName, 'column_name' => $result->Field, 'type' => $result->Type, 'nullable' => boolval($result->Null), 'virtual' => strtoupper($result->Extra) == 'VIRTUAL GENERATED', ]; })->toArray(); } }
- Database\Query\MySqlBuilderを作成します。
このクラスに、\DB::table('user')::XXXXXX()で呼び出す関数の定義を行います。<?php namespace CustomBuilder\Database\Query; use Illuminate\Database\Query\Builder as BaseBuilder; class MySqlBuilder extends BaseBuilder { // \DB::table('user')::XXXXXX()関数の形式 ------------------------------------------- /** * Get column difinitions * * @return array */ public function getColumnDefinitions() { $results = $this->connection->selectFromWriteConnection($this->grammar->compileColumnDefinitions($this->from)); return $this->connection->getPostProcessor()->processColumnDefinitions($this->from, $results); } }
- また、\Database\Query\Grammars\MySqlGrammarで、上記のDatabase\Query\MySqlBuilderで呼び出すGrammerを作成します。
(\Database\Schema\Grammars\MySqlGrammarとまとめられないかな?という思いもありつつ)<?php namespace CustomBuilder\Database\Query\Grammars; use Illuminate\Database\Query\Grammars\MySqlGrammar as BaseGrammar; class MySqlGrammar extends BaseGrammar { /** * Compile the query to get column difinitions * * @return string */ public function compileColumnDefinitions($tableName) { return "show columns from {$this->wrapTable($tableName)}"; } }
- Database\Eloquent\MySqlBuilderを作成します。
このクラスに、\User::XXXXXX()で呼び出す関数の定義を行います。<?php namespace CustomBuilder\Database\Eloquent; use Illuminate\Database\Eloquent\Builder as BaseBuilder; class MySqlBuilder extends BaseBuilder { // \User::XXXXXX()関数の形式 ------------------------------------------- /** * Get column difinitions * * @return array */ public function getColumnDefinitions() { $table = $this->model->getTable(); $connection = $this->query->connection; $results = $connection->selectFromWriteConnection($connection->getQueryGrammar()->compileColumnDefinitions($table)); return $connection->getPostProcessor()->processColumnDefinitions($table, $results); } }
- Model\CustomBuilderTraitを作成します。
このTraitでは、各Modelで独自のEloquent\Builder、Query\Builderを呼び出すために必要となります。<?php namespace CustomBuilder\Model; trait CustomBuilderTrait { /** * Get a new query builder instance for the connection. * * @return \Illuminate\Database\Query\Builder */ protected function newBaseQueryBuilder() { $connection = $this->getConnection(); return $connection->query(); } /** * Create a new Eloquent query builder for the model. * * @param \Illuminate\Database\Query\Builder $query * @return \Illuminate\Database\Eloquent\Builder|static */ public function newEloquentBuilder($query) { $connection = $this->getConnection(); return $connection->eloquentBuilder($query); } }独自関数を呼び出すModelで、このTraitをuseしてください。
<?php namespace App; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; use CustomBuilder\Model\CustomBuilderTrait; class User extends Authenticatable { use Notifiable; // 追加 use CustomBuilderTrait; // 略 }まとめ
以上です!
Helperクラス的な関数を作ってもいいですが、出来ればこのように、クエリビルダを拡張することを行いたいですよね。
その場合は是非、こちらのコードを使用してください!ちなみに今回のコードのGitHubはこちらです。
https://github.com/hirossyi73/custom-builder
- 投稿日:2019-11-29T16:52:15+09:00
Laravelでよく使うコマンドまとめ
Laravelを使っていてよくコマンドを使いますが、すぐ忘れてしまうので、
まとめておきます。Laravelでよく使うコマンド集
Laravelの作成 composer create-project laravel/laravel qiita --prefer-dist "6.0.*" //バージョン指定可 ローカルサーバ起動 php artisan serve --host 192.168.33.10:8000 コントローラー作成 php artisan make:controller ShowProfile モデル作成 php artisan make:model Flight php artisan make:model Flight --migration //マイグレーションファイル付 テスト作成 php artisan make:test UserTest php artisan make:test UserTest --unit //ユニットテスト テスト実行 ./vendor/bin/phpunit マイグレーションファイル作成 php artisan make:migration add_votes_to_users_table --table=users //テーブル名指定 マイグレート実行 php artisan migarate php artisan migrate:refresh //全てをリセットしてから実行する マイグレートを戻す php artisan migrate:rollback //最後の一回分 php artisan migrate:rollback --step=1 //戻す数を指定する場合 php artisan migrate:reset //全てをリセット シーダー作成 php artisan make:seeder UsersTableSeeder シーダー実行 composer dump-autoload //シーダー実行前に流す php artisan db:seed php artisan db:seed --class=UsersTableSeeder //個別にシーダーを実行したい場合 ファクトリの作成 php artisan make:factory PostFactory キャッシュクリア php artisan config:clear フォームリクエスト作成 php artisan make:request PostRequest 認証(一括作成) php artisan make:auth以上です。
随時追加していきます。
- 投稿日:2019-11-29T16:22:36+09:00
Laravel-Excelで複数行のヘッダーを無視したい
Laravel-Excelで複数行のヘッダーを無視したい時
ドキュメントをみたけれど、書いてなかったので、Issueに書いてあったことを記録しておきます。
例えば、ヘッダー行(1行目)を飛ばすのはオプションでありそうですが、複数行目(例:6行目からデータ行が始まっているので、)飛ばしたい場合、いかのように書いてやればいいです。
WithStartRow
を使用します。use Maatwebsite\Excel\Concerns\WithStartRow; class UsersImport implements ToModel, WithStartRow { /** * @return int */ public function startRow(): int { return 6; } }
- 投稿日:2019-11-29T12:39:18+09:00
入力フォームの実装で結構苦労した話
自己紹介
職業プログラマ歴約半年、PHP歴約半年、Laravelの存在は入社直前に知った、ひよっこプログラマです。Qiitaへの投稿はこれが初めてです。暖かい目で見てただければ幸いです。
背景
会社のサービスで使うフレームワークをLaravelにするということで、とある入力フォームの移植をすることになった。「項目数も少ないしそんなに時間かからないだろう」と思いながらやっていたところ、意外と厄介なことに気づいて、最終的に色々な手法を組み合わせて無理やり仕上げることになった。
この記事はそのダイジェスト版である。(実際のところもっと苦戦したり頓珍漢な実装になりかけたりしている)仕様
- DB
- tableX:ユーザーアカウントと一対一関係にあるが、存在しないことがある
- 入力ページ
- ユーザーアカウントでログインしている時のみアクセスできる = アクセスされる時、アクセス者に対応するユーザーアカウントが必ず存在している
- ユーザーアカウントに紐づくtableXの情報が存在していれば規定値が入力されたフォームを表示する
- ユーザーアカウントに紐づくtableXの情報が存在しなければ空のフォームを表示する
- 確認ページに向かうボタンがある
- 確認ページから戻ってきた際入力値が保持されている
- 確認ページ
- 入力ページのフォームの内容が表示される
- 入力ページに戻るボタン・内容を確定するボタンがある
<input type="hidden">
で内容を保持するのは禁止(改竄対策などの為)どう実装したか
tableXの情報を取得する
まずは以下のような感じに書いた。(ルーティングやミドルウェアについては省略)
App\User.php// ... public function tableX(): HasOne { return $this->hasOne('App\TableX', 'userno') } // ...App\Http\Controllers\SomeformController.phpClass SomeformController extends Controller { public function edit() { $tableX = Auth::user()->tableX(); return view('someform.edit', ['tableX' => $tableX]); } }resources\views\someform\edit.blade.php{{-- ... --}} <form method="..." action="..."> @csrf <div> <h4>項目A</h4> <input name="item_a" value="{{ $tableX->item_a }}" /> </div> {{-- ... --}} <input type="submit" name="confirm" value="確認する" /> </form> {{-- ... --}}このように実装した結果……
ErrorException (E_ERROR) Trying to get property 'item_a' of non-object無事
原因は上にも書いた…が、存在しないこともある
である。次のように書き換えて解消した。resources\views\someform\edit.blade.php{{-- ... --}} <input name="item_a" value="{{ $tableX->item_a ?? '' }}"/> {{-- ... --}}な時
$tableX
はnull
で、通常の箇所で$tableX->item_a
と書くとTrying to get property 'b' of non-object
と出てくるところだが、null合体演算子??
の左辺に書いた場合はisset
の時のように上手く処理してくれるようだった。確認画面に入力値を表示させる
かなり苦戦した覚えがあるが、最終的に次のように書いたところ動作するようになった。
App\Http\Controllers\SomeformController.php// ... public function confirm(Request $request) { $request->flash(); return view('someform.confirm'); } // ...resources\views\someform\confirm.blade.php<div> <div> <h4>項目A</h4> <div>{{ old('item_a') }}</div> </div> {{-- ... --}} <form method="..." action="..."> @csrf <input type="submit" name="submit" value="保存"/> </form> <form method="..." action="..."> <input type="submit" name="back" value="戻る"> </form> </div>
old()
と$request->flash()
の使い方を何となく理解できたようなできていないような……。確認画面から戻った時に入力値がクリアされないようにする
ここまでのコードだと、戻るボタンを押した時に入力値がリセットされてしまう
ここも最適解を見つけるまでに結構な時間が掛かったような覚えがあるが、最終的に次のように書くことで解決できた。resources\views\someform\edit.blade.php{{-- ... --}} <input name="item_a" value="{{ old('item_a', $tableX->item_a ?? '') }}"/> {{-- ... --}}保存処理を実装する
ここまで書いてしまえばあとは保存処理を実装するだけ、楽勝!
App\Http\Controllers\SomeformController.php// ... public function submit() { $tableX = Auth::user()->tableX; $tableX->fill(old())->save(); return redirect('...'); } // ...Symfony \ Component \ Debug \ Exception \ FatalThrowableError (E_ERROR) Call to a member function fill() on null
原因は最初にも出てきた
…が、存在しないこともある
だった。
最終的に次のように書いて解決した。App\Http\Controllers\SomeformController.php// ... public function submit() { $tableX = TableX::firstOrNew(['userno' => Auth::user()->id]); $tableX->fill(old())->save(); return redirect('...'); } // ...「
TableX
テーブルとUser
テーブルは関連付いているからUser
モデルのオブジェクトからTableX
オブジェクトを……」という考えに固執していると無意味に複雑なコードになってしまう。(実際なってしまっていた。)おわりに
本文中にもある通り、完成までにかなり苦戦しました。完成に至るまでに無意味に複雑で長いコードになって、「Laravelは厄介だ」と思うこともありました。しかし記事に起こしていると、
firstOrNew
関数など、煩雑な記述を解消する為のツールがLaravelによって既に用意されていることも分かってきました。そういったツールを使いこなせるよう、これからも勉強していきたい次第です。ここまでお読みくださり、ありがとうございました。
- 投稿日:2019-11-29T12:14:34+09:00
Laravel & Guzzle httpdで500 Internal Server Errorの解決に手間取った
Laravelで実装している際、某社のAPIへリクエストして500エラーが発生し、解決に時間がかかったことがありました。
最終的に、API開発元に確認しHeaderにAcceptがないのが原因だと判明したのですが、なぜこれが原因だったのか、いまだに謎です。下記のようなコードで送っています。
$paramater = [ 'http_errors' => true, // 40X・50X系のエラーをExceptionにしない 'headers' => [ 'Accept' => 'application/json', 'Authorization' => 'Bearer ' . \Config('authorization'), ], ]; $client = new Client(); $response = $client->request('GET', 'https://xxxxx', $paramater);同社の別APIに対してはAcceptなしで送れて、このAPIだけエラーなのでハマりました。
レスポンスする時にAcceptなしをブロックしているなら500にならないだろうし、必須のヘッダーなら他のリクエストでも同様のエラーが出るはずだし・・・
- 投稿日:2019-11-29T11:48:57+09:00
Laravel6.x移行でハマった話
Illuminate\Support\Facades\LangのLang::getFromJsonが6.x移行で使えなくなってて
local.ERROR: Method Illuminate\Translation\Translator::getFromJson does not exist.
などというエラーに見舞われてしまった
ググってもphp artisan view:clear php artisan view:cache
しろとしかヒットせず
自作のメールテンプレートで多言語処理を実装していた場合、これでは解決できないLaravel5とLaravel6にて
Illuminate\Translation\Translator.phpを見比べてみると確かにgetFromJsonメソッドがなくなっており
getFromJsonを利用する側のIlluminate/Auth/Notifications/VerifyEmail.phpのtoMail()メソッド内の処理を見比べてみると-Lang::getFromJson() +Lang::get()と置き換わっており
このメソッド書き換えを行うと6.x(6.2環境で確認)で正しく動作した関連
Laravelで多言語対応いろいろ
https://qiita.com/shikigamix/items/d92ec72b4418f31c356d
- 投稿日:2019-11-29T11:05:27+09:00
Laravel Mixでwebpackを簡単に利用する」ってどういうこと?
はじめに
業務上活用しているLaravel Mixにてコンパイル関連で色々と模索していおり、
今更ですがLaravel Mixについて整理したことを備忘録としてまとめました。まず、Laravel Mix公式を見てみると
以下公式サイトhttps://readouble.com/laravel/5.5/ja/mix.html より引用
Laravel Mixは多くの一般的なCSSとJavaScriptのプリプロセッサを使用し、Laravelアプリケーションために、構築過程をWebpackでスラスラと定義できるAPIを提供しています。シンプルなメソッドチェーンを使用しているため、アセットパイプラインを流暢に定義できます。例を見てください。
mix.js('resources/assets/js/app.js', 'public/js') .sass('resources/assets/sass/app.scss', 'public/css');Webpackやアセットのコンパイルを始めようとして、混乱と圧倒を感じているならLaravel Mixを気に入ってもらえるでしょう。しかし、アプリケーションの開発時に必要だというわけではありません。どんなアセットパイプラインツールを使用してもかまいませんし、使わなくても良いのです。
なるほど、わからん。カタカナ語が使いたい年頃の人が書いた文書のようにになっていますが、ざっくり言うと「webpackというモジュールバンドラー(モジュールの束)を簡単に使えるようにしたラッパー」ということだと後になって理解しました。
以下でもうちょっとだけ詳しく見ていきます。
概要
①Laravel Mixとは、フロントエンドのアセット(JS,SASS等)をコンパイル、バンドルしてくれるツール
②webpack設定ファイルをより分かりやすく簡単に書けるように設定ファイルをラップしている
③lessやsass、babelなどよく使われるローダーが最初から用意されていて、デフォルトで利用することができる
⑤Laravelを使っていないアプリでも、コンパイル・バインディングのツールとして利用できる使い方
Laravelをインストールした段階で、package.jsonとwebpack.mix.jsが用意されています。
・package.json
⇒Laravel Mix本体やその他必要なパッケージが記述済み。
package.jsonのscriptsにはwebpackを実行するためのスクリプトも記述されている。・webpack.mix.js
⇒webpack設定ファイル(webpack.config.js)のラッパー。
ここにコンパイル対象ファイルやバンドル対象ファイルなどの設定を記述していく。※LaravelではないアプリでLaravel Mixを使う場合でも、
package.jsonとwebpack.mix.jsの2ファイルを用意するだけであとは同じです。
Laravel Mix公式サイトのStand-Alone Projectを参考に。↓
https://laravel-mix.com/docs/5.0/installation設定ファイルの記述
webpack.mix.jsに、設定を記述する。
sassファイルをコンパイルしたい場合
mix.sass('resources/assets/sass/app.scss', 'public/css');cssファイルをバンドルしたい場合
mix.styles([ 'public/css/vendor/normalize.css', 'public/css/vendor/videojs.css' ], 'public/css/all.css');jsをコンパイルしたい場合
mix.js('resources/assets/js/app.js', 'public/js');jsファイルをバンドルしたい場合
mix.scripts([ 'public/js/admin.js', 'public/js/dashboard.js' ], 'public/js/all.js');他にもいろいろ設定できることはある。
Laravel Mixの実行
npm run dev を実行すると、package.jsonに書いてあるスクリプトが実行され、
設定ファイルに記述したコンパイル、バンドルが実行される。npm run production の場合は圧縮されたファイルが出力される。
知っておくと良い機能抜粋
もう少し具体的な機能について、知っておいたほうがいい主な機能を抜粋。
jsのコンパイル
上記の通り、jsファイルをコンパイルするにはmix.js('resources/assets/js/app.js', 'public/js');
と書く。この処理では
・ES2015記法
・モジュール
・.vueファイルのコンパイル
・開発環境向けに圧縮
のコンパイルが実行される。①babel実行
jsファイルをバンドルする設定として、mix.scripts()を紹介したが、
この代わりにmix.babel()を使うことができる。これをすると、バンドルされたファイルはES5記法に変換された状態になる。
IEはES5までしか対応していないため、もしIEでも動作させる必要があるシステムの場合は
このmix.babel()機能を使ってES5記法に変換するほうが良い。②キャッシュバスティング
mix.js('resources/assets/js/app.js', 'public/js') .version();このように記述すると、
ファイル名の末尾に一意のハッシュ値が付与される。これによって、コンパイルのたびにファイル名が変更されるため、CSSやJSなどがブラウザキャッシュに残って変更が反映されないことを防止できる。
このファイルを読み込むbladeファイル側では、
のようにmix()関数を使うことで、ハッシュ値のついたファイル名でも取得することができる。おわりに
Laravel Mixにはオプションの指定で挙動を簡単に変えられるという特徴もあります。
そのあたりのカスタマイズについてのメモがたまってきたのでまた、整理していこうと思います。とりあえず、CSS側のコンパイルが極端に遅い方は
"processCssUrls: false"を試してみましょう。
(画像PASSの書き換えオプションをOFFにする。デフォルトはON。)例)
mix.sass('src/app.scss', 'dist/') .options({ processCssUrls: false });詳細はまた後ほどほどまとめます!
参考
https://readouble.com/laravel/5.5/ja/mix.html
https://laravel-mix.com/docs/5.0/quick-webpack-configuration
- 投稿日:2019-11-29T04:31:24+09:00
Laravel モデルファイル作成
マイグレーションファイルの作成後に、モデルファイルを作成する手順。
Modelとは
Laravelにおいて、データベースを操作する為の実行ファイル。データベースに関連づけて作成する。
artisanコマンドでモデルを作成
$ php artisan make:model モデル名
Laravelには命名規則があり、テーブル名(複数系)とモデル名(単数系)とする必要がある。
項目 名前 テーブル名 users モデル名 User このルールを守る事で、自動的にデータベースとモデル(実行ファイル)が紐づいてくれる。
実行結果
<?php namespace App; use Illuminate\Database\Eloquent\Model; class モデル名 extends Model { // }モデルが作成される場所
ディレクトリ名/app
appディレクトリ内に作成されるので確認
- 投稿日:2019-11-29T02:06:56+09:00
Laravel で他のフィールド名を受け取って、配列にも対応したカスタムバリデーションルールを作る
経緯
Laravel のバリデーションルールの same 等は他のフィールド名を受け取る事ができ、配列にも対応している。
このようなカスタムバリデーションルールを作ろうと思ったがなかなか情報が見つからずに苦労したのでまとめる。あるデータ内の2つの値の合計が41になる事を検証したい事がよくあると思うので1本記事では例として実装する。
配列に対応していない版
AppServiceProvider::boot
内でValidator
ファサードのextend
メソッドを使ってルールを登録する。<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use Validator; class AppServiceProvider extends ServiceProvider { public function boot() { Validator::extend('sum41', function ($attribute, $value, $parameters, $validator) { return $value + ($validator->getData())[$parameters[0]] === 41; }); } }
rule:param1[,...]
のようにルールに渡した引数は、extend
メソッドのクロージャの第3引数で配列として受け取れる。第4引数は
\Illuminate\Validation\Validator
のインスタンスで、getData
メソッドを使えば全体のデータが取得できる。よって
param1
に他のフィールドのキーを指定しているなら($validator->getData())[$parameters[0]]でそのフィールドの値が取得できる。
実際にルールを使ってみる。
>>> $data = ['data1' => 10, 'data2' => 31]; >>> $rules = ['data1' => 'required', 'data2' => 'sum41:data1']; >>> Validator::make($data, $rules)->validate() => [ "data1" => 10, "data2" => 31, ] >>> $data2 = ['data1' => 10, 'data2' => 30]; >>> Validator::make($data2, $rules)->validate() Illuminate/Validation/ValidationException with message 'The given data was invalid.'データが一件の時は問題なく動いているように見えるが、配列に対して使おうとすると
*.data1
をそのままキーとして認識するためNotice: Undefined index
が発生する。>>> $data = [['data1' => 10, 'data2' => 31], ['data1' => 20, 'data2' => 21]]; >>> $rules = ['*.data1' => 'required', '*.data2' => 'sum41:*.data1']; >>> Validator::make($data, $rules)->validate() PHP Notice: Undefined index: *.data1 in /***/app/Providers/AppServiceProvider.php on line 14配列に対応
調べた所、パラメータの
*
を配列のインデックスに変換するためにはextend
の代わりにextendDependent
メソッドを使ってルールを登録すれば良い事が分かった。(この情報がなかなか見つからなかった)これだけで
$parameters
配列に自動的に0.data1
のような値が入ってくれる。また、
$validator->getData()
はarray:2 [ 0 => array:2 [ "data1" => 10 "data2" => 31 ] 1 => array:2 [ "data1" => 20 "data2" => 21 ] ]このような構造になっているので
Arr::get($validator->getData(), $parameters[0])で目的の値が取得できる。
最終的に以下のようになった。
<?php namespace App\Providers; use Arr; use Illuminate\Support\ServiceProvider; use Validator; class AppServiceProvider extends ServiceProvider { public function boot() { Validator::extendDependent('sum41', function ($attribute, $value, $parameters, $validator) { return $value + Arr::get($validator->getData(), $parameters[0]) === 41; }); } }>>> $data = [['data1' => 10, 'data2' => 31], ['data1' => 20, 'data2' => 21]]; >>> $rules = ['*.data1' => 'required', '*.data2' => 'sum41:*.data1']; >>> Validator::make($data, $rules)->validate() => [ [ "data1" => 10, "data2" => 31, ], [ "data1" => 20, "data2" => 21, ], ]別の方法
一度しか使わないルールを検証時にその場で記述したい場合は、
\Illuminate\Validation\Validator::addDependentExtension
でもルールの登録ができる。$validator = Validator::make($data, $rules); $validator->addDependentExtension('sum41', function($attribute, $value, $parameters, $validator) { return $value + Arr::get($validator->getData(), $parameters[0]) === 41; }); $validator->validate();
ない ↩
- 投稿日:2019-11-29T00:29:51+09:00
ComposerでLaravelの開発環境を構築しよう
Laravelとは
Laravelは、MVCのWebアプリケーション開発用の無料・オープンソースのPHPで書かれたWebアプリケーションフレームワークです。webフレームワークを使うことでwebサービスの開発スピードが上がったり、セキュリティの安全性を担保できます。日本では、様々な企業で使われています。
引用: ウィキペディア
公式ページ: http://laravel.jp/Composerとは
composerはPHPのパッケージ管理システムです。
https://getcomposer.org/
環境構築の手順
- Homebrewをインストール
- MySQLをインストール
- Composerをインストール
- Laravelのプロジェクトディレクトリを作成
1. Homebrewをインストール
HomebrewとはmacOS用パッケージマネージャーで、composerとmysqlをインストールをするために必要なのでインストールします。
Homebrew公式ページ: https://brew.sh/index_ja/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"2. MySQLをインストール
laravelはデータベースシステムを使うので、MySQLをインストールします。laravelはMySQL以外にもSQLiteやPostgreSQLなどを使うこともできます。
brewコマンドを使ってmysqlをインストールします。
brew install mysqlmysqlのサーバーを起動させます。
mysql.server start Starting MySQL . SUCCESS!mysqlサーバーに接続します。
mysql -u root3. Composerをインストール
brewコマンドでcomposerでインストールします。
brew install composer4. Laravelのプロジェクトディレクトリを作成
composerコマンドでlaravelのプロジェクトディレクトリを作成します。
composer create-project laravel/laravel your-project-name --prefer-dist作成したプロジェクトディレクトリに移動
cd your-project-namelaravelサーバーを起動
php artisan serve起動ができたら、 http://localhost:8000/ にアクセスしましょう。
参考