laravel eloquent relationship for indirectly related model - laravel

I want a relationship where two unrelated models are linked together with a linker model.
My tables are like:
card table
id(pk)
name
User table
id(pk)
username
password
card_id(fk)
Feature table
id(pk)
name
card_id(fk)
How can i define an eloquent relationship to access all the features of user's card from user model like this:
class User extends Model
{
use HasFactory;
public function features(){
return $this->relatonship_statement;
}
}
and when I tried in Card Model:
class Card extends Model
{
use HasFactory;
public function features(){
return $this->hasMany(Feature::class);
}
}
and in User model:
class User extends Model
{
use HasFactory;
public function card(){
return $this->belongsTo(User::class);
}
public function features(){
return $this->card->features;
}
}
I get error:
App\Models\User::features must return a relationship instance.

What you really want is an accessor function, not a relationship. This is how you would do to achieve what you want.
class User extends Model
{
use HasFactory;
protected $appends = ['features']; //to append features in the response json
public function card(){
return $this->belongsTo(Card::class); //editted User to Card
}
public function getFeatures(){ //accessor method
return $this->card->features()->get();
}
}
sample result after returning user in a controller function
return User::query()->with('card')->first();
However, the right way is to access the features through the Card Relationship because these two models have a direct relationship.

Related

one to many relationship laravel with multiple foreign key

I am on a project with Laravel.
I have two database tables that 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 backward 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');
}
}
I don't want to use "use Awobaz\Compoships\Compoships;"
You need to give hasMany() and belongsTo method the namespace of your models.
Something like 'App\Models\Trip' or Trip::class
class Route extends Model
{
public function trips()
{
return $this->hasMany('App\Models\Trip', 'route_name,source_file', 'route_name,source_file')
}
}
class Trip extends Model
{
public function routes()
{
return $this->belongsTo('App\Models\Route', 'route_name,source_file', 'route_name,source_file');
}
}

Laravel: How to define belongsTo in a MorphPivot?

