質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

Q&A

解決済

1回答

720閲覧

laravel topics indexページを画像付きで表示したい(1:多)

Suzuki-Yamato

総合スコア8

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

0グッド

0クリップ

投稿2021/02/17 01:38

開発環境:Laravel5.5 , MySQL5.7
にて実装しています。

トピック(新着情報)のリストページを作成しているのですが、
簡単なことでエラーとなりました。

トピック情報を掲載するのに、
データベース テーブルは2つあります。

topics テーブル
id , title , content , updated_at

topic_images テーブル
id , topic_is(外部キー), img_at , updated_at

です。
このテーブルは、
topics : topic_images = 1 : 多
となります。

Laravel クエリービルダーでこの情報をコントローラで読み込み際に
$topic_datas = DB::table('topics')
->join('topic_images', 'topics.id', '=', 'topic_images.topic_id')
->select('topics.id', 'topics.title', 'topics.content', 'topic_imags.img_at')
->groupBy('topics.id')
->get()

と実装しますと、当然かもしれませんが img_at が複数あるために どれが選択して良いか不明となるためエラーになってしまいます。

SELECT list is not in GROUP BY clause and contains nonaggregated column ‘(フィールド名)’ which is not functionally dependent on columns in GROUP BY clause

img_at の選択は、topic_images.id の 1番若い番号を選出する様にしたいのですが、
どのようなクエリー分になるか、わかりますでしょうか?

単純な質問で申し訳ありません。
不足情報は記述しますので、どなたかアドバイスをお願いしたいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

DBファサードの代わりにEloquentを使っても良いのではないかと思いました。
その場合は、以下のような感じにするのはいかがでしょうか。

Topicモデル

php

1namespace App; 2 3use Illuminate\Database\Eloquent\Model; 4 5class Topic extends Model 6{ 7 public function topicImages() 8 { 9 return $this->hasMany(TopicImage::class); 10 } 11}

参考: 1対多

TopicImageモデル

php

1namespace App; 2 3use Illuminate\Database\Eloquent\Model; 4 5class TopicImage extends Model 6{ 7 // 8}

コントローラのアクション

php

1 public function index() 2 { 3 // Topicを取得して、topicImagesを遅延ロードする 4 $topics = \App\Topic::with(['topicImages' => function ($query) { 5 $query->orderBy('id', 'desc'); // idが若い順に取得 6 }])->get(); 7 8 return view(ビュー名, compact('topics')); 9 }

参考: Eagerロードへの制約

Bladeビュー

php

1 <table class="table"> 2 ... 3 <tbody> 4 @foreach($topics as $topic) 5 <tr> 6 <td>{{ $topic->id }}</td> 7 <td>{{ $topic->title }}</td> 8 <td>{{ $topic->content }}</td> 9 <td> 10 {{-- topicImagesを取得して最初のものを選出して表示 --}} 11 <img 12 src="{{ $topic->topicImages->first()->img_at }}" 13 alt="{{ $topic->topicImages->first()->id }}" 14 > 15 </td> 16 </tr> 17 @endforeach 18 </tbody> 19 </table>

参考: first()

投稿2021/02/17 02:59

Lulucom

総合スコア1899

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Suzuki-Yamato

2021/02/17 03:04

ご支援ありがとうございます。 実は、今回 Laravel-Admin というライブラリーを採用しております。 (前担当者が実装していました。) Eloquent で実装すると、なぜか エラーになる (どうも Roleの箇所が不適切の様でエラーの対策ができずに クエリービルダーで対応していました。) やはりEloquent で実装できる方法が良いのかもしれませんね。 アドバイス適切であります。ご連絡ありがとうございます。
Suzuki-Yamato

2021/02/17 04:08

protected static function boot() { parent::boot(); static::addGlobalScope('owner_id', function (Builder $builder) { if (Admin::user()->inRoles(['super_admin', 'system_admin'])) { $builder->whereNotNull('id')->orderBy('updated_at', 'desc'); } }); } Laravel-Admin (管理画面からの投稿)でこのグルーバルスコープにてラーになってしまいます。 Call to a member function inRoles() on null 良きアドバイスがありましたら助かります。
Lulucom

2021/02/17 04:10

Admin::user() の戻り値がnullになっているようですね。何かお心当たりはありますか?
Suzuki-Yamato

2021/02/17 04:39

正しく、そこであります。 管理画面(Auth認証で、ログイン後 Topicsモデルを編集するために、この関数があると思いますが、 viewで表示させるためでしたら、ここは不要なはずなのですが、 ここを、どの様に編集して良いか。。。実は困っていたところです。 管理画面のコントロールでは、 $grid = new Grid(new Topic); と使用されていますが、実は Laravel-Admin の仕様も不明で困っていました。 そのため、Eloquentを使用せず、クエリービルダーで対応していたところです。 深みにハマる質問ですみません。
Lulucom

2021/02/17 04:49

私もLaravel-Adminは殆ど知見がないのですが、 ・先ほどのbootメソッドは何のモデルのものでしょうか ・Admin::user()のAdminとはどのようなクラスでしょうか
Suzuki-Yamato

2021/02/17 04:55

ご連絡ありがとうございます。 Topicモデルになります。 全文を記載させていただきます。 namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Builder; use Encore\Admin\Facades\Admin; class Topic extends Model { /** * モデルの「初期起動」メソッド * * @return void */ protected static function boot() { parent::boot(); static::addGlobalScope('owner_id', function (Builder $builder) { if (Admin::user()->inRoles(['super_admin', 'system_admin'])) { $builder->whereNotNull('id')->orderBy('updated_at', 'desc'); } }); } /** * ユーザーに関連する情報を取得 */ public function user() { return $this->hasOne(config('admin.database.users_model'), 'id', 'owner_id'); } public function topic_category() { return $this->belongsTo(TopicCategory::class); } public function topic_images() { return $this->hasMany(TopicImage::class,'topic_id'); } } もし一般的にviewへの適用の際には、無効にするような方法があれば良いのですが、、、
Lulucom

2021/02/17 05:08 編集

Admin::user()は、認証済みの管理者ユーザーがアクセスしてきたときだけ、管理者ユーザーのインスタンスが返されるのかもしれないですね。モデルの中で認証状況を判定するのってどうなのかな?という疑問はありますが、その部分でoptional()を使って以下のようにしてみるとどうでしょうか。 if (optional(Admin::user())->inRoles([ ... 参考: https://readouble.com/laravel/5.5/ja/helpers.html#method-optional
Suzuki-Yamato

2021/02/17 05:21

なるほど! やってみます。 おっしゃる通りで、前任者が モデルの中で認証状況をした理由がわからず、どの様に変更すれば良いかが困っていたところです。
Lulucom

2021/02/17 05:23

または、そこはそのままにしておき、代わりに、Laravel-admin以外でTopicを取得するときには必ず withoutGlobalScope('owner_id') を呼ぶようにしても良いと思います。 例: $topics = \App\Topic::withoutGlobalScope('owner_id') ->with(['topicImages' => function ($query) { $query->orderBy('id', 'desc'); }]) ->get();
Lulucom

2021/02/17 05:26

または、それをグローバルスコープにするのではなく、ローカルスコープにしてLaravel-adminでTopicを取得するときだけ適用するのが良いと思います。
Suzuki-Yamato

2021/02/17 05:33

なるほどです!!! やってみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問