Make conditional Eloquent relationship in Laravel - php

Laravel 5.7. I have an Eloquent model Theme, with two fields, id and name.
Another model, Filter, has three fields: id, name, theme_id.
Filter:
class Filter extends Model
{
public function theme()
{
return $this->belongsTo('App\Theme');
}
}
I can attach these filters to an arbitrary number of other models, e.g. the model Foo has two fields, id and name. I attach the filter to it using a Filterables table:
Filterables:
id | filter_id | filterable_id | filterable_type
------------------------------------------------
1 | 1 | 3 | App\Foo
The above example shows that the Filter of id 1 is attached to the Foo of id 3.
Now to get all the filters of Foo, I have this relationship in my Foo model:
Foo:
class Foo extends Model
{
public function filters()
{
return $this->morphToMany('App\Filter', 'filterable');
}
}
This all works fine. But now I want to get the Foo model, and only the filters where the filter's theme_id is (for example) 1.
How can I add this condition to the filters relationship?

Just add a where clause directly to your relationship
class Foo extends Model
{
public function filters()
{
return $this->morphToMany('App\Filter', 'filterable')->where('theme_id', 1);
}
}

Related

Explain Eloquent morphMany parameters

I am new to laravel, can someone explain to me the parameters of morphMany:
$this->morphMany(Photo::class, 'imageable');
The MorphMany relationship has the following function signature:
public function morphMany($related, $name, $type = null, $id = null, $localKey = null)
{
//
}
Where:
$related (required): refers to the related model. e.g: User::class.
$name (required): the name of the polymorphic relation, like commentable.
$type (optional): customize the {relation}_type field to look up when doing a query.
$id (optional): customize the {relation}_id field to look up when doing a query.
$localKey (optional): customize the local key (by default id) to search when doing a query.
So -using the example shown in the Laravel documentation- if you want to use a different table structure for the comments table from this:
posts
id - integer
title - string
body - text
videos
id - integer
title - string
url - string
comments
id - integer
body - text
commentable_id - integer
commentable_type - string
to this:
posts
id - integer
title - string
body - text
videos
id - integer
title - string
url - string
comments
id - integer
body - text
foo - integer // the index to look
bar - string // the type to match
You'd need to define your relationships like this:
Post.php
public function comments()
{
return $this->morphMany(Comment::class, 'commentable', 'foo', 'bar');
}
Video.php
public function comments()
{
return $this->morphMany(Comment::class, 'commentable', 'foo', 'bar');
}
Comment.php
public function commentable()
{
return $this->morphTo('commentable');
}
Check this other answer.
Polymorphic Relations
Table Structure
Polymorphic relations allow a model to belong to more than one other model on a single association. For example, imagine users of your application can "comment" on both posts and videos. Using polymorphic relationships, you can use a single comments table for both of these scenarios. First, let's examine the table structure required to build this relationship:
posts
id - integer
title - string
body - text
videos
id - integer
title - string
url - string
comments
id - integer
body - text
commentable_id - integer
commentable_type - string
Two important columns to note are the commentable_id and commentable_type columns on the comments table. The commentable_id column will contain the ID value of the post or video, while the commentable_type column will contain the class name of the owning model. The commentable_type column is how the ORM determines which "type" of owning model to return when accessing the commentable relation.
Model Structure
Next, let's examine the model definitions needed to build this relationship:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
/**
* Get all of the owning commentable models.
*/
public function commentable()
{
return $this->morphTo();
}
}
class Post extends Model
{
/**
* Get all of the post's comments.
*/
public function comments()
{
return $this->morphMany('App\Comment', 'commentable');
}
}
class Video extends Model
{
/**
* Get all of the video's comments.
*/
public function comments()
{
return $this->morphMany('App\Comment', 'commentable');
}
}
Retrieving Polymorphic Relations
Once your database table and models are defined, you may access the relationships via your models. For example, to access all of the comments for a post, we can use the comments dynamic property:
$post = App\Post::find(1);
foreach ($post->comments as $comment) {
//
}
You may also retrieve the owner of a polymorphic relation from the polymorphic model by accessing the name of the method that performs the call to morphTo. In our case, that is the commentable method on the Comment model. So, we will access that method as a dynamic property:
$comment = App\Comment::find(1);
$commentable = $comment->commentable;
The commentable relation on the Comment model will return either a Post or Video instance, depending on which type of model owns the comment.
See this link: polymorphic-relations:
You can entry like that:
+---------+----------------+-------------------+
| user_id | commentable_id | commentable_type |
+---------+----------------+-------------------+
| 1 | 1 | App\Post |
| 1 | 2 | App\Post |
| 1 | 3 | App\Post |
| 1 | 1 | App\Video |
| 1 | 2 | App\Video |
| 1 | 3 | App\Video |
+---------+----------------+-------------------+

Laravel 5.6 Model HasManyThrough Relationships of 3 Tables

