Laravel - How to do referenctial integrity with where clause - laravel

In Laravel-8, I have this models:
Licence:
protected $fillable = [
'id',
'number',
'employee_id',
'is_active',
];
public function employee()
{
return $this->belongsTo(Employee::class,'employee_id','id');
}
Employee:
protected $fillable = [
'id',
'first_name',
'last_name',
'other_name',
];
public function licences()
{
return $this->hasMany(DriverLicence::class);
}
Employee can have more than one licence. But only one can be active.
I have this in the controller:
$employee = Employee::with('licences')->get();
How do I add where clause in the referential integrity that it should be licence where is_active is 1?
Thank

you can use whereHas() to use condition in relation model.
$employee = Employee::with('licences')
->wherehas('licences',function($q){
$q->where('is_active',1);
})
->get();
You can also do by adding relation and condition to get active licence
public function activeLicence()
{
return $this->hasOne(DriverLicence::class,'employee_id')->where('is_activce',1);
}
You can access active licence as below:
$employee->activeLicence;

Related

Laravel complexe relationships

I need help please, to figure out for convenient ways to link between User/Staff/Parent/Student.
A Staff/Parent/Student is a user.
A Staff can be a Parent too. Similarly, a Parent may be a Staff too.
A student belongsToMany Parent, and a Parent belongsToMany Student.
Here are the models I've created :
App\Models\Student.php
protected $fillable = [
'name',
'email',
'student_user_id',
'created_at',
'updated_at',
'deleted_at',
];
public function student_user()
{
return $this->belongsTo(User::class, 'student_user_id');
}
public function guardians()
{
return $this->belongsToMany(StudentGuardian::class);
}
==========================================================
App\Models\StudentGuardian.php
protected $fillable = [
'name',
'email',
'guardian_user_id',
'is_staff',
'guardian_staff_id',
'created_at',
'updated_at',
'deleted_at',
];
public function students()
{
return $this->belongsToMany(Student::class);
}
public function guardian_user()
{
return $this->belongsTo(User::class, 'guardian_user_id');
}
public function guardian_staff()
{
return $this->belongsTo(Staff::class, 'guardian_staff_id');
}
=====================================
App\Models\Staff.php
protected $fillable = [
'name',
'email',
'staff_user_id',
'staff_guardian_id',
'is_student_guardian',
'created_at',
'updated_at',
'deleted_at',
];
public function staff_user()
{
return $this->belongsTo(User::class, 'staff_user_id');
}
public function staff_guardian()
{
return $this->belongsTo(StudentGuardian::class, 'staff_guardian_id');
}
In the StudentsController, I don't know how to call the students related to the authenticated user
you can use polymorphic relation to handle it.
https://laravel.com/docs/9.x/eloquent-relationships#polymorphic-relationships

Laravel Eloquent HasManyThrough relationship

Trying to get locations through a user. Currently I'm getting an error, so either my hasManyThrough is setup incorrectly or my data structure is. It's still a new project so I don't mind restructuring the database to make the default hasManyThrough work properly.
$user = User::with('locations')->find(Auth::user()->id);
echo '<pre>';
die(print_r($user->locations,true));
Models:
User:
class User extends Authenticatable
{
protected $fillable = [
'name', 'email', 'password',
];
public function locations() {
return $this->hasManyThrough(
Location::class,
UserLocations::class,
);
}
}
UserLocations
class UserLocations extends Model
{
protected $fillable = [
'user_id',
'location_id',
];
public function user()
{
return $this->belongsTo(User::class);
}
public function location()
{
return $this->belongsTo(Location::class);
}
}
Locations
class Location extends Model
{
protected $fillable =
[
'city',
'name',
'timezone',
'email',
'state',
'address',
'address1',
'zip_code',
];
public function user_locations()
{
return $this->hasMany(UserLocations::class);
}
}
Data Structure
Users:
-id
-name
-email
-password
UserLocations:
-id
-user_id
-location_id
Locations:
-id
-name
-city
You should not have used hasManyThrough for this since UserLocations already contains the location_id. In your user model, use hasManyRelationship to UserLocation.
public function locations()
{
return $this->hasMany(UserLocation::class, 'user_id');
}
And then to include the location information, just eager load it.
$user = User::with(['locations.location'])->where('id', Auth::user()->id)->first();