In my project there is a Many-to-Many polymorphic relationship (Many instances of a model called Package (morphedByMany) can contain many different content types (each MorphedToMany).
I've created a pivot table containing some additional fields that I'll need to access and query by, and so I've decided that the best thing would be to create a Pivot model by extending the MorphPivot.
Querying is now easy enough, however, I can't access the content through a relation (which I can do if i query the App\Packages::findOrFail(1)->contentType()). I know I should declare that the pivot belongsTo the contentType, but I'm not sure how to go about it seeing as it could belong to any of the morphed contentTypes.
EDIT
Code blocks as requested
Content1
class Song extends Model
{
public function packages()
{
return $this->morphToMany('App\Package', 'packageable')->withPivot('choice')->using('App\PackageContent');
}
Content2
class Video extends Model
{
public function packages()
{
return $this->morphToMany('App\Package', 'packageable')->withPivot('choice')->using('App\PackageContent');
}
Package
class Package extends Model
{
public function songs()
{
return $this->morphedByMany('App\Song', 'packageable')->withPivot('choice')->using('App\PackageContent');
}
public function videos()
{
return $this->morphedByMany('App\Video', 'packageable')->withPivot('choice')->using('App\PackageContent');
}
MorphPivot
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\MorphPivot;
class PackageContent extends MorphPivot
{
protected $table = 'packageables';
Pivot table migration
public function up()
{
Schema::create('packageables', function (Blueprint $table) {
$table->integer('package_id');
$table->integer('packageable_id');
$table->string('packageable_type');
$table->integer('choice');
});
}

Laravel Role HasMany relationship

I have a User Model and a Role Model which are in many-to-many relation.
I have two roles: admin and manager.
I also have an Order Model. Managers need to have many orders. Where do I state such relations? Do I have to state it in the User Class?
Do I need to create separate models for Admins and Managers?
Managers & admins are a subset of your users, defined by their roles.
Therefore, we'll use scope to filter users who are managers by their roles.
App\Scopes\ManagerUserScope.php
<?php
namespace App\Scopes;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
class ManagerUserScope implements Scope
{
/**
* Apply the scope to a given Eloquent query builder.
*
* #param \Illuminate\Database\Eloquent\Builder $builder
* #param \Illuminate\Database\Eloquent\Model $model
* #return void
*/
public function apply(Builder $builder, Model $model)
{
//Assuming Your user has a relationship (has many) role
$builder->whereHas('role', function($roleQuery) {
//Assuming that in the role table, the manager role entry has ID 1
$roleQuery->where('id','=',1);
});
}
}
Then, we extend the User model to create a manager model which has the above scope automatically applied.
App\Models\Manager.php
namespace App\Models;
use App\Scopes\ManagerUserScope;
class Manager extends User {
/**
* The "booting" method of the model.
*
* #return void
*/
protected static function boot()
{
parent::boot();
static::addGlobalScope(new ManagerUserScope);
}
/**
* Relationship: Orders (Has many)
*/
public function orders()
{
return $this->hasMany('orders');
}
}
Your many-to-many relationship between User and Role can be perfectly described with belongsToMany Eloquent relation methods both ways. Also since each Order must have responsible manager for it we also have one-to-many relation between Manager and Order which will be described with hasMany/belongsTo methods.
So, your User model will have:
public function roles()
{
return $this->belongsToMany('App\Role');
}
public function orders()
{
return $this->hasMany('App\Order');
}
For your Role model:
public function users()
{
return $this->belongsToMany('App\User');
}
And lastly your Order model:
public function manager()
{
return $this->belongsTo('App\User');
}
There is no need to create a certain limitations (like "only users with role manager can have orders") on DB schema level, it's easier to implement in the code. So, for example, you might want to implement a method that will assign order to user and check his roles first.

How to get access to relationship in model User Laravel?

I have default User model:
class User extends Authenticatable implements HasRoleContract
{
use Notifiable, HasRole;
}
With one relationship inside:
public function distributor() {
return $this->hasOne('App\DistributorContacts', 'distributor_id', 'id');
}
So, when user passed authorization I can not see this relation in object:
{{dd(Auth::user())}}
you may use ->with('distributor') on your user Object to get relationships loaded.
e.g.
$user = new User()->with('distributor');
dd($user->distributor);
or
Auth::user()->with('distributor');

Eloquent ORM relationships one-to-one or one-to-many?

I see the power of using Eloquent but have yet to put it to good use in my project. With two tables I want to achieve this:
//output - LinkedIn
echo User::find(42)->SocialProvider->Name
I have a user table and I have a SocialProvider table with a list of social sites with their name and api key info.
Record 42 in my user's table has a column 'SocialProviderID' with the the id of the LinkedIn record in my SocialProvider table.
I have defined the relationships in model classes as following
class User extends BaseModel implements UserInterface, RemindableInterface {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'dbo_RegisteredUser';
protected $primaryKey = "UserID";
public function SocialProvider() { return $this->hasOne('SocialProvider','id'); }
AND
class SocialProvider extends Eloquent {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'dbo_SocialProvider';
public function user() { return $this->belongsTo('User','SocialProviderID'); }
But the queries and results are not executing as I'd like.
Does anyone have an ideas?
I'm using MSSQL but in my more familiar MYSQL, I would like this ORM scenario to perform a join like this:
SELECT * FROM dbo_RegisteredUser
LEFT JOIN (dbo_SocialProvider)
ON (dboRegisteredUser.SocialProviderID=dbo_SocialProvider.id)
WHERE dbo_RegisteredUser.UserID=42
Thanks
Jon.
Ahh I figured it out with a bit of debugging. I specified the relationships incorrectly.
In my User model I needed
class User extends Eloquent implements UserInterface, RemindableInterface {
public function socialProvider() {
return $this->belongsTo('SocialProvider','SocialProviderID');
}
Well...relationships use the ID of the model in question....and you're not referencing the actual user anywhere...
You need to have a collumn in the social Provider table that stores the user_id
Then in your functions...
public function SocialProvider() { return $this->hasOne('SocialProvider','user_id'); }
and...
public function user() { return $this->belongsTo('User'); }

Resources