How to make a relationship between 3 tables of Laravel
+---------------+ +---------------+ +-------------------+
| venue_images | | transactions | | image_transaction |
+---------------+ +---------------+ +-------------------+
| id | | id | | venue_image_id |
| user_id | | user_id | | transaction_id |
+---------------+ +---------------+ +-------------------+
Here's my code but it's not working.
class Transaction extends Model
{
public function images(){
return $this->hasManyThrough(ImageTransaction::class ,VenueImage::class, 'transaction_id', 'id');
}
}
I want to join the three tables using transaction id and venue image id
on my controller
$transactions = transaction::where('user_id', Auth::id())->with('images')->get();
If I don't misunderstood your question you have a pivot table image_transaction which is many-to-many relationship. Eloquent automatically arrange pivot table's name alphabetically like transactions_venue_image so you need to pass your custom name image_transaction in the parameter. [docs]
In your VenueImage Model
public function transactions()
{
return $this->belongsToMany('App\Transaction','image_transaction');
}
In your Transaction Model
public function venue_images()
{
return $this->belongsToMany('App\VenueImage','image_transaction');
}
There are also 3rd and 4th parameters which are foreign keys of the related model which are explained better in the docs.
In your Controller
$transactions = transaction::where('user_id', Auth::id())->with('venue_images')->get();
The order of the parameters to the hasManyThrough function looks wrong. According to the Laravel documentation
The first argument passed to the hasManyThrough method is the name of the final model we wish to access, while the second argument is the name of the intermediate model.
So in your case it should be like this (without defining the foreign keys)
class Transaction extends Model
{
public function images() {
return $this->hasManyThrough(VenueImage::class, ImageTransaction::class);
}
}
If this does not work try to include the keys as described in the documentation:
Typical Eloquent foreign key conventions will be used when performing the relationship's queries. If you would like to customize the keys of the relationship, you may pass them as the third and fourth arguments to the hasManyThrough method. The third argument is the name of the foreign key on the intermediate model. The fourth argument is the name of the foreign key on the final model. The fifth argument is the local key, while the sixth argument is the local key of the intermediate model.
You should try this:
class Transaction extends Model
{
public function images(){
return $this->belongsToMany(ImageTransaction::class ,VenueImage::class, 'transaction_id', 'id');
}
}

Laravel variable model polymorphic

I have a table as follows in my database:
table area_blocks;
id
owner_type
owner_id
created_at
updated_at
in the owner_type field it has the Eloquent Model name and the owner_id is the id of that model in the database. Example:
db: area_blocks
id | owner_type | owner_id
1 | App\Models\Title | 3
2 | App\Models\Title | 4
3 | App\Models\Textarea | 1
So I'm expecting when I fetch all of these to also eager load the relevant field from the eloquent model stored in owner_type.
Is there an eloquent relationship that can bring back that record from the owner_type field using eager loading? I've tried $this->morphTo(), e.g.
public function block()
{
return $this->morphTo();
}
but that is returned as null. Any ideas how this can be done?
Example code;
<?php
namespace App\Models;
use Cviebrock\EloquentSluggable\Sluggable;
use Illuminate\Database\Eloquent\Model;
class AreaBlocks extends Model
{
protected $with = ['block'];
public function block()
{
return $this->morphTo();
}
}
Route::get('/', function(){
return App\Models\AreaBlocks::all();
});
You have to specify the column name/prefix:
public function block()
{
return $this->morphTo('owner');
}
Or rename the relationship:
public function owner()
{
return $this->morphTo();
}

Relationship between two tables in Eloquent (Laravel) based on a secondary table

Maybe I don't know the terminology for this, but I'm trying to create a HasMany relationship between Person and Car object.
Person:
id | user_name | created_at ....
Car:
id | make | model | year ...
Person_Car:
car_id | person_id
So obivously the relationship is defined by linking through the Person_Car relationship. Maybe I'm brain farting but I've forgotten what that this relationship is called and how to define Person as hasMany Cars
What's the name of the relationship and how can I define it in a Laravel Eloquent object?
Car class:
public function persons()
{
return $this->belongsToMany(Person::class);
}
Person class:
public function cars()
{
return $this->belongsToMany(Cars::class);
}
https://laravel.com/docs/5.6/eloquent-relationships#many-to-many
Use many to many relationship https://laravel.com/docs/5.6/eloquent-relationships#many-to-many
Car.php
public function persons()
{
return $this->belongsToMany('App\Car', 'Person_Car');
}

Laravel 5.4 | Fetching data from Pivot Table

I have 4 tables in my database:
Table 1: Category
---|------
id | name
---|------
1 | Cars
In 'Category' model class I have defined the following relationship:
class Category {
public function fields() {
return $this->belongsToMany('App\Field');
}
}
Table 2: Field
id | name
---|-------
1 | Make
In 'Field' model class I have defined the following relationship:
class Field {
public function categories() {
return $this->belongsToMany('App\Category');
}
}
Table 3: Field_Options
field_id | value
---------|-------
1 | Audi
1 | BMW
In 'FieldOption' model class I have defined the following relationship:
class FieldOption extends Model
{
public function field() {
return $this->belongsTo('App\Field');
}
}
Table 4: Category_Field
category_id | field_id
------------|-------
1 | 1
Now I need to fetch all the fields and field_options for category_id=1. How can I achieve this using Laravel?
Thanks!
First define relationship between Field and FieldOptions
public function options() {
return $this->hasMany('App\FieldOption');
}
Then you can eager load all relationships like this
$category = Category::with('fields.options')->find(1);
//Get category 1, with all fields and their respectif fieldOptions

Categories