Query Laravel Relationship

I have 3 Model
In Purchase Model
protected $fillable = [
'name', 'date', 'description', 'active', 'supplier', 'total', 'paid', 'purchase_status', 'payment_status',
];
public function product()
{
return $this->belongsTo(\App\Product::class);
}
public function order()
{
return $this->belongsTo(\App\Order::class);
}
In Order Model
protected $fillable = [
'name', 'quantity', 'unit_cost', 'discount', 'tax', 'sub_total'
];
public function order_items()
{
return $this->belongsTo(\App\OrderItem::class);
}
In my OrderItem Model
protected $fillable = ['active', 'description', 'quantity', 'discount', 'unit_price'];
public function order()
{
return $this->belongsTo(\App\Order::class);
}
Is it possible to query Order_Items From Purchases trough Orders Relationship in Laravel?
Oh, i found my answer...
In Order Model
i changed belongsTo to hasMany
protected $fillable = [
'name', 'quantity', 'unit_cost', 'discount', 'tax', 'sub_total'
];
public function order_items()
{
return $this->hasMany(\App\OrderItem::class);
}
Yes you can write this relations in your models and write the query like this:
Purchase
public function order()
{
return $this->belongsTo('App\Models\Order', 'order_id', 'id');
}
Order_Item
public function order()
{
return $this->belongsTo('App\Models\Order', 'order_id', 'id');
}
Order
public function order_items()
{
return $this->hasMany('App\Models\OrderItem', 'order_id', 'id');
}
public function purchases()
{
return $this->hasMany('App\Models\purchase', 'order_id', 'id');
}
Now you can use this query:
$purchase = \App\Models\Purchase::first();
$order_items = $purchase->order->order_items;
I see that you've fixed the relationship Order -> OrderItem of belongsTo to hasMany. But the question was also about how to query through relationships so I'll just add up to this so it could be useful to other users here.
Now you could do
$order_items = $purchase->order->order_items
to get the order items of the purchase.
However you should consider that this would execute further queries to the DB. One for fetching the order and then another one for fetching the order_items. If you're looping through a list of purchases, this could escalate quickly and end up making too much DB queries and affect the performance of your application.
The solution is eager loading.
You could do either pre-fetch the order and items along with the purchase like this:
$purchase = Purchase::with('order.order_items')->find(1);
or if you've already fetched the purchase, then you could do:
$purchase->load('order.order_items');
Then when getting the order items in your code like this
$purchase->order->order_items, you have no additional queries to the DB.

Laravel eloquent: Multiply two columns of two different tables

