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

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

ただいまの
回答率

87.62%

laravel Model の with() のリレーション先カラム名を変更して取得したい

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 4,881

score 125

前提

以下のような構成のtable_atable_bがあります。
table_atable_bは一対多の関係にあります。

  • table_a
    id (int)
    name (string)

  • table_b
    id (int)
    table_a_id (int)
    name (string)

namespace App\Models;
use Illuminate\Database\Eloquent\Model;

Class TableA extends Model
{
    protected $table = 'table_a';
    public function b()
    {
        return $this->hasMany('App\Models\TableB');
    }
}
namespace App\Models;
use Illuminate\Database\Eloquent\Model;

Class TableB extends Model
{
    protected $table = 'table_b';
    protected $hidden = ['table_a_id',];
    public function a()
    {
        return $this->belongsTo('App\Models\TableA');
    }
}

知りたいこと

例えばtable_bから以下のようにModelを取得すると、

$model = TableB::with('a')->find($id);
{
    "id": 123,
    "name": "hoge",
    "a": {
        "id": 456,
        "name": "fuga"
    }
}


こんな感じになると思います。
ここで、

{
    "id": 123,
    "name": "hoge",
    "a": {
        "a_id": 456,
        "a_name": "fuga"
    }
}


上記のように
id -> a_id
name -> a_name
と、withでリレーション先テーブルのカラム名を任意に変更して取得したいのですが、どなたかご存知ないでしょうか?

version

laravel 5.6

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • takg

    2019/01/22 16:02 編集

    mix-peach様がおっしゃっているのは、ローカルキー/外部キーが`table名_id`になっていない場合などに明示的に指定する方法ではないでしょうか?

    SQLで書くと、
    SELECT a.id as a_id, a.name as a_name
    FROM table_b AS b
    LEFT JOIN table_a as a
    ON b.a_id = a.id
    WHERE b.id = ?;
    における "a.name as a_name" の部分のように、
    リレーション先の列名を任意のものに変更する方法が知りたいので、少し違う気がしたのですが。。。

    もしも誤解であれば、申し訳ありません。

    キャンセル

  • mix-peach

    2019/01/22 16:29

    はっ!質問を読み違えていたようで、申し訳ないです;;
    正しい回答を、書いてくださっている方がいるので、主には、そちらを参考に!
    他の方法も回答に書いてみますね(あんまりオススメしない方法ですが)

    キャンセル

  • takg

    2019/01/22 17:25

    見直してみると、質問の文章が少しわかりにくかったです。
    修正しておきます。
    ご回答、ありがとうございました。

    キャンセル

回答 2

+1

crhgさんが書かれている方法が、正しいと思いますので、主にはそちらを参考にしてください。


他の方法のお話。

いつでも

{
    "id": 123,
    "name": "hoge",
    "a": {
        "a_id": 456,
        "a_name": "fuga"
    }
}


の形で取得したくて、
つまり、「withするたびに、いちいちカスタマイズの指定を書くのはめんどくさい!」とかいう場合。

予め取得対象のカラムを指定するのと同じ要領で、TableBのModelのbelongsToに書いてしまう方法もあります。

public function a()
    {
        return $this->belongsTo('App\Models\TableA')
                    ->select([
                      'id as a_id',
                      'name as a_name',
                      'table_a_id']
                    );
    }


こんな感じで、いけたはず・・
※ 外部キー「table_a_id」は、必ず含めてください。

コメントにも書いたのですが、この方法をオススメしないのは、

aの取得結果が、いつでもa_id,a_nameになってしまうので、「直感的にlaravelのwith」として使った場合に正しく参照できない可能性が高いことや、取得カラムを増やしたい場合に追記しなければいけないことなど、本来の利便性で失われる面があるからです。。。

「システム全体」で、このような共通の仕様(テーブルのリレーション先を見る時、カラム名はテーブル名が先頭に付く)があるのであれば、この方法でも特には問題ないかもですね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/01/22 17:24

    ご回答ありがとうございます。
    なるほど、belongTo()の時点で設定しておくこともできるのですね。
    勉強になりました。

    キャンセル

checkベストアンサー

0

マニュアルの「Eagerロードへの制約」のところに書いてあるクロージャでクエリビルダをもらっていろいろ操作を行うやり方は

もちろんEagerロード操作を更にカスタマイズするために、他のクエリビルダを呼び出すこともできます。

とあるように他のカスタマイズにも使えますので、selectを使って別名をつけることができます。

        $model = TableB::with(['a' => function ($query) {
            $query->select(
                'id AS a_id',
                'name AS a_name',
                'table_a_id'    // リレーションに使うカラムは必ず含める必要があります
            );
        }])->find($id);

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/01/22 17:22

    ご回答ありがとうございます。
    教えていただいた方法で実現できました!

    キャンセル

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

  • ただいまの回答率 87.62%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る