Laravel Lucid whereHas by latest column in pivot table - php

I have 3 tables : Orders ( id, name, surname, created_at and updated_at ), OrdersStatuses (order_id, order_status_name_id, created_at) and OrderStautsNames ( id and name ):
I have orders model which has method like this:
protected $appends = ['actual_status'];
public function orderProducts()
{
return $this->hasMany(OrderProduct::class);
}
public function statuses()
{
return $this->belongsToMany(OrderStatusName::class, 'order_statuses')
->withPivot('created_at');
}
public function getActualStatusAttribute()
{
return $this->statuses()->latest('set_at')->first();
}
I have problem with seraching all orders, where highest status id ( this info is in pivot table OrderStatuses, and I need name of this status which is in OrderStatusNames ) is like $statuses (this is an array with statuses ). I started do like this:
$orders = Order::query();
$orders->whereHas('statuses', function($query) use ($statuses) {
$query->whereIn('order_status_name_id', $statuses);
});
But it return me orders with not latest status, but this query search me throught all statuses... . Can i do this by latest status? I tryed to use current_status but I don't know how to get there.

Add this relation to your Order Model
public function lastStatus()
{
return $this->hasOne(OrderStatusName::class)->select('OrderStautsNames.*', 'order_statuses.order_id', DB::raw('MAX(order_statuses.set_at) as lastOrder'))->join('order_statuses', 'order_statuses.order_status_name_id', '=', 'OrderStautsNames.id')
}
Then eager load it
$orders = Order::whereHas('lastStatus', function ($query) use ($statuses) {
$query->whereIn('OrderStautsNames.id', $statuses);
})->get();

Related

Use a scope in a JOIN in Laravel Eloquent

I am trying to get all the products with active prices and display them and the active price using a scope in the ProductPrices Model. My Products Model has an hasMany relation with prices:
Product.php (Model)
public function prices () {
return $this->hasMany(ProductsPrice::class);
}
My Prices Model has an scope is active that checks if the prices is active on this date:
ProductsPrices.php (Model)
public function scopeIsActive($query)
{
return $query->whereRaw(' timestampdiff(second, start_time, NOW()) >= 0')
->where(function ($query) {
$query->whereRaw(' timestampdiff(second, end_time, NOW()) <= 0')
->orWhereNull('end_time');
});
}
I tried many different ways to get products with an active price and display them both. Things I feel should work, but don't, are:
Route::get('/test', function (Request $request) {
return Product::join('products_prices', 'products.id', 'products_prices.product_id')
->prices->isActive()
->where('products.is_active', true)
->get();
});
I get the error:
Property [prices] does not exist on the Eloquent builder instance.
or test2
Route::get('/test2', function (Request $request) {
$prices = DB::table('products_prices')->select('id');
$product = Product::whereIn('id', $prices)->get();
return $product->prices()->isActive()->get();
});
I get the error:
Method Illuminate\Database\Eloquent\Collection::prices does not exist.
Why can't I access the ->prices() on my Product Model? Should I not use eloquent for this and go for the Query Builder of Laravel?
I think a combination of with and whereHas might work:
$products = Product::with(['prices' => function($query) {
$query->isActive(); // to fetch prices relation that is active
}])->whereHas('prices', function($query) {
$query->isActive(); // this one is to filter the products that has active price
})->get();

laravel searching belongsToMany relation

I have the following tables
items ( id, item-name, catalog-name)
categories (id, category-name)
item_categories ( pivot table )
on Items model I made this relation
public function itemCategories()
{
return $this->belongsToMany('App\Models\Categories');
}
In my controller I want to search all items from a catalog that belong to categories so i am trying this
$items = Items::where('catalog-name', 'somename')->whereHas('itemCategories', function ($query) {
$query->where('category', 'something');
});
But I keep getting the error
Call to undefined method App\Models\Items::itemCategories()
Any ideas what I am doing here ?

Laravel Join query is not working for 4 tables

I have 4 tables
Table Name : Clinics
Fields: clinicID , clinicName
Table Name : locations
Fileds: locationID, clinicID,locationname
Table Name : Services
Fields: ServiceId , ServiceName
Table Name: LocationServices
Fields: locationServiceID, locationID , ServiceId
My requiremnt is that when i pass clinicID, i need to retrive Corresponding clinics service name, there may be more than one.
But when i tried join query is not working
Following is my code in controller
public function showClinic($id)
{
$clinic = Clinic::find($id);
$locations = Location::where('clinicID', $id)->get();
$locationsservices=\App\Clinic::with('locations');
var_dump($locationsservices);
die();
return view('clinic.show')->with(['locations' => $locations ,'clinic'=>$clinic]);
}
You can get this details by using relationships.
In the Clinic model,add
public function locations()
{
return $this->belongsTo('App\Models\Locations','clinicID','clinicID');
}
In the Locations model,add,
public function location_services()
{
return $this->hasOne('App\Models\LocationServices','locationID','locationID');
}
On the LocationServices model,
public function services()
{
return $this->hasOne('App\Models\Services','ServiceId','ServiceId');
}
You can get the result by,
$clinic_info = Clinic::find($id);
if(isset($clinic_info->locations))
{
if(isset($clinic_info->locations->location_services))
{
if(isset($clinic_info->locations->location_services->services))
{
echo $clinic_info->locations->location_services->services->ServiceName;
}
}
}
Reference Maybe HelpFull for You
Multi Joins
$data = DB::table('city')
->join('state', 'state.state_id', '=', 'city.state_id')
->join('country', 'country.country_id', '=', 'state.country_id')
->select('country.country_name', 'state.state_name', 'city.city_name')
->get();
return view('join_table', compact('data'));