My Order Model
class Order extends Model
{
protected $fillable = [
'id','user_id', 'erp_id', 'currency_code','ex_rate_with_base','order_status','status','created_at'
];
protected $hidden = ['updated_at',];
public function orderList(){
return $this->hasMany(OrderList::class);
}
public function currency(){
return $this->belongsTo(Currency::class,'currency_code');
}
}
My Currency Model
class Currency extends Model
{
protected $fillable = [
'currency_code','currency_name', 'currency_symbol', 'ex_rate_with_base', 'update_via', 'status',
];
protected $hidden = [
'created_at','updated_at','updated_by','created_by',
];
protected $primaryKey = 'currency_code';
public $incrementing = false;
public function order()
{
return $this->hasMany(Order::class,'currency_code');
}
}
My OrderList Model
class OrderList extends Model
{
protected $fillable = [
'id','order_id', 'product_code', 'qty','unit_price','status',
];
protected $hidden = [
'created_at' ,'updated_at',
];
public function order(){
return $this->belongsTo(Order::class);
}
}
In my Order controller I want to run the query:
$order_history_list = Order::where([['user_id', $user->id], ['updated_at','>', $updated_at]])
->with([
'currency' => function ($query) {
$query->select('currency_code','currency_symbol','ex_rate_with_base');
},
'orderList' => function ($query) {
$query->select('id','order_id', 'product_code', '***order_lists.qty * orders.ex_rate_with_base AS unit_price_with_ex_rate***','status');
}
])->get();
But error is occuring due to the highlighted portion.
Error: Unknown column 'order_lists.qty * orders.ex_rate_with_base' in 'field list'
Please help me with the correct syntax
How can I use column of order table in the sub query ?
Use DB::raw in your select statement and add a join to the 'orderList' $query
$order_history_list = Order::where([['user_id', $user->id], ['updated_at','>', $updated_at]])
->with([
'currency' => function ($query) {
$query->select('currency_code','currency_symbol','ex_rate_with_base');
},
'orderList' => function ($query) {
$query->select('id','order_id', 'product_code', DB::raw('order_lists.qty * orders.ex_rate_with_base AS unit_price_with_ex_rate'),'status')
->join('orders','order_lists.order_id', 'orders.id');
}
])->get();
My Final Query That Worked:
$order_history_list = Order::where([['user_id',$user->id],['updated_at','>',$updated_at]])
->with(['currency'=>function($query){
$query->select('currency_code','currency_symbol','ex_rate_with_base');
},'orderList' => function($query){
$query->select('order_lists.id','order_lists.order_id', 'order_lists.product_code', 'order_lists.qty','order_lists.unit_price',DB::raw('he_order_lists.qty* he_orders.ex_rate_with_base AS unit_price_with_ex_rate'),'order_lists.status')->join('orders','order_lists.order_id', 'orders.id');
}])->get();

laravel eloquent doesn't use protected table name

In my model i added protected $table, but when i'm going to use it laravel does't use it. This is my role models:
class Role extends Model
{
protected $table = 'role';
protected $primaryKey = 'ROLE_ID';
protected $casts = [
'ACTIVE' => 'boolean',
];
protected $fillable = [
'ROLE', 'ACTIVE', 'TYPE'
];
public $timestamps = false;
public function groups()
{
return $this->belongsToMany(Group::class, GroupRole::class, 'ROLE_ID', 'GROUP_ID');
}
}
And this is Group model:
class Group extends Model
{
protected $table = 'groups';
protected $primaryKey = 'GROUP_ID';
protected $fillable = [
'GROUP_ID', 'GROUP_NAME', 'PARENT_GROUP', 'ACTIVE'
];
protected $casts = [
'ACTIVE' => 'boolean',
];
public $timestamps = false;
public function type()
{
return $this->belongsTo(GroupType::class, 'TYPE', 'TYPE_ID');
}
public function roles()
{
return $this->belongsToMany(Role::class, GroupRole::class, 'GROUP_ID', 'ROLE_ID');
}
}
And this is group_role table model. It handles many to many relation between role and group:
class GroupRole extends Model
{
protected $table = 'group_role';
protected $primaryKey = 'GROUP_ROLE_ID';
protected $fillable = [
'COMMENT', 'ROLE_ID', 'GROUP_ID'
];
public $timestamps = false;
}
Problem begin when i want to use this models. For example:
$role = App\Role::first();
$groups = $role->groups;
Laravel returns this error messages:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'favian_mydb.App\GroupRole' doesn't exist (SQL: select groups.*, App\GroupRole.ROLE_ID as pivot_ROLE_ID, App\GroupRole.GROUP_ID as pivot_GROUP_ID from groups inner join App\GroupRole on groups.GROUP_ID = App\GroupRole.GROUP_ID where App\GroupRole.ROLE_ID = 1)
I tried to replace App\GroupRole with group_role and executing in mysql. It works fine. Am i missing something?
The Problem is in your roles relation:
public function roles()
{
return $this->belongsToMany(Role::class, GroupRole::class,'GROUP_ID','ROLE_ID');
}
The belongsToMany expects the intermediate table name as second argument, not the class name.
So you have to define it like this:
public function roles()
{
return $this->belongsToMany(Role::class, 'group_role','GROUP_ID','ROLE_ID');
}
I think the problem is in you relation functions. Try to use strings instead of Model::class.
Example:
return $this->return $this->belongsTo('App\GroupType', 'TYPE', 'TYPE_ID');
Hope this works.

Resources