Laravel 5.2 eager loading deep nested relations - php

I would like to chain some models together as following:
ContentBlock > Template > TemplateFields > FieldValue
Models:
class ContentBlock extends Model {
public function template() {
return $this->hasOne('\App\Models\Template', 'id', 'template_id');
}
}
class Template extends Model {
public function templateFields() {
return $this->hasMany('\App\Models\TemplateField', 'template_id');
}
}
class TemplateField extends Model {
public function fieldValue() {
return $this->hasOne('\App\Models\FieldValue', 'field_id');
}
}
Controller:
$contentBlock = \App\Models\ContentBlock::with('template.templateFields.fieldValue')->find(1);
dd($contentBlock->template->templateFields());
// This works
Now, i can go as deep as templateFields()
But if i go one relation further, i get 'BadMethodCallException in Macroable.php line 74: Method fieldValue does not exist'
dd($contentBlock->template->templateFields->fieldValue());

Related

Touching Eloquent model via polymorphic relationship

Laravel 5.7. I have two models, Foo and Content. Their relationship is polymorphic because Content can also be related to other models:
class Foo extends Model
{
public function contents()
{
return $this->morphToMany('App\Content');
}
}
class Content extends Model
{
use LastModified;
public function foos()
{
return $this->morphedByMany('App\Foo');
}
}
I want to touch the Foo model whenever the Content model is updated. So I use a LastModified trait for the Content model:
trait LastModified
{
protected static function bootLastModified()
{
static::updating(function ($model) {
static::updateLastModified($model);
});
}
protected static function updateLastModified($model)
{
$foos = $model->foos;
if (count($foos) > 0) {
foreach ($foos as $foo) {
$foo->touch();
}
}
}
}
My problem is that $model->foos returns the correct Foo models, but with the wrong ids. Instead of the Foo's own model id, each Foo has the id of the pivot table row. This means that the wrong Foo row is touched.
Laravel has built-in functionality for touching parent timestamps.
On the content model, you can add a property telling which relationships should be touched when the given model is updated.
The following should work:
class Content extends Model
{
protected $touches = ['foos'];
public function foos()
{
return $this->morphedByMany('App\Foo');
}
}
Edit: Since you are using a static updated event you should manually call $model->touchOwners() from the static::updated

Loading Laravel Model with hasMany relation data

I have two models:
class Parent extends Model {
public function children(){
return $this->hasMany(Child::class);
}
}
class Child extends Model {
public function parent(){
return $this->belongsTo(Parent::class);
}
}
When I run the following:
$parent = Parent::with(Child::class)->find(1);
I get the following error:
Call to undefined method Illuminate\Database\Query\Builder::child()
Any thoughts on this?

relations null in laravel 5.5

I'm trying to make relationship between 2 tables:
My models:
class Modele extends Model
{
public function shoe()
{
return $this->hasMany('Shoe');
}
}
class Shoe extends Model
{
public function modele()
{
return $this->belongsTo(Modele::class, 'IdModele','id');
}
}
my Controler:
class shoeController extends Controller
{
public function index()
{
$shoesList= \App\Shoe::with('modele')->orderBy('idModele')->get();
return view('shoe.index',compact('shoesList'));
}
}
When I dd($shoeList) , I have this:
#relations: array:1 [▼
"modele" => null
]
and if I try to use the params in blade like this:
<p>{{$shoe->modele->idGender}}</p>
Ihave this error:
ErrorException thrown with message "Trying to get property of non-object (View: C:\laragon\www\ipepsShoes2017\resources\views\shoe\index.blade.php)
I have make other relations between tables in this project with using the same way and they'r working fine.
I don't understand why it doesn't work.
Thank you.
try this
class Modele extends Model
{
public function shoe()
{
return $this->hasMany('App\Shoe');
}
}
class Shoe extends Model
{
public function modele()
{
return $this->belongsTo('App\Modele', 'IdModele','id');
}
}
in your view first check {{print_r($shoe->modele)}} if you get object then call param what you need
Try to write a foreign key for hasMany relation to Modele Model:
class Modele extends Model
{
public function shoe()
{
return $this->hasMany('Shoe', 'IdModele');
}
}
Hope it help you :)

Laravel DRY nested eager loading

Suppose I got a model with a few relations:
class Author extends Model
{
public function shortStories()
{
return $this->hasMany(ShortStory::class);
}
public function essays()
{
return $this->hasMany(Essay::class);
}
public function books()
{
return $this->hasMany(Book::class);
}
}
Now suppose I got two more models that want to eager load this model with its relations:
class Publisher extends Model
{
public function scopeWithAuthor($query)
{
$query->with('author.shortStories', 'author.essays', 'author.books');
}
}
class Reviewer extends Model
{
public function scopeWithAuthor($query)
{
$query->with('author.shortStories', 'author.essays', 'author.books');
}
}
Problem - if the relations of author change I now need to reflect this in multiple locations.
My question - how do I achieve this in DRY style?
I know that I could add a protected $with to the Author class but then it would always load the relation, not just when required.
With that in mind, one solution I have come up with is to extend the Author model like so:
class AuthorWithRelations extends Author
{
protected $with = ['shortStories', 'essays', 'books'];
}
This then allows me to refactor the scopes of the other models like so:
class Publisher extends Model
{
public function scopeWithAuthor($query)
{
$query->with('authorWithRelations');
}
}
class Reviewer extends Model
{
public function scopeWithAuthor($query)
{
$query->with('authorWithRelations');
}
}
This works well enough but really I was wondering if Laravel provides a better / inbuilt approach to this?

information about related models in Laravel

Hello I´m writing an API and I want to display more information about the related model.
Routes.php
Route::resource('makes', 'MakesController');
MakesController.php
class MakesController extends Controller
{
public function index()
{
$data = Make::all();
return response()->json($data);
}
}
This returns only information about the makes (id, name)
but how can I display also how many models has each make?
I have defined these two models
class Make extends Model
{
public function models()
{
return $this->hasMany('App\CarModel');
}
}
class CarModel extends Model
{
public function make()
{
return $this->belongsTo('App\Make');
}
}
You can define $visible field in the Make model's class like this:
protected $visible = ['models'];
This will automatically appends the related model's array to array/json.
You can also use an optional way with makeVisible method:
class MakesController extends Controller
{
public function index()
{
$data = Make::all();
return response()->makeVisible('models')->json($data);
}
}

Categories