Laravel how to define relationship based on two models or columns? - laravel

I have the following:
//users table
id
name
email
remeber_token
role_id
//roles table
id
name
//products table
id
name
//product_prices
role_id
product_id
price
The price of the product will vary depending on the user role, how to define the correct relationship so in blade I can do something like:
$product->price
and that will return the correct price depending on the user and the product?

I believe that when you say the user role, you refer to the role of the authenticated user.
The easiest approach is to define a HasOne relationship on the product model:
class Product
{
public function price()
{
return $this->hasOne(Price::class)->where('role_id', auth()->user()->role_id)
}
}
So from the view, you can simply say:
// Lets use optional() because there may not be any price for that product and user.
optional($product->price)->price
If there are many products involved, then using sub queries would make more sense.
class ProductsController extends Controller
{
public function index()
{
$products = Product::addSelect(['right_price' => Price::select('price')
->whereColumn('product_id', 'products.id')
->where('role_id', auth()->user()->role_id)
->limit(1)
])->get()
return view('products.index', compact('products'));
}
}
And then in the view:
#foreach($products as $product)
<p>{{$product->right_price}}</p>
#endforeach
For more info, pls check out this article.

Related

Join tables in Laravel Eloquent method

How to write this code in eloquent method ?
$product = DB::table('products')
->join('purchase', 'products.id', '=', 'purchase.id')
->join('sales', 'purchase.id', '=', 'sales.id')
->select('sales.*', 'purchase.*','products.*')
->get();
Create model Product and add one to many relationship with Purchase in Product model.
public function purchases()
{
return $this->hasMany('App\Models\Purchase');
}
Create model Purchase and add one to many relationship with Sale in Purchase model.
public function sales()
{
return $this->hasMany('App\Models\Sale');
}
Create model Sale.
You can retrieve data using following statement.
$products = Product::with('purchases.sales')->get();
Note: I am assuming the relationship as one to many you can also declare as per your data, also you can define one to many inverse relationship, please refer to laravel docs https://laravel.com/docs/8.x/eloquent-relationships#one-to-many.
You will get purchases and sales data in different key so you can use below syntax to loop over it.
foreach ($products as $product) {
foreach ($product->purchases as $purchase) {
//Purchase data for current product
foreach($purchase->sales as $sale){
//Sale data for current purchase
}
}
}

How to make this Eloquent relationship in Laravel

I have a table called users with a column username. Another table called students with a column code. I have made a hasMany relationship in User model like below and it's working fine.
public function students()
{
return $this->hasMany(Student::class,'code','username');
}
I have another table called institutes where a column is similar to students table named inst. I need to show data from institutes table while showing data of an user. How to make this relationship?
users table
username|mobile|address|password
students table
username|name|inst|roll|reg
institutes table
name|inst|address|phone
This is my home controller
public function index()
{
$admins = User::where('username','=',Auth::user()->username)->get();
return view('home', compact('admins'));
}
And this is my view
#foreach($admins as $key => $admin)
#foreach($admin->students as $student)
{{ $student->reg }}
#endforeach
#endforeach
Add migration to your Students table :
$table->unsignedBigInteger('user_id')->nullable();
$table->foreign('user_id')->references('id')->on('users')->onUpdate('cascade')->onDelete('set null');
Update your model User on students method :
return $this->hasMany(Student::class);
Add "with method"
$admins = User::where('username','=',Auth::user()->username)->with('students')->get();

Laravel Fetching one to Many Relationship

Hello I am learning laravel and I am having an issue retrieving data from my relations.
In my database there are Product and Groups filled with dummy data.
I defined my relationship like this in product model:
public function Group()
{
return $this->hasMany('App\Groups','product_id', 'id');
}
And in my group vice versa with :
public function Product()
{
return $this->belongsTo('App\Product','product_id', 'id');
}
The way I am referencing to my products table is :
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
Now I have column product_id in my database under groups, and it is linked to if from products id it seems.
The groups table contains of its auto incremented id and product_id foreign key column.
While products table has auto incremented id and name column.
The issue is here :
How do I return the products that are not null or have value (of products id) in groups table.
I tried something like this in my filter controller:
public function getProductsWithGroup()
{
$Products = Product::with('groups')->get();
return $Products ;
}
But that is giving me call to undefined relations.
I am not sure how to access belongsTo or hasMany methods and whether I need an extra group_id column in my products table.
You named the relationship wrong. It should be groups & define in lowercase as
public function groups()
{
return $this->hasMany('App\Groups','product_id', 'id');
}
And use ->has() to check existence
public function getProductsWithGroup()
{
$Products = Product::has('groups')->get();
return $Products ;
}
->with() is used to eager load and ->has() is used to check existence & filter.
To get the products don't have any groups,
$Products = Product::doesntHave('groups')->get();
To see other ways to use ->has() check, https://laravel.com/docs/5.7/eloquent-relationships#querying-relationship-existence

limiting user to only select items on laravel listbox

