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

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'); }

Related

laravel eloquent relationship for indirectly related model

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.

How to filter User by role based on the called Model?

I'm using Laratrust to manage these roles:
Patient
Doctor
I've a class called User which is the main entity, then I have a specific class for each role: Patient and Doctor.
Problem
To retrieve a list of users with the role of doctor I have to write:
User::whereRoleIs('doctor')->get();
The problem's that I have defined some relationship within the class Doctor, eg:
<?php
namespace App\Models;
use App\Models\Boilerplate\User;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Doctor extends User
{
use HasFactory;
protected $table = 'users';
public function patients()
{
return $this->belongsToMany(Patient::class, 'invites', 'doctor_id', 'user_id');
}
}
and I cannot access to the relationship patients from the User model.
Is there a way to call Doctor:with('patients')->get() and return automatically the users which have the role of Doctor?
So if I type: Doctor:all() the result must be equal to User::whereRoleIs('doctor')->get()
How can I do this?
Splitting data like this by model isn't really the intended use for models. Models in Laravel contain data on a per-table basis. In order to achieve what you want I would either make a DocterService that has methods in it to retrieve docter users by calling User::whereRoleIs('doctor') or just use this method straight away.
If you really want to use the model though you can use scopes. (https://laravel.com/docs/9.x/eloquent#query-scopes) Create a new scope that includes the whereRoleIs('doctor') method
<?php
namespace App\Scopes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
class DoctorScope 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)
{
$builder->whereRoleIs('doctor');
}
}
and apply it to the model by adding the following to the model:
/**
* The "booted" method of the model.
*
* #return void
*/
protected static function booted()
{
static::addGlobalScope(new DoctorScope);
}

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 : delete rows from multiple table with same id

I am a bit new to Laravel. I am trying to delete a project from a table along with its images and plans from 2 other tables. How to do this in Laravel Eloquent?
Here is the delete controller of the project:
public function destroy($id)
{
$project = Projects::findOrFail($id);
$project->delete();
return Redirect::to('admin/view-project')->with('message', 'Project deleted successfully');
}
How can I get this to be done from the model? I didn't understand that.
Here is the Projects model:
class Projects extends Eloquent implements UserInterface, RemindableInterface
{
use UserTrait, RemindableTrait;
protected $table = 'project_info_arabic';
public function projectImages()
{
return $this->hasMany('ProjectsImage');
}
public function projectPlans()
{
return $this->hasMany('ProjectsPlans');
}
}
Can kindly anybody help?
The better way when thinking about data consistency is the implementation of foreign keys on the database layer. That does it automatically for you and you don't need to think about it anymore.
See https://laravel.com/docs/5.3/migrations#foreign-key-constraints
You could try model events in laravel.Check this
class Projects extends Eloquent implements UserInterface, RemindableInterface
{
public static function boot()
{
parent::boot();
Projects::deleted(function($project)
{
$project->projectImages()->delete();
$project->projectPlans()->delete();
});
}
}

Resources