- 投稿日:2019-05-22T23:27:32+09:00
【個人用】Laravel5.5 初開発メモ①
用途
- 開発中に調べたことをメモしてた(雑です)
- 限定公開に埋もれ出したので、公開する
- Laravel 5.5
- 困った時に見てる
設計
- 外部キーにユニーク制約が必要でないか調べる
FormHelper
RadioButton
CheckBox
だいたいこんな感じで進むと思われる
1) make migration 2) make model 3) make factory 4) make seeder 5) make controller 6) make blade 7) make routing 8) make RequestForm 9) make logic 10) testing api & validationDone!
実装・修正箇所の探し方
Controllerから探す
①Controller見る
②Routingを見る
③Blade見るViewから探す
①Routingから見る
②Controller探す
or
①Grepかける使ったライブラリ
- barryvdh/laravel-debugbar => デバッガー
- FriendsOfPHP/PHP-CS-Fixer => コード解析&修正
Composer
dump-autoload
- とりあえず、クラス等のロードが早くなるイメージ
Migrate
$ php artisan make:migration create_users_tableint、bigint、smallint、および tinyint (Transact-SQL)
- TinyIntにunsignedは要らない
- intは-2からなのでいる
Eloquent(Model)
- Migrationファイルと一緒に生成することもできる。
論理削除
$ php artisan make:model UserSeeder
- SeederでFactory使うときは、呼び出す
$ php artisan make:seeder UsersTableSeederFactory
$user = factory(User::class)->create(); # モデルの作成&保存 $user = factory(User::class)->make(); # モデルの作成$ php artisan make:factory PostFactoryFaker
- 出たものは出さないようにする
'user_id' => $faker->unique()->numberBetween(1, 50),Controller
Routing
Route::resource
Roure::resource('/email-template', 'EmailTemplateController');
- ルートの確認
$ php artisan route:list名前付きルート
バリデーション
- おそらく、sizeとmaxの違いは、文字数かKBの違い
フォームリクエストバリデーション
$ php artisan make:request StoreBlogPost
- return=falseでrulesがからの場合、the action is unconciousになる
検索のバリデーション
- 検索のバリデーションも考慮する。
- name属性がちゃんと指定されているか、確認する
name="title" #いける title="title" #grepかけて、直すとミスる時がある。PHPUnit
Generate
// Featureディレクトリにテストを生成する(Controller) $ php artisan make:test StaffControllerTest // Unitディレクトリにテストを生成する(Model) $ php artisan make:test StaffTest --unitExecute
$ ./vendor/bin/phpunit // 全体のテスト $ ./vendor/bin/phpunit tests/Feature // Featureのテスト $ ./vendor/bin/phpunit tests/Unit // UnitのテストPoint of view
Feature Test(Controller)
- Testing APIUnit Test(Model etc)
- Testing ValidationTips
- Laravel 5.3 データベースのテスト
- 属性のオーバーライド、ステート、DBのリフレッシュあたりは押さえておきたい
use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\DatabaseMigrations;
- Docker内だと、セッション開始がテスト時に実行されないケースがあるので、明示的に開始する
use DatabaseMigrations; use WithFaker; protected function setUp() { parent::setUp(); Session::start(); }FormHelper
Form::open{{ Form::open(['route' => array('email-template.update', $email_template->id), 'method' => 'post']) }} {{ method_field('PUT') }} @include('email_template.partials.form')Mailer
- 設定の変更
$ cp .env.example .env
- 再読み込み
$ php artisan config:cache
- generate
$ php artisan make:mail UserPasswordResetMail
- Error
Class 'App\Http\Controllers\Mail' not found
- HTMLの命名規則はケバブケース
=> password-reset.blade.php
namespaceについて
form request validation
フォームのバリデーション設定
パスワードリセット機能を作る
laravel str_randomは安全ですか? - 文字列、laravel、URL、ランダム
CSRF の安全なトークンの作成方法
[Laravel]メール認証を使った会員登録- メールで初期パスワードを平文で送るの大丈夫か??
ルーティング
Viewに値を渡す
[laravel] controllerからviewへの変数の受け渡しとその展開方法
RequestFormによるバリデーション
ORM
- where(※一件だけ取得する)
$user = User::where('email', $request->email)->first();HTTPレスポンス
フラッシュメッセージ
trans
日付処理
Laravelで日付関連の処理を行うCarbonを使ってみる
複数の変数を引数で渡す
php – Laravel – 複数の変数を渡して表示する
- 取り出し方$user->name = $data['user_info']['name'];405: ルーティング定義漏れ
419: CSRF対策漏れハッシュ化と暗号化
Laravel 5.6 ハッシュ
Laravel 5.5 暗号化コメント
@section('script') <script> (function ($) { /* --------------------------------------------------- // character count -----------------------------------------------------*/ (function () { $('textarea').on('keyup', function() { const len = $(this).val().length; if (len > 1000) { $(this).val($(this).val().substring(0, 999)); } else { $(this).next('span').text(len + '/1000文字'); } })
- 投稿日:2019-05-22T20:44:16+09:00
Laravelで投稿アプリの機能を作成 ~リレーション編~
はじめに
前回、「【30分クッキング】Laravelで投稿アプリの機能を作成 ~CRUD編~」というタイトルで記事を書かせていただきましたが、その続きの記事になります。
今回は、Auth認証できるusersテーブルと前回作ったpostsテーブルをリレーション(関連付け)させてみたいと思います。前提
前回のデータをベースに修正していきます
なので、前回の記事から実装をお勧めします
完全コピペすれば30分ほどで実装できるはずです
https://qiita.com/ProgramingDai/items/cf6944f9cd0ac08f4e3eテーブルイメージ
外部キーカラムの命名規則
(主テーブル名の単数形) _ id
※今回のケースではusersテーブルが主テーブルなので「user_id」が外部キーとなります[用語説明]リレーション【relation】とは
かかわりがあること・つながりがあること・関係・関連リレーションの一例
・誰が投稿したのかを区別して表示できる
・記事を投稿した人だけがその記事を編集したり削除したり、またそのユーザーだけ表示することもできる
など手順レシピ
1.ログイン機能実装
Laravelでは以下のコマンドだけで簡単にAuth機能を実装できます
なんと便利なこと!!!
$ php artisan make:authそうするとwelcome.blade.phpの右上に「LOGIN」と「REGISTER」リンクが表示されるので
「REGISTER」からアカウント登録をおこなってください
そのアカウントで「LOGIN」ページからログインできます(注)前回の記事で実装した方ならすでにマイグレートでusersテーブルができているかと思いますが、
まだマイグレートしてない方は以下コマンドでマイグレートお願いします
$ php artisan migrate2.ルーティング設定
/routes/web.php// RESTfulサービスのルーティング Route::resource('/post', 'PostController')->middleware('auth'); // ->middleware('auth')を追加こうすることで、このページにアクセスする際は登録したメールアドレス・パスワードが必要になります
3.モデル内修正
/app/Post.php// belongsTo結合(主テーブル <- 従テーブル) public function user() { return $this->belongsTo('App\User'); }postsテーブルは従テーブルなので「belongsTo」を設定します
/app/User.php// hasMany結合(主テーブル -> 従テーブル) public function posts() { return $this->hasMany('App\Post'); } // 今回はこちらは使いませんが一応設定しておきますusersテーブルは主テーブルなので「hasMany」(1対多結合) or 「hasOne」(1対1結合)を設定します
共に引数には互いのモデル名を入れます4.コントローラー設定
/app/Http/PostController.php// 追加 これがないとエラーになります use Illuminate\Support\Facades\Auth; // 中略 public function index() { $user = Auth::user(); // 認証ユーザー取得 $items = Post::with('user')->get(); // 「Post::all();」ではN+1問題になり、SQLの発行数が増える $params = [ 'user' => $user, 'items' => $items, ]; return view('post.index', $params); // ビューの描画 // return $items->toArray(); // JSONデータで描画 } // 中略 public function show($id) { $user = Auth::user(); // 認証ユーザー取得 $item = Post::find($id); $params = [ 'user' => $user, 'item' => $item, ]; return view('post.show', $params); } // 中略use追加、indexとshowメソッドのみ修正
cf. N+1問題について
https://qiita.com/B106827/items/2a33fcf288eda7769e415.ビューでの切り分け
/resource/post/index.blade.php<!-- 中略 --> <!-- 前回仮入れした箇所: <input type="hidden" name="user_id" value="1"> --> <!-- これで認証ユーザーでの記事投稿が可能になる --> <input type="hidden" name="user_id" value="{{ $user->id }}"> <!-- 中略 --> <!-- 記事描画部分 --> @if(count($items) > 0) @foreach($items as $item) <div class="alert alert-primary" role="alert"> @if($user->id === $item->user_id) <!-- 主キーと外部キーが同じ場合 -> リンク付きテキストと削除ボタン表示 --> <a href="/post/{{ $item->id }}" class="alert-link">{{ $item->title }}</a> <div>{{ $item->message }}</div> <form action="/post/{{ $item->id }}" method="POST"> {{ csrf_field() }} <input type="hidden" name="_method" value="DELETE"> <input type="submit" class="delete" value="削除"> </form> @else <!-- 主キーと外部キーが違う場合 -> 通常のテキストのみ表示 --> <span class="alert-link">{{ $item->title }}</span> <div>{{ $item->message }}</div> @endif <!-- この部分はいろいろ出し方を変えられますのでおのおのでカスタマイズしてみてください --> </div> @endforeach @else <div>投稿記事がありません</div> @endif <!-- 中略 -->/resource/post/show.blade.php<!-- index.blade.php同様、value差し替え --> <input type="hidden" name="user_id" value="{{ $user->id }}">cf. RESTfulのルーティング確認方法
php artisan route:listあとがき
これで2つのテーブルのリレーションはできたかと思います。
まだログイン画面やログアウト先のルーティングなどはデフォルトのままなので、
次はオリジナルのログイン画面の実装などをしていきたいと思います。
※そちらは別ページでのアップ予定です。Laravelで投稿アプリの機能を作成
~CRUD編~
https://qiita.com/ProgramingDai/items/cf6944f9cd0ac08f4e3e
~リレーション編~
https://qiita.com/ProgramingDai/items/249acc8894079ee58268
~ログインカスタマイズ編~
https://qiita.com/ProgramingDai/items/fee669e5a8cf67f0e38e参考書籍: PHPフレームワーク Laravel入門
https://blog.hiroyuki90.com/articles/laravel-books/
N+1問題について: https://qiita.com/B106827/items/2a33fcf288eda7769e41
- 投稿日:2019-05-22T18:22:40+09:00
vagrant box add した際のエラー解決(OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 54)
Homesteadで仮想マシンを使用していたが、VirtualBoxのバージョンアップをしたらホストOSとゲストOSのバージョンが違うということで使用できなくなった。
vagrant-vbguestでうまくできると思ったが、ゲストOSのビルド?が必要だったり?と難しそうだったので今回はマシンを作り直すことにしました。仮想マシンを作り直そうとHomesteadのboxファイルを削除して、また入れ直そうとした時に以下のエラーが発生
$ vagrant box add laravel/homestead ==> box: Loading metadata for box 'laravel/homestead' box: URL: https://vagrantcloud.com/laravel/homestead This box can work with multiple providers! The providers that it can work with are listed below. Please review the list and choose the provider you will be working with. 1) hyperv 2) parallels 3) virtualbox 4) vmware_desktop Enter your choice: 3 ==> box: Adding box 'laravel/homestead' (v7.2.1) for provider: virtualbox box: Downloading: https://vagrantcloud.com/laravel/boxes/homestead/versions/7.2.1/providers/virtualbox.box box: Download redirected to host: vagrantcloud-files-production.s3.amazonaws.com An error occurred while downloading the remote file. The error message, if any, is reproduced below. Please fix this error and try again. OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 54ダウンロード関係のファイル等が格納されている
~/.vagrant.d/tmp/を確認$ ls ~/.vagrant.d/tmp/ boxd96a327de9d4e23d1ce1a91384ae3975899cf47e boxf045ffba7f5588c8bf5a474bb05e6eab94df86acダウンロードに失敗した後にtmpフォルダにごみファイルが残ってしまうようなので、この中のファイルを削除します。
$ rm ~/.vagrant.d/tmp/*再度boxをインストール
$ vagrant box add laravel/homestead ==> box: Loading metadata for box 'laravel/homestead' box: URL: https://vagrantcloud.com/laravel/homestead This box can work with multiple providers! The providers that it can work with are listed below. Please review the list and choose the provider you will be working with. 1) hyperv 2) parallels 3) virtualbox 4) vmware_desktop Enter your choice: 3 ==> box: Adding box 'laravel/homestead' (v7.2.1) for provider: virtualbox box: Downloading: https://vagrantcloud.com/laravel/boxes/homestead/versions/7.2.1/providers/virtualbox.box box: Download redirected to host: vagrantcloud-files-production.s3.amazonaws.com ==> box: Successfully added box 'laravel/homestead' (v7.2.1) for 'virtualbox'!無事入りました!
- 投稿日:2019-05-22T17:44:06+09:00
Lalavelでのログイン機能実装にあたって罠にはまった
背景
Laravel5.8でコマンド「php artisan make:Auth」でログイン機能やら登録画面やら一撃実装できることを知って、
感動してたときのことです。やっぱり自分流にカスタマイズしたい
そう思うでしょう?
罠
登録画面をカスタマイズ、DBにテーブルも準備してユーザ登録されることも確認!いざ!ログイン!
だがしかし、IDとパスワードを入れてログインボタンを押すと、永遠にログイン画面にリダイレクトされる。。。
今回の問題点
僕は数行前でIDとパスワードを入れてログインボタンを押すといった。
そう、IDとパスワード。
そう、IDこれだ。
改善
コマンドで一撃実装をすると、ログイン画面で入力するフォームは
・password
となっている。このe-mailのフィールドをblade上でidに書き換えるだけではだめだったのである。
ここで公式のドキュメントを見てみる。
[ユーザー名のカスタマイズ]の項目を見ると、どうやらLoginController内にてusernameメソッドを定義する必要があったようだ。
こんな感じで定義してやると、ログインできる。
もちろん、bladeのフィールド名はちゃんと書き換えてくれ。
公式のドキュメント見たら済むお話をわざわざ記事にしてしまった自分が情けない。。。。
- 投稿日:2019-05-22T15:31:49+09:00
Laravelでヘルパー乱用をしてグローバル汚染するのを避ける提案
Laravelでviewのロジックを切り出したいときにhelperは便利
以下のように定義してしまえば、どこからでも呼び出せる
viewロジックをまとめられた!!となるが、
どこからでも呼び出せてしまうという問題も同時におきている。if (!function_exists('normalizeAge')) { /** * 年齢から 10代前半 の表記に丸めた文字列を返す * @param int $age 年齢 * @return string 10代前半など年代を丸めた文字列 */ function normalizeAge($age) { if (empty($age)) { return '年齢 未回答'; } return getTensPlace($age) . '代' . (isEarlyAge($age) ? '前半' : '後半'); } }そこでviewテンプレートのBladeの構文解析器を拡張する(directive追加)
Controller側でこれを定義しておくことで、そのControllerを用いた時だけ使える
viewテンプレートで利用可能な構文が追加される。Blade::directive('normalizeAge', function ($age) { if (empty($age)) { return "<?php echo 年齢、未回答; ?>"; } return "<?php echo getTensPlace($age) . '代' . (isEarlyAge($age) ? '前半' : '後半') ?>"; });使い方
bladeテンプレートファイルで @if や @foreach のように記述するだけ
@normalizeAge(14)このようにすることでグローバル汚染を防ぎつつ、viewで使えるロジックを定義できるのではないかと思った。
いや、普通に違う方法あるでしょというベストアンサーお待ちしてます。
- 投稿日:2019-05-22T14:20:47+09:00
AWS CodeBuildのコンテナから、RDSへ直接マイグレーションを実行する方法
概要
サービスを全部ECS + Fargateで行うサービスで、簡単かつCoolにマイグレーション実行する方法を記します。
具体的にはCodePipeline & CodeBuildを設定し、ビルド中にマイグレーションが走るように設定します。この記事が役に立ちそうな人
- ECS + Fargateでサービスを構築しようとしている人
- サービスにはRDSを用いているが、マイグレーションをどこから行おうか悩んでいる人
背景
マイグレーションをいかにCoolに行うかはサーバーサイドの至上命題と言っても過言ではありません。(?)
前述の通りECS + Fargateでサービスを構築すると、FargateにはSSHできないのは周知の事実です。
よってコンテナに入れないため、フレームワークの機能を用いたマイグレーションを実行できません。
そして、マイグレーションは必ずソースコードのデプロイ前に実行される必要があります。以上のことから、ソースコードのデプロイを行うCodePipelineのフローでマイグレーションを行うフェーズを追加し、マイグレーション含めたアプリケーションのデプロイを管理できたらCoolだなと思った次第です。
こちらの方法で実はその例が示されているのですが、タスク定義をjsonで書く必要があり、ステージング環境などの環境ごと対応が手間のように見受けられました。
もっと簡単でセキュアな方法はないかと考えていたところ、CodeBuildのドキュメントにCodeBuildが特定VPC, サブネットで実行できると書いていました。
RDSにはプライベートサブネットからしかアクセスできないようにしていましたが、これならCodeBuildインスタンスに立ち上げたコンテナから、マイグレーションを直接実行できるのでは? と思いついたわけです。
実際に
プライベートサブネット上に分離された Amazon RDS データベース内のデータに対して、ビルドから統合テストを実行する。
とあるように、RDSへのアクセスが想定されているようです。
目的
- CodePipelineのフェーズ中にmigrationフェーズを追加し、ソースコードのデプロイに加えてマイグレーションも制御したい
- ECSタスク定義を書きたくない
- もちろんセキュリティは維持する
- フレームワークのマイグレーション機能を使いたい 1
インフラ構成の説明
これが全貌ではありませんが、プライベートサブネットについてはこの構成です。AZの冗長化は端折っています。
ECSのセキュリティグループとは別のSGを用意し、CodeBuildにはそれを設定しておきます。セキュリティグループ3にはセキュリティグループ1のインバウンドトラフィックを許可しておきます。
セキュリティグループ1には特に設定は不要です。具体的な設定
CodeBuild
上記画像のようなVPCに関する設定があります。
ここにインフラ構成で記した通りの設定をしておきます。あと環境変数
AWS_ENVIRONMENTを設定しておきます。
これでどの環境のデータベースへ接続するかを、laravelのenvファイルの読み込みを切り替えることで選択できるようになります。
つまり後述のbuildspecは全環境で共通利用できます。加えて使用するbuildspecは後述の
buildspec-migration.ymlを指定してください。buildspec
実例を示します。
buildspec-migration.ymlversion: 0.2 phases: install: runtime-versions: docker: 18 commands: - echo Install started on `date` - cat /etc/issue - curl -L "https://github.com/docker/compose/releases/download/1.21.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && chmod +x /usr/local/bin/docker-compose - docker-compose --version - docker -v - pwd && ls -l build: commands: - echo Build started on `date` - echo Building the Docker image... - sed -e 's/AWS_ENVIRONMENT/$AWS_ENVIRONMENT/g' docker-compose-migration.yml > docker-compose.yml - docker-compose build - docker-compose up -d - docker ps - docker exec laravel-api bash /project/build.sh post_build: commands: - echo Build completed on `date` - echo Start migrate - docker exec laravel-api php project/artisan migrate私はdocker-composeを用いてコンテナを立ち上げています。2
sed -e 's/AWS_ENVIRONMENT/$AWS_ENVIRONMENT/g' docker-compose-migration.yml
これで環境ごとにdocker-compose.ymlを生成します。これでこのymlは全環境で使いまわせます。
docker exec laravel-api bash /project/build.sh
ここではcomposer installを行うだけのシェルを実行しています。でないとmigrateが動かないので。
docker exec laravel-api php project/artisan migrate
ここでついにmigrationを実行しています。docker-compose
私はdocker-composeを用いているので、その設定も例を示します。
docker-compose-migration.ymlversion: '3.3' services: # web - api api: build: ./alpine-apache-php7 container_name: laravel-api environment: - APP_ENV=AWS_ENVIRONMENT volumes: - "./project:/project" ports: - "18080:80"
APP_ENVには設定すればdevelopmentなどの任意のテキストを入れられるので、読み込む環境設定ファイルの制御ができます。CodePipeline
パイプラインの例を示します。
上記のようにECRへのビルドフェーズと、マイグレーション含むデプロイフェーズは分けています。
こうすることでマイグレーションとデプロイが自動的に実行されないようになります。参考文献
LaravelをElastic BeanstalkからFargateに移行しました
https://qiita.com/hareku/items/73f7730c1adc01bbe5a0AWS公式CodeBuildのVPCサポートについてのドキュメント
https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/vpc-support.html
フレームワークはLaravelを使っています。多分他のフレームワーク、言語でも同じことができるはずです。 ↩
どこかのタイミングからCodeBuildでdocker-composeを動かすとエラーを吐くようになりました。どうやら標準イメージを使うようになってから追加の設定が必要になったようです。このように別のソフトをインストールするときは、CodeBuildの環境設定において
Enable this flag if you want to build Docker images or want your builds to get elevated privileges.にチェックを入れないとエラーとなります。注意してください。 ↩
- 投稿日:2019-05-22T10:30:15+09:00
(Laravel5.8)ポリモーフィックを使った時の保存方法で詰んだのでメモしておく
はじめに
マルチログインを実装した画像投稿アプリを作っている中で、ポリモーフィックリレーションについての記事があまりなくて悩んだので、忘備録として残しておきます。内容はモデルのリレーションの話と、実装方法のみ。Laravelのインストール〜モデルの作成、マルチログイン実装などは参考になる記事がたくさんあったのでそちらをご参照ください。
今回のユースケースの解説
マルチログインを実装した時に、usersテーブルとgroupsテーブルを使ってそれぞれ別のログインページからログインさせて、middlewareを使ってログイン後の画面も別々で管理していました。group側からは写真の投稿ができたりマイページで自分の投稿を一覧で見たりする機能がありますが、user側からは投稿の閲覧とコメントしかできないように設計しています。
今回ポリモーフィックを使った箇所はコメント機能の実装です。コメントはuser側からもgroup側からも可能で、誰がコメントしたか分かるようにします。この時コメント(comment)はuserもしくはgroupどちらかに所属することになります。これがポリモーフィック関係です。
テーブル構造
users //親その1 id - integer name - string nickname - string email - string ///省略 groups //親その2 id - integer name - string email - string establish - date ///省略 comments //userかgroupいずれかにひも付く id - integer post_id - unsignedInteger //外部キーでpostにひも付く body - text commentable_id - integer //userかgroupのidが入る commentable_type - string //モデル名:App\UserかApp\Groupが入るcommentsテーブルだけ書き方が特殊です。構造見れば分かりますが、commentsテーブルに
user_idとgroup_idを外部キーとして持たせておけば、別にポリモーフィックを使わずともそれぞれ一対多のリレーションで処理できるのです。
ということでポリモーフィックは実際使う人が少なくて記事がなかったんだろうなと思っています。(私はせっかく機能としてあるなら使いたい!ということで使いました)それと、ポリモーフィック自体がアンチパターンでもあるという記事も見かけましたので置いておきますね。
SQLアンチパターンを読んで (ポリモーフィック関連について)
実際に書いていく
前提はここまでにして、いざ書いていきます。まずは、各モデルにリレーションの定義をしていきます。
各モデルのリレーション定義
User.phpclass User extends Authenticatable { /** * Commentに対してmorphMany */ public function comments() { return $this->morphMany('App\Comment', 'commentable'); } }Group.phpclass Group extends Authenticatable { /** * Userと同じ */ public function comments() { return $this->morphMany('App\Comment', 'commentable'); } }Comment.phpclass Comment extends Model { /** * 忘れずに$fillableを定義する */ protected $fillable = [ 'post_id', 'body', 'commentable_id', 'commentable_type' ]; /** * コメントはPost(投稿)にひも付く(今回は解説しません) */ public function post() { return $this->belongsTo('App\post'); } /** * 所有しているcommentableモデルの全取得 */ public function commentable() { return $this->morphTo(); } }で、ここまではだいたい調べれば書いてあるので、大丈夫だと思います。
次は、リレーションが定義できているかを調べるため、まずはtinkerでダミーのデータを登録しておきます。tinkerでダミーデータの登録
php artisan tinker >>> $com = new App\Comment => App\Comment {#2972} >>> $com->post_id = 1 => 1 >>> $com->body = 'testtesttest' => "testtesttest" >>> $com-> commentable_id = 1 => 1 >>> $com->commentable_type = 'App\Group' => "App\Group" >>> $com->save(); => true >>> exitmysql> select * from comments; +----+---------+--------------+----------------+------------------+---------------------+---------------------+ | id | post_id | body | commentable_id | commentable_type | created_at | updated_at | +----+---------+--------------+----------------+------------------+---------------------+---------------------+ | 1 | 1 | testtesttest | 1 | App\Group | 2019-05-21 05:51:03 | 2019-05-21 05:51:03 | +----+---------+--------------+----------------+------------------+---------------------+---------------------+ 1 row in set (0.00 sec)ちゃんと登録されました。
投稿者に関連するコメントを取り出す
先ほど登録した情報を取り出します。コメントの投稿者は
Groupモデルのid=1としたので、Groupモデルからコメントのデータを取って来られれば成功です。php artisan tinker >>> $comment = App\Group::find(1)->comments->all(); [ App\Comment {#2988 id: 1, post_id: 1, body: "testtesttest", commentable_id: 1, commentable_type: "App\Group", created_at: "2019-05-21 05:51:03", updated_at: "2019-05-21 05:51:03", }, ] //ちなみに逆の時、つまりcommentからuserもしくはgroupを取得する時はこんな感じ >>> $auth = App\Comment::find(1)->commentable->all(); => App\Group {#2989 id: 1, name: "グループname", cover_img: "sample.jpeg", icon_img: "sample.jpeg", //・・・省略 }よしっ!!!ページに実装だ!
・・・と思ってview側からコメントの表示はできたのですが、保存は???となりました。
コメントの保存
結論から言うと、めちゃくちゃ簡単でした。この辺が調べた時見たやつです。
https://laracasts.com/discuss/channels/eloquent/save-polymorphic-table?page=1
https://qiita.com/naga3/items/e7612d868857228c0bad
commentsテーブルの
commentable_idとcommentable_typeは定義せずともいい感じにやって頂けるようで。相変わらずかしこい。CommentController.phppublic function store(Request $request) { /**ログインユーザーの情報取得*/ $auth = Auth::user(); /**ログインユーザーにひも付けてコメントを保存*/ $auth->comments()->create( [ 'post_id' => $request->post_id, 'body' => $request->body ] ); //これで保存完了 /**リダイレクト先の振り分け*/ if (get_class($auth) == "App\Group") { return redirect('/group/posts'); } elseif (get_class($auth) == "App\User") { return redirect('/'); } }これでOKです!最後に一応、groupのview側からのコメント投稿箇所のコードも一部載せておきます。ルートの定義は、こんな感じでいけるはず。
web.phpRoute::get('group/comments', 'CommentController@index') Route::post('group/comments', 'CommentController@store');index.blade.php@forelse ($post->comments as $comment) <p>コメント</p> <pre>{{ $comment->body }}</pre> @empty <p>コメントがまだありません</p> @endforelse <form method="post" action="{{ url('group/comments') }}"> @csrf <p>コメント<br><textarea name="body" cols="40" rows="3"></textarea></p> <input type="hidden" name="post_id" value="{{ $post->id }}"> <button type="submit">コメント投稿</button> </form>不備や、もっとこうしたほうがいい!等ご意見があればぜひコメントいただければと思います。
- 投稿日:2019-05-22T00:16:16+09:00
【Laravel】コレクションのgroupByメソッド 練習問題3問(初心者向け)
はじめに
Laravelのコレクションの便利なメソッド
groupBy。あれこれ触ったので、覚えたことを忘れないよう、練習問題にしてみました。
問題
Order,OrderDetail,Book,Publisherモデルがあり、OrderDetailからリレーションのあるBook,Publisherまでを以下のように取得しました。$order_details = OrderDetail::with('book.publisher')->get(); print_r(json_encode($order_details, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT))$order_detailsをJSON化したもの[ { "id": 10001, "order_id": 1, "book_id": 111, "selling_price": 3000, "book": { "id": 111, "publisher_id": 11, "name": "自習Laravel", "list_price": 3500, "is_electronic_book": false, "publisher": { "id": 11, "name": "AA出版" } } }, { "id": 10002, "order_id": 1, "book_id": 222, "selling_price": 2500, "book": { "id": 222, "publisher_id": 22, "name": "基礎から学ぶPHP", "list_price": 3000, "is_electronic_book": true, "publisher": { "id": 22, "name": "BB出版" } } }, { "id": 10003, "order_id": 1, "book_id": 333, "selling_price": 3000, "book": { "id": 333, "publisher_id": 22, "name": "パーフェクトLaravel", "list_price": 3000, "is_electronic_book": false, "publisher": { "id": 22, "name": "BB出版" } } } ]問1
publisher_idでgroupByしてください。問2
問1の結果では、グループ化された配列のキーは
publisher_idの値になります。(11や22){ "11": [ { "id": 10001, "order_id": 1, "book_id": 111, "selling_price": 3000, "book": { "id": 111, "publisher_id": 11, "name": "自習Laravel", "list_price": 3500, "is_electronic_book": false, "publisher": { "id": 11, "name": "AA出版" } } } ], "22": [ { "id": 10002, "order_id": 1, "book_id": 222, //略これを
0から振り直してください。(JSON化した場合、以下のように出力されるようにしてください)[ [ { "id": 10001, "order_id": 1, "book_id": 111, "selling_price": 3000, "book": { "id": 111, "publisher_id": 11, "name": "自習Laravel", "list_price": 3500, "is_electronic_book": false, "publisher": { "id": 11, "name": "AA出版" } } } ], [ { "id": 10002, "order_id": 1, "book_id": 222, //略問3
まず、
is_electronic_bookでgroupByし、その上でそれぞれの要素に対して、publisher_idでgroupByしてください。補足
必要に応じてLaravel公式ドキュメントの
groupByほかを参照してください。
https://readouble.com/laravel/5.8/ja/collections.html#method-groupbyここから先、解答になります。
...
...
...
解答
問1の解答
publisher_idでgroupByしてください。
publisher_idは、bookをキーとする値の中に、さらにキーとして存在していました。$order_detailsをJSON化したものの抜粋"book": { "id": 111, "publisher_id": 11,こういった場合は、
.で繋いで指定すればOKです。問1の解答例$answer1 = $order_details->groupBy('book.publisher_id');問1の別解$answer1 = $order_details->groupBy('book.publisher.id');問2の解答
問1の結果では、グループ化された配列のキーは
publisher_idの値になります。(11や22)
これを0から振り直してください。キーの振り直しにはコレクションのメソッドである
valuesが使えます。valuesメソッドはキーをリセット後、連続した整数にした新しいコレクションを返します。
Laravel5.8 公式ドキュメント - values
https://readouble.com/laravel/5.8/ja/collections.html#method-values問2の解答例$answer2 = $order_details->groupBy('book.publisher_id') ->values();問2の解答例の結果をJSON化したもの[ [ { "id": 10001, "order_id": 1, "book_id": 111, "selling_price": 3000, "book": { "id": 111, "publisher_id": 11, "name": "自習Laravel", "list_price": 3500, "is_electronic_book": false, "publisher": { "id": 11, "name": "AA出版" } } } ], [ { "id": 10002, "order_id": 1, "book_id": 222, "selling_price": 2500, "book": { "id": 222, "publisher_id": 22, "name": "基礎から学ぶPHP", "list_price": 3000, "is_electronic_book": true, "publisher": { "id": 22, "name": "BB出版" } } }, { "id": 10003, "order_id": 1, "book_id": 333, "selling_price": 3000, "book": { "id": 333, "publisher_id": 22, "name": "パーフェクトLaravel", "list_price": 3000, "is_electronic_book": false, "publisher": { "id": 22, "name": "BB出版" } } } ] ]問3の解答
まず、
is_electronic_bookでgroupByし、その上でそれぞれの要素に対して、publisher_idでgroupByしてください。こういった場合は、同じくコレクションのメソッドである
transformの利用が考えられます。transformメソッドはコレクションを繰り返し処理し、コレクションの各アイテムに指定したコールバックを適用します。コレクション中のアイテムはコールバックから返される値に置き換わります。
Laravel5.8 公式ドキュメント - transform
https://readouble.com/laravel/5.8/ja/collections.html#method-transform
is_electronic_bookでgroupByした結果、2つの要素に分かれていますので、各々の要素に対してさらにpublisher_idでgroupByします。問3の解答例$answer3 = $order_details->groupBy('book.is_electronic_book') ->transform(function ($order_detail) { return $order_detail->groupBy('book.publisher_id') ->values(); });問3の解答例の結果をJSON化したもの[ [ [ { "id": 10001, "order_id": 1, "book_id": 111, "selling_price": 3000, "book": { "id": 111, "publisher_id": 11, "name": "自習Laravel", "list_price": 3500, "is_electronic_book": false, "publisher": { "id": 11, "name": "AA出版" } } } ], [ { "id": 10003, "order_id": 1, "book_id": 333, "selling_price": 3000, "book": { "id": 333, "publisher_id": 22, "name": "パーフェクトLaravel", "list_price": 3000, "is_electronic_book": false, "publisher": { "id": 22, "name": "BB出版" } } } ] ], [ [ { "id": 10002, "order_id": 1, "book_id": 222, "selling_price": 2500, "book": { "id": 222, "publisher_id": 22, "name": "基礎から学ぶPHP", "list_price": 3000, "is_electronic_book": true, "publisher": { "id": 22, "name": "BB出版" } } } ] ] ]最後に
以上です。何問解けたでしょうか?
コレクションメソッドを使っていて、また何か気付きがあれば練習問題にしてみたいと思います
参考
- 投稿日:2019-05-22T00:16:16+09:00
Laravelコレクションメソッド groupBy練習問題3問(初心者向け)
はじめに
Laravelのコレクションの便利なメソッド
groupBy。あれこれ触ったので、覚えたことを忘れないよう、練習問題にしてみました。
問題
Order,OrderDetail,Book,Publisherモデルがあり、OrderDetailからリレーションのあるBook,Publisherまでを以下のように取得しました。$order_details = OrderDetail::with('book.publisher')->get(); print_r(json_encode($order_details, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT))$order_detailsをJSON化したもの[ { "id": 10001, "order_id": 1, "book_id": 111, "selling_price": 3000, "book": { "id": 111, "publisher_id": 11, "name": "自習Laravel", "list_price": 3500, "is_electronic_book": false, "publisher": { "id": 11, "name": "AA出版" } } }, { "id": 10002, "order_id": 1, "book_id": 222, "selling_price": 2500, "book": { "id": 222, "publisher_id": 22, "name": "基礎から学ぶPHP", "list_price": 3000, "is_electronic_book": true, "publisher": { "id": 22, "name": "BB出版" } } }, { "id": 10003, "order_id": 1, "book_id": 333, "selling_price": 3000, "book": { "id": 333, "publisher_id": 22, "name": "パーフェクトLaravel", "list_price": 3000, "is_electronic_book": false, "publisher": { "id": 22, "name": "BB出版" } } } ]問1
publisher_idでgroupByしてください。問2
問1の結果では、グループ化された配列のキーは
publisher_idの値になります。(11や22){ "11": [ { "id": 10001, "order_id": 1, "book_id": 111, "selling_price": 3000, "book": { "id": 111, "publisher_id": 11, "name": "自習Laravel", "list_price": 3500, "is_electronic_book": false, "publisher": { "id": 11, "name": "AA出版" } } } ], "22": [ { "id": 10002, "order_id": 1, "book_id": 222, //略これを
0から振り直してください。(JSON化した場合、以下のように出力されるようにしてください)[ [ { "id": 10001, "order_id": 1, "book_id": 111, "selling_price": 3000, "book": { "id": 111, "publisher_id": 11, "name": "自習Laravel", "list_price": 3500, "is_electronic_book": false, "publisher": { "id": 11, "name": "AA出版" } } } ], [ { "id": 10002, "order_id": 1, "book_id": 222, //略問3
まず、
is_electronic_bookでgroupByし、その上でそれぞれの要素に対して、publisher_idでgroupByしてください。補足
必要に応じてLaravel公式ドキュメントの
groupByほかを参照してください。
https://readouble.com/laravel/5.8/ja/collections.html#method-groupbyここから先、解答になります。
...
...
...
解答
問1の解答
publisher_idでgroupByしてください。
publisher_idは、bookをキーとする値の中に、さらにキーとして存在していました。$order_detailsをJSON化したものの抜粋"book": { "id": 111, "publisher_id": 11,こういった場合は、
.で繋いで指定すればOKです。問1の解答例$answer1 = $order_details->groupBy('book.publisher_id');問1の別解$answer1 = $order_details->groupBy('book.publisher.id');問2の解答
問1の結果では、グループ化された配列のキーは
publisher_idの値になります。(11や22)
これを0から振り直してください。キーの振り直しにはコレクションのメソッドである
valuesが使えます。valuesメソッドはキーをリセット後、連続した整数にした新しいコレクションを返します。
Laravel5.8 公式ドキュメント - values
https://readouble.com/laravel/5.8/ja/collections.html#method-values問2の解答例$answer2 = $order_details->groupBy('book.publisher_id') ->values();問2の解答例の結果をJSON化したもの[ [ { "id": 10001, "order_id": 1, "book_id": 111, "selling_price": 3000, "book": { "id": 111, "publisher_id": 11, "name": "自習Laravel", "list_price": 3500, "is_electronic_book": false, "publisher": { "id": 11, "name": "AA出版" } } } ], [ { "id": 10002, "order_id": 1, "book_id": 222, "selling_price": 2500, "book": { "id": 222, "publisher_id": 22, "name": "基礎から学ぶPHP", "list_price": 3000, "is_electronic_book": true, "publisher": { "id": 22, "name": "BB出版" } } }, { "id": 10003, "order_id": 1, "book_id": 333, "selling_price": 3000, "book": { "id": 333, "publisher_id": 22, "name": "パーフェクトLaravel", "list_price": 3000, "is_electronic_book": false, "publisher": { "id": 22, "name": "BB出版" } } } ] ]問3の解答
まず、
is_electronic_bookでgroupByし、その上でそれぞれの要素に対して、publisher_idでgroupByしてください。こういった場合は、同じくコレクションのメソッドである
transformの利用が考えられます。transformメソッドはコレクションを繰り返し処理し、コレクションの各アイテムに指定したコールバックを適用します。コレクション中のアイテムはコールバックから返される値に置き換わります。
Laravel5.8 公式ドキュメント - transform
https://readouble.com/laravel/5.8/ja/collections.html#method-transform
is_electronic_bookでgroupByした結果、2つの要素に分かれていますので、各々の要素に対してさらにpublisher_idでgroupByします。問3の解答例$answer3 = $order_details->groupBy('book.is_electronic_book') ->transform(function ($order_detail) { return $order_detail->groupBy('book.publisher_id') ->values(); });問3の解答例の結果をJSON化したもの[ [ [ { "id": 10001, "order_id": 1, "book_id": 111, "selling_price": 3000, "book": { "id": 111, "publisher_id": 11, "name": "自習Laravel", "list_price": 3500, "is_electronic_book": false, "publisher": { "id": 11, "name": "AA出版" } } } ], [ { "id": 10003, "order_id": 1, "book_id": 333, "selling_price": 3000, "book": { "id": 333, "publisher_id": 22, "name": "パーフェクトLaravel", "list_price": 3000, "is_electronic_book": false, "publisher": { "id": 22, "name": "BB出版" } } } ] ], [ [ { "id": 10002, "order_id": 1, "book_id": 222, "selling_price": 2500, "book": { "id": 222, "publisher_id": 22, "name": "基礎から学ぶPHP", "list_price": 3000, "is_electronic_book": true, "publisher": { "id": 22, "name": "BB出版" } } } ] ] ]最後に
以上です。何問解けたでしょうか?
コレクションメソッドを使っていて、また何か気付きがあれば練習問題にしてみたいと思います
参考
- 投稿日:2019-05-22T00:16:16+09:00
Laravelコレクションメソッド groupByを重ねて複数使う (練習問題形式)
はじめに
Laravelのコレクションの便利なメソッド
groupBy。あれこれ触ったので、覚えたことを忘れないよう、練習問題にしてみました。
タイトルの、groupByを重ねて複数使う、最後の問3です。
問題
Order,OrderDetail,Book,Publisherモデルがあり、OrderDetailからリレーションのあるBook,Publisherまでを以下のように取得しました。$order_details = OrderDetail::with('book.publisher')->get(); print_r(json_encode($order_details, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT))$order_detailsをJSON化したもの[ { "id": 10001, "order_id": 1, "book_id": 111, "selling_price": 3000, "book": { "id": 111, "publisher_id": 11, "name": "自習Laravel", "list_price": 3500, "is_electronic_book": false, "publisher": { "id": 11, "name": "AA出版" } } }, { "id": 10002, "order_id": 1, "book_id": 222, "selling_price": 2500, "book": { "id": 222, "publisher_id": 22, "name": "基礎から学ぶPHP", "list_price": 3000, "is_electronic_book": true, "publisher": { "id": 22, "name": "BB出版" } } }, { "id": 10003, "order_id": 1, "book_id": 333, "selling_price": 3000, "book": { "id": 333, "publisher_id": 22, "name": "パーフェクトLaravel", "list_price": 3000, "is_electronic_book": false, "publisher": { "id": 22, "name": "BB出版" } } } ]問1
publisher_idでgroupByしてください。問2
問1の結果では、グループ化された配列のキーは
publisher_idの値になります。(11や22){ "11": [ { "id": 10001, "order_id": 1, "book_id": 111, "selling_price": 3000, "book": { "id": 111, "publisher_id": 11, "name": "自習Laravel", "list_price": 3500, "is_electronic_book": false, "publisher": { "id": 11, "name": "AA出版" } } } ], "22": [ { "id": 10002, "order_id": 1, "book_id": 222, //略これを
0から振り直してください。(JSON化した場合、以下のように出力されるようにしてください)[ [ { "id": 10001, "order_id": 1, "book_id": 111, "selling_price": 3000, "book": { "id": 111, "publisher_id": 11, "name": "自習Laravel", "list_price": 3500, "is_electronic_book": false, "publisher": { "id": 11, "name": "AA出版" } } } ], [ { "id": 10002, "order_id": 1, "book_id": 222, //略問3
まず、
is_electronic_bookでgroupByし、その上でそれぞれの要素に対して、publisher_idでgroupByしてください。補足
必要に応じてLaravel公式ドキュメントの
groupByほかを参照してください。
https://readouble.com/laravel/5.8/ja/collections.html#method-groupbyここから先、解答になります。
...
...
...
解答
問1の解答
publisher_idでgroupByしてください。
publisher_idは、bookをキーとする値の中に、さらにキーとして存在していました。$order_detailsをJSON化したものの抜粋"book": { "id": 111, "publisher_id": 11,こういった場合は、
.で繋いで指定すればOKです。問1の解答例$answer1 = $order_details->groupBy('book.publisher_id');問1の別解$answer1 = $order_details->groupBy('book.publisher.id');問2の解答
問1の結果では、グループ化された配列のキーは
publisher_idの値になります。(11や22)
これを0から振り直してください。キーの振り直しにはコレクションのメソッドである
valuesが使えます。valuesメソッドはキーをリセット後、連続した整数にした新しいコレクションを返します。
Laravel5.8 公式ドキュメント - values
https://readouble.com/laravel/5.8/ja/collections.html#method-values問2の解答例$answer2 = $order_details->groupBy('book.publisher_id') ->values();問2の解答例の結果をJSON化したもの[ [ { "id": 10001, "order_id": 1, "book_id": 111, "selling_price": 3000, "book": { "id": 111, "publisher_id": 11, "name": "自習Laravel", "list_price": 3500, "is_electronic_book": false, "publisher": { "id": 11, "name": "AA出版" } } } ], [ { "id": 10002, "order_id": 1, "book_id": 222, "selling_price": 2500, "book": { "id": 222, "publisher_id": 22, "name": "基礎から学ぶPHP", "list_price": 3000, "is_electronic_book": true, "publisher": { "id": 22, "name": "BB出版" } } }, { "id": 10003, "order_id": 1, "book_id": 333, "selling_price": 3000, "book": { "id": 333, "publisher_id": 22, "name": "パーフェクトLaravel", "list_price": 3000, "is_electronic_book": false, "publisher": { "id": 22, "name": "BB出版" } } } ] ]問3の解答
まず、
is_electronic_bookでgroupByし、その上でそれぞれの要素に対して、publisher_idでgroupByしてください。こういった場合は、同じくコレクションのメソッドである
transformの利用が考えられます。transformメソッドはコレクションを繰り返し処理し、コレクションの各アイテムに指定したコールバックを適用します。コレクション中のアイテムはコールバックから返される値に置き換わります。
Laravel5.8 公式ドキュメント - transform
https://readouble.com/laravel/5.8/ja/collections.html#method-transform
is_electronic_bookでgroupByした結果、2つの要素に分かれていますので、各々の要素に対してさらにpublisher_idでgroupByします。問3の解答例$answer3 = $order_details->groupBy('book.is_electronic_book') ->transform(function ($order_detail) { return $order_detail->groupBy('book.publisher_id') ->values(); });問3の解答例の結果をJSON化したもの[ [ [ { "id": 10001, "order_id": 1, "book_id": 111, "selling_price": 3000, "book": { "id": 111, "publisher_id": 11, "name": "自習Laravel", "list_price": 3500, "is_electronic_book": false, "publisher": { "id": 11, "name": "AA出版" } } } ], [ { "id": 10003, "order_id": 1, "book_id": 333, "selling_price": 3000, "book": { "id": 333, "publisher_id": 22, "name": "パーフェクトLaravel", "list_price": 3000, "is_electronic_book": false, "publisher": { "id": 22, "name": "BB出版" } } } ] ], [ [ { "id": 10002, "order_id": 1, "book_id": 222, "selling_price": 2500, "book": { "id": 222, "publisher_id": 22, "name": "基礎から学ぶPHP", "list_price": 3000, "is_electronic_book": true, "publisher": { "id": 22, "name": "BB出版" } } } ] ] ]最後に
以上です。何問解けたでしょうか?
コレクションメソッドを使っていて、また何か気付きがあれば練習問題にしてみたいと思います
参考
- 投稿日:2019-05-22T00:16:16+09:00
Laravelコレクションメソッド groupByを重ねて複数使うには? (練習問題形式)
はじめに
Laravelのコレクションの便利なメソッド
groupBy。あれこれ触ったので、覚えたことを忘れないよう、練習問題にしてみました。
タイトルの、groupByを重ねて複数使う、最後の問3です。
すぐにやり方を知りたいという方はこちらへどうぞ。問題
Order,OrderDetail,Book,Publisherモデルがあり、OrderDetailからリレーションのあるBook,Publisherまでを以下のように取得しました。$order_details = OrderDetail::with('book.publisher')->get(); print_r(json_encode($order_details, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT))$order_detailsをJSON化したもの[ { "id": 10001, "order_id": 1, "book_id": 111, "selling_price": 3000, "book": { "id": 111, "publisher_id": 11, "name": "自習Laravel", "list_price": 3500, "is_electronic_book": false, "publisher": { "id": 11, "name": "AA出版" } } }, { "id": 10002, "order_id": 1, "book_id": 222, "selling_price": 2500, "book": { "id": 222, "publisher_id": 22, "name": "基礎から学ぶPHP", "list_price": 3000, "is_electronic_book": true, "publisher": { "id": 22, "name": "BB出版" } } }, { "id": 10003, "order_id": 1, "book_id": 333, "selling_price": 3000, "book": { "id": 333, "publisher_id": 22, "name": "パーフェクトLaravel", "list_price": 3000, "is_electronic_book": false, "publisher": { "id": 22, "name": "BB出版" } } } ]問1
publisher_idでgroupByしてください。問2
問1の結果では、グループ化された配列のキーは
publisher_idの値になります。(11や22){ "11": [ { "id": 10001, "order_id": 1, "book_id": 111, "selling_price": 3000, "book": { "id": 111, "publisher_id": 11, "name": "自習Laravel", "list_price": 3500, "is_electronic_book": false, "publisher": { "id": 11, "name": "AA出版" } } } ], "22": [ { "id": 10002, "order_id": 1, "book_id": 222, //略これを
0から振り直してください。(JSON化した場合、以下のように出力されるようにしてください)[ [ { "id": 10001, "order_id": 1, "book_id": 111, "selling_price": 3000, "book": { "id": 111, "publisher_id": 11, "name": "自習Laravel", "list_price": 3500, "is_electronic_book": false, "publisher": { "id": 11, "name": "AA出版" } } } ], [ { "id": 10002, "order_id": 1, "book_id": 222, //略問3
まず、
is_electronic_bookでgroupByし、その上でそれぞれの要素に対して、publisher_idでgroupByしてください。補足
必要に応じてLaravel公式ドキュメントの
groupByほかを参照してください。
https://readouble.com/laravel/5.8/ja/collections.html#method-groupbyここから先、解答になります。
...
...
...
解答
問1の解答
publisher_idでgroupByしてください。
publisher_idは、bookをキーとする値の中に、さらにキーとして存在していました。$order_detailsをJSON化したものの抜粋"book": { "id": 111, "publisher_id": 11,こういった場合は、
.で繋いで指定すればOKです。問1の解答例$answer1 = $order_details->groupBy('book.publisher_id');問1の別解$answer1 = $order_details->groupBy('book.publisher.id');問2の解答
問1の結果では、グループ化された配列のキーは
publisher_idの値になります。(11や22)
これを0から振り直してください。キーの振り直しにはコレクションのメソッドである
valuesが使えます。valuesメソッドはキーをリセット後、連続した整数にした新しいコレクションを返します。
Laravel5.8 公式ドキュメント - values
https://readouble.com/laravel/5.8/ja/collections.html#method-values問2の解答例$answer2 = $order_details->groupBy('book.publisher_id') ->values();問2の解答例の結果をJSON化したもの[ [ { "id": 10001, "order_id": 1, "book_id": 111, "selling_price": 3000, "book": { "id": 111, "publisher_id": 11, "name": "自習Laravel", "list_price": 3500, "is_electronic_book": false, "publisher": { "id": 11, "name": "AA出版" } } } ], [ { "id": 10002, "order_id": 1, "book_id": 222, "selling_price": 2500, "book": { "id": 222, "publisher_id": 22, "name": "基礎から学ぶPHP", "list_price": 3000, "is_electronic_book": true, "publisher": { "id": 22, "name": "BB出版" } } }, { "id": 10003, "order_id": 1, "book_id": 333, "selling_price": 3000, "book": { "id": 333, "publisher_id": 22, "name": "パーフェクトLaravel", "list_price": 3000, "is_electronic_book": false, "publisher": { "id": 22, "name": "BB出版" } } } ] ]問3の解答
groupByを重ねて複数使うには、同じくコレクションのメソッドであるtransformも利用することが考えられます。問3の解答例$answer3 = $order_details->groupBy('book.is_electronic_book') ->transform(function ($order_detail) { return $order_detail->groupBy('book.publisher_id') ->values(); // valuesは用途に応じてお好みで。詳細は問2参照。 });transformメソッドはコレクションを繰り返し処理し、コレクションの各アイテムに指定したコールバックを適用します。コレクション中のアイテムはコールバックから返される値に置き換わります。
Laravel5.8 公式ドキュメント - transform
https://readouble.com/laravel/5.8/ja/collections.html#method-transform解答例では
is_electronic_bookでgroupByした結果、2つの要素に分かれていますので、このtransformを使って各々の要素に対してさらにpublisher_idでgroupByしています。問3の解答例の結果をJSON化したもの[ [ [ { "id": 10001, "order_id": 1, "book_id": 111, "selling_price": 3000, "book": { "id": 111, "publisher_id": 11, "name": "自習Laravel", "list_price": 3500, "is_electronic_book": false, "publisher": { "id": 11, "name": "AA出版" } } } ], [ { "id": 10003, "order_id": 1, "book_id": 333, "selling_price": 3000, "book": { "id": 333, "publisher_id": 22, "name": "パーフェクトLaravel", "list_price": 3000, "is_electronic_book": false, "publisher": { "id": 22, "name": "BB出版" } } } ] ], [ [ { "id": 10002, "order_id": 1, "book_id": 222, "selling_price": 2500, "book": { "id": 222, "publisher_id": 22, "name": "基礎から学ぶPHP", "list_price": 3000, "is_electronic_book": true, "publisher": { "id": 22, "name": "BB出版" } } } ] ] ]最後に
以上です。何問解けたでしょうか?
コレクションメソッドを使っていて、また何か気付きがあれば練習問題にしてみたいと思います
参考