I would like to ask for help, please advise how to solve such problems in laravel
how to make an application like a vehicle ticket application, to limit if there are 5 people on car A, then user can not choose car A in listbox (item listbox carA disable) when booking.
I am confused where to start
I am currently thinking of creating 3 tables
users (id, name,car_id, created_at, updated_at)
cars (id, car_name, created_at, update_at)
I am confused what should be done to the controller Thank you very much
thanks to all of you, i can start the first step.
currently
on the controller
public function create(){
$list=MCars::all();
return view('booking/create')->with('sent_list',$list);
}
on the view
<select name="car" value="{{ old('car')}}">
#foreach($sent_list as $a)
<option value="{{$a->id}}">{{$a->car_name}}</option>
#endforeach
</select>
I want only cars that contain users <5 that appear on the view
maybe i should put this somewhere
SELECT DISTINCT cars.id, cars.car_name, COUNT(users.car_id) from cars INNER JOIN users ON cars.id = users.car_id
The relationship can be like this:
a user belogsTo a car and the car hasMany users
So the Car model class should be:
..
class Car extends Model
{
public function users()
{
return $this->hasMany('App\User');
}
}
And the User model:
class User extends Model
{
public function car()
{
return $this->belongsTo('App\Car');
}
}
Eloquent will automatically determine the proper foreign key. So, here Eloquent will assume the foreign key on the User model is car_id.
Access the collection of users by accessing the users property.
$users = App\Car::find(1)->users;
foreach ($users as $user) {
//
}
In the UserController use:
$user = App\User::find(1);
echo $user->car->name;
This is how the Eloquent works!
Now use the custom logic for limit(5).
To retrieve the number of cars as users:
public function getTotalUsersAttribute()
{
return $this->hasMany('Car')->whereUserId($this->user_id)->count();
}
And:
if(getTotalUsersAttribute() >= 5) {
// dismiss this function with an err msg
}
// otherwise add user to car
Find similar cases and solution from the official docs.
you can make the registration for user, user will insert their name(according to your table), but i'll suggest for inserting new column email and password for login system. if they not login, they cant booked cars. they must register and login to booking cars.
after user login, the car can be booked, you must create form for it. the code something like this
$cars_id = request::get('id');
$total_passenger = DB::table('passenger')->WHERE('car_id',$cars_id);
if(count($data) < 5){
//do insert data into passenger
}else{
//windows alert / whatever
}

Laravel Eloquent nested query

I was working with Laravel and got stuck in a situation. I have following models:
Category
Product
CategoryProduct
CategoryProduct holds the information about which product belongs to which category (a product may belong to multiple categories).
Now, when I want to load all products belonging to a particular category, I need to run query on Product and CategoryProduct which is where I'm stuck.
I gave it the following try but was unsuccessful:
$products = Product::where('status', '=', 'active')
->where('category_id', '=', $category_id)
->take($count)
->skip($skip)
->get();
Obviously, it will say that category_id is not a column.
Here is my DB & Model structure:
categories table
id,
name,
etc.
products table
id,
name,
sku,
etc.
category_products table
id,
product_id, ( Foreign key to Product.id )
category_id, ( Foreign key to Category.id )
etc.
Product model
class Product extends Eloquent {
protected $table = 'products';
protected $hidden = array();
public static $rules = array('name' => 'required|min:3');
}
Category model
class Category extends Eloquent {
protected $table = 'categories';
public static $rules = array('name' => 'required|min:3');
}
CategoryProduct model
<?php
class CategoryProduct extends Eloquent {
protected $table = 'category_products';
public function product()
{
return $this->belongsTo('Product');
}
public function category()
{
return $this->belongsTo('Category');
}
}
Update
A new question on this
I'm trying to display products. If category is not passed (value is -1), then I will show all products, otherwise I will show products from the passed category.
Now, when I show all products, those products may already exist in a category. I want to display ticked checkbox for products that are already in a category. I'm doing something like this:
if($category_id==-1)
$products = Product::where('status', '=', 'active')->take($count)->skip($skip)->get();
else{
$products = Product::whereHas('categories', function($q) use ($category_id)
{
$q->where('category_id', $category_id);
})->where('status', 'active')
->take($count)
->skip($skip)
->get();
}
The table category_products have product_id, category_id as columns.
Now, the query:
$products = Product::where('status', '=', 'active')->take($count)->skip($skip)->get();
will pick products only from products table. If I check each product for its existence in category_products, then there will be too many database queries for large number of products.
Any idea, how to achieve this. I hope I was able to clear my situation. Thanks
The CategoryProduct model should not be necessary unless you have additional fields besides product_id and category_id which point to other relationships.
What is necessary are the methods for setting up the relationship on the Category and Product models.
In Category, add the relationship function...
public function products()
{
return $this->belongsToMany('Product', 'category_products');
}
In your Product model, do the same for categories.
public function categories()
{
return $this->belongsToMany('Category', 'category_products');
}
Then you can query for your active products that belong to that category using your relationship method and whereHas()
$products = Product::whereHas('categories', function($q) use ($category_id)
{
$q->where('id', $category_id);
})->where('status', 'active')
->take($count)
->skip($skip)
->get();
You don't need a model for a pivot table in Many-to-Many relationships. Look at this section of the Eloquent documentation for further explanation.
You still need to create a migration to set up the pivot table (or do it manually if you don't use migrations), but not a model. Instead, create a function for Category to designate the relationship:
public function products()
{
return $this->belongsToMany('App\Product', 'category_products');
// - You might need to adjust the namespace of App\Product
// - category_products refers to the pivot table name
}
Likewise, Product needs a similar public function.
Then you're able to do it the other way around, by finding the category and then listing all its related products:
$products = Category::find($category_id)
->products()
->where('status', 'active')
->take($count)
->skip($skip)
->get();
This question could also be relevant to yours.

Resources