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

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

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

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Eloquent

Eloquentとは、PHPフレームワークのLaravelに最初から含まれているORM(Object-relational mapping:オブジェクト関係マッピング)です。

Laravel 5

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

Q&A

解決済

2回答

3069閲覧

Eloquentのmorphとwithの併用は可能か?

masaya_ohashi

総合スコア9206

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Eloquent

Eloquentとは、PHPフレームワークのLaravelに最初から含まれているORM(Object-relational mapping:オブジェクト関係マッピング)です。

Laravel 5

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

0グッド

0クリップ

投稿2017/10/03 09:32

編集2017/10/04 01:21

EloquentのPolymorphic RelationsでHogeとFugaを使い分けているデータがあるとします。

hoge

idnamenumber
1hoge0
```php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Hoge extends Model
{
public function base() { return $this->morphMany(Base::class, 'ref'); }

}

### fuga |id|name|text| |:--|:--| |1|fuga|a| ```php <?php namespace App; use Illuminate\Database\Eloquent\Model; class fuga extends Model { public function base() { return $this->morphMany(Base::class, 'ref'); } }

base

idref_idref_type
11Hoge
21Fuga
```php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Base extends Model
{
public function ref() { return $this->morphTo(); }

}

このとき、withメソッドを使わずBaseを得たときの挙動はこうなります。 ```php $base_list = Base::all(); // [ // ['id' => 1, 'ref_id' => 1, 'ref_type' => 'Hoge'], // ['id' => 2, 'ref_id' => 1, 'ref_type' => 'Fuga'] // ]

さらに、withを使うとこうなります。

php

1$base_list = Base::with(['ref'])->all(); 2// [ 3// ['id' => 1, 'ref_id' => 1, 'ref_type' => 'Hoge', 'ref' => [id => 1, 'name' => 'hoge', 'number' => 0]], 4// ['id' => 2, 'ref_id' => 1, 'ref_type' => 'Fuga', 'ref' => [id => 1, 'name' => 'fuga', 'text' => 'a']], 5// ]

ここまではいいのですが、例えばHogeにだけ新たにImageモデルのリレーションを加えたとします。

image

idhoge_idpath
11image.jpg

php

1<?php 2namespace App; 3use Illuminate\Database\Eloquent\Model; 4class Image extends Model 5{ 6 public function hoge() { 7 return $this->belongsTo(); 8 } 9}

Hoge(改変)

php

1<?php 2namespace App; 3use Illuminate\Database\Eloquent\Model; 4class Hoge extends Model 5{ 6 public function base() { 7 return $this->morphMany(Base::class, 'ref'); 8 } 9 public function images() { 10 return $this->hasMany(Image::class); 11 } 12}

このあと、HogeのImageも欲しいので以下のようにwithを書き直すとエラーになります。

php

1$base_list = Base::with(['ref', 'ref.images'])->all(); 2// Hogeにはimagesがあるが、Fugaにはimagesのリレーションがないのでエラー

当たり前だ、と言われればそれまでなのですが、「あったら取る」「なければnull、またはプロパティ自体が無い」状態のデータが取得したいのです。なんとか方法はないでしょうか。

試したこと

  • Hogeモデルのappendsにimageを加え、getImageAttributeを実装する

php

1class Hoge extends Model 2{ 3 public function base() { 4 return $this->morphMany(Base::class, 'ref'); 5 } 6 public function images() { 7 return $this->hasMany(Image::class); 8 } 9 protected $appends = ['images']; 10 public function getImagesAttribute($value) { 11 return $this->images; // なぜかここでimagesというattributeは無いとエラーになる。 12 // なお外部から$hoge->imagesとアクセスした場合はエラーにならない 13 } 14}

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

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

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

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

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

guest

回答2

0

自己解決

試した方法の「$appendsにimageを加える」で、なぜエラーになるのかをコードを追っていったところ、以下のコードを見つけました。

php

1// Illuminate\Database\Eloquent\Concerns\HasAttribute 2 3 public function getAttribute($key) 4 { 5 if (! $key) { 6 return; 7 } 8 9 // If the attribute exists in the attribute array or has a "get" mutator we will 10 // get the attribute's value. Otherwise, we will proceed as if the developers 11 // are asking for a relationship's value. This covers both types of values. 12 if (array_key_exists($key, $this->attributes) || 13 $this->hasGetMutator($key)) { 14 return $this->getAttributeValue($key); 15 } 16 17 // Here we will determine if the model base class itself contains this given key 18 // since we do not want to treat any of those methods are relationships since 19 // they are all intended as helper methods and none of these are relations. 20 if (method_exists(self::class, $key)) { 21 return; 22 } 23 24 return $this->getRelationValue($key); 25 }

このgetAttributeというメソッドはモデルに対し__getの呼び出し時に呼ばれるメソッドで、$appendsで加えたいプロパティ名と、リレーションのメソッド名が同一である場合、以下のifに引っかかってしまうようです。

php

1 if (method_exists(self::class, $key)) { 2 return; 3 }

なので、このgetAttributeの最後で呼ばれているgetRelationValueを直接呼べばいいんじゃないか?と思って試したところ、希望通りの動作をしました。

php

1class Hoge extends Model 2{ 3 public function base() { 4 return $this->morphMany(Base::class, 'ref'); 5 } 6 public function images() { 7 return $this->hasMany(Image::class); 8 } 9 protected $appends = ['images']; 10 public function getImagesAttribute($value) { 11 return $this->getRelationValue('images'); 12 } 13}

やはり多少面倒でもコードを追うことは大事だということをまた実感させられました。

投稿2017/10/04 01:15

編集2017/10/04 01:23
masaya_ohashi

総合スコア9206

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

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

masaya_ohashi

2017/10/04 02:15

嫌がらせでマイナスつけていくのやめてもらえませんかね…
guest

0

以下のように、一度対象のプロパティにアクセスすれば、強引に値を読み込ませることができ、以降はimageもtoArrayに含まれるようになりました。

php

1$base_list = Base::with(['ref'])->all(); 2foreach($base_list as $index => $base) { 3 if($base->ref_type == 'Hoge') { 4 $base->images; 5 } 6} 7// [ 8// ['id' => 1, 'ref_id' => 1, 'ref_type' => 'Hoge', 'ref' => [id => 1, 'name' => 'hoge', 'number' => 0, 'images' => [['id' => 1, 'hoge_id' => 1, 'path' => 'image.jpg']]]], 9// ['id' => 2, 'ref_id' => 1, 'ref_type' => 'Fuga', 'ref' => [id => 1, 'name' => 'fuga', 'text' => 'a']], 10// ]

とても泥臭いので、もう少しだけ他の方の意見を待ちたいと思います。

投稿2017/10/04 00:55

編集2017/10/04 01:22
masaya_ohashi

総合スコア9206

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問