Laravel polymorphic relationship scope by pivot field - laravel

I have the following polymorphic relationship:
// User.php
public function regions()
{
return $this->morphedByMany('App\Region', 'relationship')->withPivot('relationship_level');
}
public function groups()
{
return $this->morphedByMany('App\Group', 'relationship')->withPivot('relationship_level');
}
The pivot table is as follows:
id | user_id | relationship_id | relationship_type | relationship_level
1 | 12 | 8 | App\Region | master
2 | 18 | 12 | App\Group | fan
Is there any way (preferably as scope) where I can get every user who has level "master" when this user can have many relationship level to many relationship_type.

Using the existing relationships:
User::whereHas('groups', function ($query) {
$query->where('relationship_level', 'master');
})->orWhereHas('regions', function ($query) {
$query->where('relationship_level', 'master');
})->get();
Using a pivot model and a new relationship (faster):
class Relationship extends \Illuminate\Database\Eloquent\Relations\MorphPivot
{
//
}
class User extends Model
{
public function relationships()
{
return $this->hasMany(Relationship::class);
}
}
User::whereHas('relationships', function ($query) {
$query->where('relationship_level', 'master');
})->get();

Related

hasOneThrough Laravel Eloquent Relationship

I have 3 tabes categories, sub_categories & products
category table
---------------------
| id | category_name |
---------------------
sub_category table
--------------------------------------------
| id | category_id(FK) | sub_category_name |
--------------------------------------------
product table
-----------------------------------------------------------------
| id | sub_category_id(FK) | product_name | product_description |
-----------------------------------------------------------------
**How do I get product category name using hasOneThrough eloquent relationship ( or using any other relationship).
I tried this in product model **
public function category(){
return $this->hasOneThrough(
Category::class,
SubCategory::class
);
}
But it gives error: Unknown column 'sub_categories.product_id'
You can install this external package staudenmeir/belongs-to-through to add the relationship you need.
class Product extends Model
{
public function subCategory()
{
return $this->belongsTo(SubCategory::class);
}
public functoin category()
{
return $this->belongsToThrough(Category::class, SubCategory::class);
}
}
class SubCategory extends Model
{
public functoin category()
{
return $this->belongsTo(Category::class);
}
}
class Category extends Model
{
public function subCategories()
{
return $this->hasMany(SubCategory::class);
}
public functoin products()
{
return $this->hasManyThrough(Product::class, SubCategory::class);
}
}
If you need to access Category directly from Product, and want to use laravels functions like $product->category()->attach($category->id) etc, then you need this dependency to achieve that.
If you are ok with doing:
$product->subCategory->category;
// or
$product->subCategory->category()->attach($category->id);
Then you don't need the dependency and you can exclude the category relationship on the Product model.

laravel: How to get column related to another column in pivot table (3 column pivot)

I'm not sure how to phrase this question, but I need to do the following:
I have a pivot table with three columns user_id, account_id, role_id
So in my database if I have these rows on account_role_user (pivot)
|---------------------|------------------|-------------
| account_id | user_id | role_id |
|---------------------|------------------|-------------
| 1 | 1 | 1 |
|---------------------|--------------------------------
| 2 | 2 | 1 |
------------------------------------------------------
| 1 | 2 | 3 |
------------------------------------------------------
Role - 1 = owner
Role - 3 = manager
What I'm trying to do is get users on a specific account with their specific role. But I'm only able to query things like App\User::with('accounts.roles')->whereId(2)->first(); which does show the users on an account, but it groups their roles that aren't specific to the account.
I only want the users and their roles that are relevant to the account.
If I'm querying account with id of 1 and I want to list users on that account with their role, I should have something like:
$account = App\Account::find(1)
User with ID of 1 has a role id of 1 on the account id of 1
User with ID of 2 has a role id of 3 on the account id of 1
User Model:
public function accounts() {
return $this->belongsToMany('App\Account', 'account_role_user', 'user_id', 'account_id');
}
public function roles() {
return $this->belongsToMany('App\Role', 'account_role_user', 'user_id', 'role_id');
}
Account model:
public function users() {
return $this->belongsToMany('App\User', 'account_role_user', 'account_id', 'user_id');
}
public function roles() {
return $this->belongsToMany('App\Role', 'account_role_user', 'account_id', 'role_id');
}
Role Model:
public function users() {
return $this->belongsToMany('App\User', 'account_role_user', 'role_id', 'user_id');
}
public function accounts() {
return $this->belongsToMany('App\Account', 'account_role_user', 'role_id', 'account_id');
}
Thanks to someone's help on Laravel's Discord channel, I figured this out.
On the Account Model, I changed the users() relation to:
public function users() {
return $this->belongsToMany('App\User', 'account_role_user')
->using('App\AccountRoleUser')
->withPivot('role_id');
}
I created a pivot model called AccountRoleUser
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class AccountRoleUser extends Pivot
{
public function role() {
return $this->belongsTo('App\Role');
}
}
And on the User model, I changed the accounts() relation to:
public function accounts() {
return $this->belongsToMany(Account::class, 'account_role_user')->withPivot('role_id');
}
Now my query is really succinct and logical:
$account = auth()->user()->accounts->where('foo', 'bar')->first();
$users = $account->users;
Each User inside the collection has a pivot object now coming from the pivot model.
Which means I can now do something like:
#foreach ($users as $user)
<p>This is user {{ $user->first_name }} {{ $user->last_name }} with a role of
{{$user->pivot->role->description}}
</p>
#endforeach

Override primary key with foreign key in hasMany relation using laravel

