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

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

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

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

Laravel 5

Laravel 5は、PHPフレームワークLaravelの最新バージョンで、2014年11月に発表予定です。ディレクトリ構造がが現行版より大幅に変更されるほか、メソッドインジェクションやFormRequestの利用が可能になります。

Q&A

解決済

1回答

1555閲覧

Auth::user() に hasMany 関係のtableの値を入れたい

sakamata

総合スコア203

Laravel

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

Laravel 5

Laravel 5は、PHPフレームワークLaravelの最新バージョンで、2014年11月に発表予定です。ディレクトリ構造がが現行版より大幅に変更されるほか、メソッドインジェクションやFormRequestの利用が可能になります。

0グッド

1クリップ

投稿2018/11/10 11:39

編集2018/11/10 11:43

Laravel5.6 でユーザーとコミュニティが多対多の関係を持つアプリを制作しています。
認証をカスタマイズしているのですが、アプリをけっこう作り込んでから困った事になっています。

##table設計

###users
ユーザーはユニークIDを持つ

###community_users
中間tableでユニークIDと userと community のIDを持つ

###community_user_status
上記中間tableと1対1で紐付いた ユーザーのcomuunity内でのステータス情報を持つ

###community
コミュニティ毎のユーザーの情報を持つ(管理権限等)

ユーザーはコミュニティ毎に異なるユーザーステータスを保持しています。
当初は以下のサイトを参考に、認証時に複数のtableを Join をした値を取得し、値を保持することには成功しました。

Laravel 5.2 Auth::user() に他テーブルのJOINしたデータを追加する。

これで以下の様な方法で値を取得し処理を書いていました。

Auth::user()->role == "Admin"

しかし、いざユーザーが二つ目のコミュニティにログインしようとする時点で詰まってしまいました。
ログイン認証が行われる際以下の処理が走ります。
app\Http\Controllers\Auth\LoginController.php

PHP