Issue with group by laravel and sql

Firstly I have problem which count products which are sold every day. In sql I have query
select product_name, sum(quantity) as quantity from invoice_product
join invoices on invoices.id = invoice_product.invoice_id
join products on products.id = invoice_product.product_id
where invoices.issued_at = '2019-05-16'
and products.`made_by_us` = 1
group by product_name
It show me interesting for me information but I used product_name to make group by but I should use product_id - I need show name too but I don't know how to do it.
Secondly I want to use it in Laravel so maybe someone know which is it possible to do it in Eloquent?
Thank you in advance :)
I would go with withCount() combined with select(DB::raw()), like this:
$products = Product::withCount(['invoices as quantity' => function ($query) {
$query->select(DB::raw('sum(quantity)'));
}])->get();
Then, you can access each quantity sum like this:
$quantity = $products->first()->quantity;
You would need to update your model relationships to achieve that.
Models:
InvoiceProduct Model
class InvoiceProduct extends Model
{
protected $table = 'invoice_product';
protected $guarded = [
'id',
];
}
public function invoice()
{
return $this->belongsTo('App\Invoice'); // Assuming `Invoice` Model is directly in app folder
}
public function product()
{
return $this->belongsTo('App\Product'); // Assuming `Product` Model is directly in app folder
}
Controller:
$full_query = InvoiceProduct::whereHas('invoice', function ($query) {
return $query->where('issued_at', '2019-05-16');
})->whereHas('product', function ($query) {
return $query->where('made_by_us', 1);
});
$product_names = $full_query->get(['product_name']);
$total_quantities = $full_query->sum('quantity');

Laravel Eloquent: how to filter reviews of products by product category and/or product brand?

I will describe this situation with more details:
I have a list of products where every product belongs to a certain category and to a certain brand. Some of the products can get reviewed by users.
On /reviews/ page in my Laravel application, I have a list of reviews and select boxes for category and brand along with search button of course.
If user doesn't choose category or brand, all reviews get displayed, paginated, and that's good.
The problem arises when user chooses either category or brand or both and tries to get all the reviews filtered that way.
Reviews table fields: ID, user_id(foreign key users.ID), product_id(foreign key products.ID), text
Products table fields: ID, category_id(foreign key categories.ID), brand_id(foreign key brands.ID), name
Categories table fields: ID, name
Brands table fields: ID, name
Users table fields: ID, username
When I'm listing reviews, I'm simply using:
$reviews = Review::orderBy('id', 'DESC')->paginate(5);
If I would like to filter reviews by user_id, that would be easy as the reviews table contains user_id column,
but, how to filter them by product category and/or product brand?
Here are Review, Product and Category models:
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Review extends Model {
protected $fillable = [];
public function product() {
return $this->belongsTo('App\Product');
}
public function user() {
return $this->belongsTo('App\User');
}
}
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Product extends Model {
protected $fillable = [];
public function user() {
return $this->belongsTo('App\User');
}
public function reviews() {
return $this->hasMany('App\Review');
}
public function category() {
return $this->belongsTo('App\Category');
}
}
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Category extends Model {
protected $fillable = [];
public function products() {
return $this->hasMany('App\Product');
}
}
If I use joins, then $review->user->id, $review->user->username, $review->id are not correct, I'm getting reviews.product_id as $review->id, and products.user_id as $review->user->id in blade template.
I was trying this join variant:
$reviews_query = Review::orderBy('reviews.id', 'DESC')
->Join('products', 'reviews.product_id', '=', 'products.id')
->Join('categories', 'products.category_id', '=', 'categories.id')
->Join('brands', 'products.brand_id', '=', 'brands.id')
->Join('users', 'reviews.user_id', '=', 'users.id')
->where('reviews.active', '=', 1)
->GroupBy('reviews.id')->paginate(5);
And this for filtering by category_id:
if (Input::has('category_id')){
$category_id = Input::get('category_id');
$reviews_query->where('categories.id', $category_id);
}
I'm not sure how to correctly address ambiguous ids such us product_id, review_id, user_id in blade template ($review->id, $review->user->id, all are messed up mutually)
Add hasManyThrough relationship in your category model
public function reviews() {
return $this->hasManyThrough('App\Review', 'App\Product');
}
now you can have all reviews by a category like this
$category->reviews();
you can add other query clauses to it like
$category->reviews()->orderBy('id', 'DESC')->paginate(5);
Try this,
$reviews = DB::table('review')
->join('product', 'product.id', '=', 'review.product_id')
->Join('category', 'product.category_id', '=', 'category.id')
->orderBy('id', 'DESC')->paginate(5);
for more you can visit-
Laravel join with 3 Tables
This may work for you.....
filter all reviews by a specific CategoryID then simply use ->
$categoryID = 1;
Categories::with(['products' => function($product){
$product->with('reviews');
}])->where('id', '=', $categoryID)->get();
also filter all reviews by a specific BrandID then
$brandID = 1;
Brands::with(['products' => function($product){
$product->with('reviews');
}])->where('id', '=', $brandID)->get();

Categories