Here are my tables
Posts
id | name | created_At
Comments
id | comment | post_id | created_at
Post Model
function comments(){
return $this->hasMany('App\Models\Comment','id','post_id');
}
PostsController
function index()
{
Post::with('comments')::get();
}
Now how can i get list of all posts along with comments?
I am trying to match post_id in the child table.
In Your Post Model:
public function comments()
{
return $this->hasMany('App\Model\Comment');
}
In Your Post Controller :
use Illuminate\Http\Request;
function index(Request $request)
{
$posts=Post::with('comments')->get();
// in json
return response()->json($posts);
// in your view
//return view('viewname')->with('posts',$posts);
}

Laravel Eloquent: multiple foreign keys for relationship

I am in the process of porting a project to Laravel.
I have two database tables which are in a One-To-Many relationship with each other. They are joined by three conditions. How do I model this relationship in Eloquent?
I am not supposed to modify the database schema, since it has to remain backwards compatible with other things.
I have tried the following, but it doesn't work.
The owning side:
use Illuminate\Database\Eloquent\Model;
class Route extends Model
{
public function trips()
{
return $this->hasMany('Trip', 'route_name,source_file', 'route_name,source_file')
}
}
The inverse side:
use Illuminate\Database\Eloquent\Model;
class Trip extends Model
{
public function routes()
{
return $this->belongsTo('Route', 'route_name,source_file', 'route_name,source_file');
}
}
Example Route database values:
id | route_name | source_file
---------------------------------------
1 | Berlin - Paris | file1.xls
2 | Madrid - London| file2.xls
3 | Berlin - Paris | file3.xls
Example Trip database values:
id | route_name | source_file | duration
---------------------------------------------------------
1 | Berlin - Paris | file1.xls | 78
2 | Madrid - London | file2.xls | 241
3 | Berlin - Paris | file3.xls | 65
1 | Berlin - Paris | file1.xls | 95
1 | Berlin - Paris | file1.xls | 65
Route and Trip have other attributes, which I did not include here for brevity.
Is this possible in Eloquent?
I had to deal with a similar problem. The solution provided by #fab won't work with eager loading because $this->source_file would be null at the time the relationship is processed. I came up with this solution
After installing Compoships and configuring it in your models, you can define your relationships matching multiple columns.
The owning side:
use Illuminate\Database\Eloquent\Model;
use Awobaz\Compoships\Compoships;
class Route extends Model
{
use Compoships;
public function trips()
{
return $this->hasMany('Trip', ['id', 'route_name', 'source_file'], ['route_id', 'route_name', 'source_file']);
}
}
The inverse side:
use Illuminate\Database\Eloquent\Model;
use Awobaz\Compoships\Compoships;
class Trip extends Model
{
use Compoships;
public function route()
{
return $this->belongsTo('Route', ['route_id', 'route_name', 'source_file'], ['id', 'route_name', 'source_file']);
}
}
Compoships supports eager loading.
As Jonathon already mentioned, you could try to add an where-clause to your relationship:
use Illuminate\Database\Eloquent\Model;
class Route extends Model
{
public function trips()
{
return $this->hasMany('Trip', 'route_name')->where('source_file', $this->source_file);
}
}
The inverse side:
use Illuminate\Database\Eloquent\Model;
class Trip extends Model
{
public function routes()
{
return $this->belongsTo('Route', 'route_name')->where('source_file', $this->source_file);
}
}
How i would tackle this would be to do something like this
class A
{
public function b1()
{
return $this->hasMany('B', 'prop1', 'prop1')
}
public function b2()
{
return $this->hasMany('B', 'prop2', 'prop2')
}
public function b3()
{
return $this->hasMany('B', 'prop3', 'prop3')
}
public function getBsAttribute()
{
$data = collect([$this->b1, $this->b2, $this->b3]);
return $data->unique();
}
}
Collecting all the single relations and returning them as unique collection, and obviously doing the same for the inverse, this should give you some data to work with.
OP was modified so no longer relevant, left in if any one needs an answer similar

Laravel 5.2 relationships: Trying to get property of non-object

I have two models: Term and Post.
The Term model represents both categories and tags.
A post can belong only to a category and it can have many tags (I use the same db table for categories and tags).
class Term extends Model
{
protected $table = 'mydb_terms';
public $timestamps = true;
public function getRouteKeyName() {
return 'slug';
}
public function posts(){
return $this -> hasMany('Post');
}
}
class Post extends Model
{
use SoftDeletes;
protected $table = 'mydb_posts';
public $timestamps = true;
public function category(){
return $this -> belongsTo('Term','mydb_posts_terms', 'post_id', 'term_id')
-> withPivot('order') -> withTimestamps() -> where('type','category');
}
public function tags(){
return $this -> hasMany('Term') -> where('type','tag');
}
}
In the CategoryController I have:
class CategoryController extends Controller
{
public function getPostsOfCategory($id)
{
$posts = Term::find($id)->posts->get();
}
public function getPostsOfAllCategories()
{
//
}
}
When I try to retrieve the posts of category event with slug event (in the db the category and one post in it exist, and also the corresponding row in mydb_posts_terms) I obtain
Trying to get property of non-object
EDIT
I tried both $posts = Term::find($id)->posts()->get(); by obtaining Call to a member function and $posts = Term::find($id)->posts; by obtaining the same Trying to get property of non-object.
In the db I have:
Table mydb_terms:
| id | name | slug | type | created_at | updated_at
| 1 | event | event | category | 2016-07-01 18:00:00| 2016-07-01 18:00:00
Table mydb_posts:
| id | title | content | created_at | updated_at
| 1 | A title | a content | 2016-07-04 17:20:12| 2016-07-04 17:20:12
Table mydb_posts_terms:
| post_id | term_id | order | created_at | updated_at
| 1 | 1 | 0 | 2016-07-06 14:13:43| 2016-07-06 14:13:43

Resources