1 public function authenticate(Request $request) 2 { 3 4 $credentials = array( 5 'unique_name' => $request->unique_name, 6 'password' => $request->password, 7 ); 8 // 'community_user.id' => $community_user_id, 9 10 // 認証許可 11 if (Auth::attempt($credentials)) { 12 //認証済み後の処理等 13 ] 14 }

上記のAuth::attempt($credentials)の処理が走る際、以下に書いた処理が走り、 Auth::user()に取得した値が入る事になっています。

app\Providers\AuthUserProvider.php namespace App\Providers; use Illuminate\Auth\EloquentUserProvider; use Illuminate\Support\Facades\Log; class AuthUserProvider extends EloquentUserProvider { public function retrieveById($identifier) { $result = $this->createModel()->newQuery() ->Join('community_user', 省略) ->Join('communities_users_statuses', 省略) ->Join('roles', 省略) ->select([ 'users.*', 'community_user.*', 'roles.*', ]) ->where('community_user.id', $identifier); return $result; } }

しかしこのメソッドの引数 $identifierに入るのはIDは users tableのユニークIDであり、本来取得に必要な中間table(community_user)のユニークIDにはならない為、ユーザーが複数のコミュニティに登録してしまうと。このクエリビルダだと、複数のレコードが存在した場合、どのレコードを拾うべきか判断がつかないのです。

そこで認証の際に使うModelを呼び出しの時点でリレーションが出来上がったモデル読み込む等して解決できないか?とか悩んでいます。
config\auth.php

'providers' => [ 'users' => [ 'driver' => 'auth_ex', 'model' => App\User::class, ],

上記の呼び出し対象は 最初からある User Authenticatableですが、ここと、呼び出し先のModelに上手い書き方をして、結合した状態のモデルを呼び出せればいいのですが、やり方がわかりません。app\User.phpに上手い書き方をすれば解決する様な気もするのですが…。

また、別の方法として、上記のモデルを CommunityUser 等に切り替えて、認証に使ってみましたが、 ユーザーのユニークな値を保持していない為一意の情報を取得できず認証できませんでした。

また、認証の拡張での方法も探ってみたのですが、理解が追い付かずです。
Laravel 5.dev フレームワークの拡張

上記ページの 認証 の部分を見て、これをどこに書き、中に何を入れるべきなのかが理解できませんでした。

Auth::extend('riak', function($app) { // Return implementation of Illuminate\Contracts\Auth\UserProvider });

また、UserProviderにある以下のメソッドもapp\Providers\AuthUserProvider.phpにて、retrieveById($identifier)と、併用または代用として使ってみましたが、やはりうまくいきません。
public function retrieveByCredentials(array $credentials);

こいつはapp\Providers\AuthUserProvider.phpに書けば認証時にオーバーライドされて処理が走る所までは掴み、 認証時の呼び出しModelを変えて色々試しましたがやはり駄目でした。

という事でこの辺のうまい解決方法やヒント等を頂けると大変助かります。
単純に Auth::user() に値を追加する等も方法でもあればいいのですが…。

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

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

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

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

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

guest

回答1

0

ベストアンサー

ユーザが参加しているコミュニティIDやロール(何のロールか不明ですが)をAuth::user()に入れておきたいということですね?

本来取得に必要な中間table(community_user)のユニークIDにはならない

まず、中間テーブルのidは関係ないのではないでしょうか。
community_usersテーブルはusersテーブルとcommunityテーブルの関係を定義しているわけですよね?
だったら、usersとcommunityのそれぞれの外部キーを持っているはずです。
たとえば下のように。

iduser_idcommunity_id
111
212
321

ということで、retrieveById()のwhereはusers.idかcommunity_users.user_idでいいでしょう。

複数のレコードが存在した場合、どのレコードを拾うべきか判断がつかないのです。

ユーザテーブルを他のテーブルとjoinして複数レコードを取得するとAuth::user()がオブジェクト配列になってしまうということですね。
元のEloquentUserProvider::retrieveById()を見ると、first()で1レコードだけ取得しています。
当然ですが、ユーザIDに対応するのは1人(1レコード)だけということでしょう。

Illuminate\Auth\EloquentUserProvider.php

php

1class EloquentUserProvider implements UserProvider 2{ 3 public function retrieveById($identifier) 4 { 5 $model = $this->createModel(); 6 7 return $model->newQuery() 8 ->where($model->getAuthIdentifierName(), $identifier) 9 ->first(); 10 }

取得するusersレコードは1つだけにし、community_usersやrolesは別に取得して$resultにくっつけるというのはどうでしょうか。

app\Providers\AuthUserProvider.php

php

1namespace App\Providers; 2 3use Illuminate\Auth\EloquentUserProvider; 4use Illuminate\Support\Facades\Log; 5 6class AuthUserProvider extends EloquentUserProvider 7{ 8 public function retrieveById($identifier) { 9 $result = $this->createModel()->newQuery() 10 ->select([ 11 'users.*', 12 ]) 13 ->where('users.id', $identifier) 14 ->first(); 15 16 $result->community_users = \App\CommunityUser::where('user_id', $identifier)->get(); 17 18 //rolesは省略 19 20 return $result; 21 } 22}

投稿2018/11/11 12:23

kgm

総合スコア275

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

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

sakamata

2018/11/11 15:44

回答ありがとうございます。 $result に一度値を入れてから、 $result->community_users と定義して、さらに値を追加できるものなんですね。まったく基礎的な事を把握していなかったので、とても良いヒントになりました。 また、joinする際にもこれまでは一意の値にこだわって中間tableのIDを頼りに取得したいと考えていましたが、逆にご提案してくださった様な方法でユーザーが加入している複数のコミュニティの値全て取得してしまった方が、アプリの仕様や実装上もなにかと都合が良いかもしれません。 おかげ様でここ数日悩んでいたことが突破できそうです。 とても良いヒントをくださってありがとうございます!! この方法で早速試してみます。
sakamata

2018/11/11 18:32

その後試してみて値が無事取得できました。よくよく考えると、Model等で取得できるデータはクエリのレコードというだけじゃなく、JavaScript等でも使うオブジェクトなのは当たり前で、あとから自由に要素を追加したり外したりが出来るわけですものね。恥ずかしながらこの辺の事柄をあまり意識せずLaravelを使ってました。 しかしこの辺を生かしてミドルウェア等にユーザーが現在閲覧中のコミュニティの値だけに絞り込む処理を書いて、他の処理がスムーズに書ける様なようなものを組み立ててみます。 繰り返しになりますが、大変良いアドバイスをありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問