Laravel relation between 5 tables - php

please what is the correct way of getting data from the MN table where one product has assigned multiple combinations of Mark / Model / Year.
E.g. product with ID 1 has following in mmis table:
id | product_id | mark_id | model_id | year_id
178 1 1 1 2
177 1 2 1 3
176 1 3 1 1
other tables are: marks, models, years.
It's completely fine getting all requested data with just:
$items = ProductMmi::where('product_id', $id)
->with(['mark', 'model', 'year'])
->get();
The problem is, that in this way I am not able to sort result based on mark.name ASC, model.name ASC, year.name ASC.
Thank you for any advice.
update:
forgot to add my second try - ordering still in troubles...
$items = ProductMmi::select([
'product_mmis.*',
'marks.*',
'mark_models.*',
'mark_model_years.*'
])
->join('marks', 'product_mmis.mark_id', '=', 'marks.id')
->join('mark_models', 'product_mmis.model_id', '=', 'mark_models.id')
->join('mark_model_years', 'product_mmis.year_id', '=', 'mark_model_years.id')
->where('product_mmis.product_id', $id)
->orderBy('mark', 'asc')
->orderBy('model', 'asc')
->orderBy('year', 'asc')
->get();

you can use this way
$items = ProductMmi::where('product_id', $id)->with(['mark'=>function($query){
$query->orderBy('your_column_name','ASC');
}])->with(['model', 'year'])
->get();
or one thing if you dont want to edit your query then in the model you can do also like this
public function mark()
{
return $this->hasMany(Mark::class)->orderBy('mark','asc');
}

I think the solution was to add orderBy methods between specific joins. E.g. the following case is working completely properly:
$items = ProductMmi::select([
'product_mmis.*',
'marks.*',
'mark_models.*',
'mark_model_years.*'
])
->join('marks', 'product_mmis.mark_id', '=', 'marks.id')
->orderBy('mark', 'asc')
->join('mark_models', 'product_mmis.model_id', '=', 'mark_models.id')
->orderBy('model', 'asc')
->join('mark_model_years', 'product_mmis.year_id', '=', 'mark_model_years.id')
->where('product_mmis.product_id', $id)
->orderBy('year', 'desc')
->get();
Is there a better way to have it done in a more efficient way? Thanks.

Related

Laravel WithSum / WithCount Relationships not bringing results

I am trying to make a query using Laravel eloquent but at the moment I have not had good results.
My query is about the scope of relationships in Laravel. We have two tables:
table 1 : orders
table 2 : products in orders (depends on table 1)
We have a relationship in the model.
public function products()
{
return $this->hasMany(OrderProduct::class);
}
OrderProduct (detail of products in orders) has the following fields:
id
order_id
product_id
qty
line_total
What we are trying to achieve is a query that returns the sum of line_total when the product_id is 139.
We tried the following options without success in the controller:
$orderspaid = Order::with('products')
->where('customer_id', '=', Auth::id())
->where('status', '=', 'completed')
->withSum ('products','line_total')
->where('product_id', '=', '139')
->get();
Error: Column not found: 1054 Unknown column 'product_id'
$orderspaid = Order::withCount(['products as orderproducts' => function($query) {
$query->where('orderproducts.product_id', '=', 139)
->select(DB::raw('sum(line_total)'));
}])->get();
But with no success.
My main question is, it is possible to use sum(line_total) or withSum('products','line_total') to directly sum the amount of money that a particular product_id have?.
Additional Info: Tinker information displaying the relationship between orders and orderproducts.
You can try this one. I don't have those tables ready to test so I could be wrong
So basicly, the method being tried is that products with wanted id will be preloaded, in this case, it's 139. When withSum is called on products table, it will use eagerly products that have been specified beforehand.
$product_id = 139;
$orderspaid = Order::with(['products' => function ($query) use ($product_id) {
$query->where(`products.id`, $product_id);
}])
->where('customer_id', '=', Auth::id())
->where('status', '=', 'completed')
->withSum('products', 'line_total')
->get();
dd($orderspaid);
Tell me if that works for you.

Counting Existing ID's in a different table - laravel

I have two items in a table called products with id's 1 and 2. There is a table called invite which has foreign key product_id for products.
In my controller below, i am trying to count the number of product id's that is existing in the invite table.
eg
Product invite
id name id token product_id user_id
1 cal 1 ..d 1 2
2 del 2 dd.. 2 2
3 mac 3 ..gh4 2 2
As above, id's 1 and 2 exist in the invite table. meaning the total count is 2 (although product id 2 appears twice.
When i run my code below, i get a count of 1 instead of 2. What could i be missing out, please?
NB: in this case, i am user just one user
Controller
public function dashboard()
{
$products = Products::orderBy('created_at', 'desc')
->where('user_id', Auth::user()->id)->get();
$get_products_id = [];
foreach($products as $product){
$get_products_id[] = $product->id;
}
$implode_data = implode(',',$get_products_id);
$count_existing_products =
Invite::where('product_id',$implode_data)
->where('user_id', Auth::user()- >id)->get()->count();
return view('dashboard', compact('count_existing_products'));
}
View
<h1>{{count_existing_products}}}</h1>
For WHERE IN clause laravel uses special whereIn() method where you pass array, not string. So, your query becomes:
Invite::whereIn('product_id', $get_products_id)
->where('user_id', Auth::user()->id)
->distinct() // added `distinct` call to get distinct values
->get()
->count();
If distinct does not work, try to groupBy:
Invite::whereIn('product_id', $get_products_id)
->where('user_id', Auth::user()->id)
->groupBy('product_id')
->get()
->count();
There is no need to use implode. you can use whereIn instead of where.
Invite::whereIn('product_id',$get_products_id)
->where('user_id', Auth::user()- >id)->get()->count();

Pagination eloquent

I want to paginate ordering by linkscount em ASC...
The table pages:
----------------------
id | name
----------------------
1 | Globo
----------------------
2 | Google
----------------------
3 | MC Donalds
----------------------
4 | Habibs
The query to FIRST PAGE RESULTS (order/query is OK):
$pages = Mypages::where('pages.author_id', auth()->user()->id)
->orderBy('linkscount', 'desc')
->leftJoin('links', 'links.page_id', '=', 'pages.id')
->selectRaw('pages.*, count(links.id) as linkscount')
->groupBy('pages.id')
->take(2)
->get();
The query TO PAGINATE (order/query is not ok):
$pages = Mypages::where('pages.author_id', auth()->user()->id)
->orderBy('linkscount', 'asc')
->leftJoin('links', 'links.page_id', '=', 'pages.id')
->selectRaw('pages.*, count(links.id) as linkscount')
->groupBy('pages.id')
->where('pages.id', '>', $id)
->take(2)
->get();
This query, don't return nothing, it was to return "MC Donalds"...
$id = LAST ID DISPLAYED.
Like Jacob H said in the comment, this isn't a real SQL, because the group by function need to have all the columns of the query that you have in the select except the functions like counts, sums, etc.
For this example you need to put the pages.name and pages.id in the group by
$pages = Mypages::where('pages.author_id', auth()->user()->id)
->orderBy('linkscount', 'asc')
->leftJoin('links', 'links.page_id', '=', 'pages.id')
->selectRaw('pages.id, pages.name, count(links.id) as linkscount')
->groupBy('pages.id', 'pages.name')
->where('pages.id', '>', $id)
->take(2)
->get();
And if you are sending the correct $id, everything seems ok.

Laravel query builder SUM returns multiplied values

I have the following query and been fighting with from yesterday after solving previous issue with the help of great stack-overflowers yesterday's question.
$sales = DB::table('sales')
->leftJoin('store_configs', 'store_configs.id', '=', 'sales.store_config_id')
->leftJoin('category_sales', 'category_sales.sale_id', '=', 'sales.id')
->leftJoin('categories', 'categories.id', '=', 'category_sales.category_id')
->leftJoin('departments', 'departments.category_id', '=', 'categories.id')
->leftJoin('department_sales', 'department_sales.sale_id', '=', 'sales.id')
->select('sales.date',
DB::raw('sales.id as sales_id'),
DB::raw('(IFNULL(sum(department_sales.amount), 0)) as department_sales'),
DB::raw('(IFNULL(sum(category_sales.amount), 0)) as cat_total')
)
->groupBy('date', 'sales.id')->orderBy('date', 'desc')->get();
The following is the result output from above query and it is wrong:
I have a table structure with following data: categories_sales has following data:
department_sales
As per the table : I expected result should have been :
department_sales: 10 for sale_id = 1
department_sales: 5 for sale_id = 2
category_sales: 200 for sale_id 1
category_sales: 30 for sale_id 2
Can someone please give me some idea ? I will be really really thankful.

Laravel joins including where there is no match

I have a table layout like so:
products
id
productname
product_weights
id
productid
weight
product_flavours
id
productid
flavour
I am trying to generate a list of all possible product variations. Some products have no variation in size, some have no flavour variation, some have both. My current thinking is using a join. I have so far for my query:
DB::table('product_weights')
->join('products', 'products.id', '=', 'product_weights.prodid')
->select('product_weights.value', 'products.productname')
->get();
This gives something kind of useful, var_dump giving:
[{"value":"1kg","productname":"Item 1"},{"value":"2.1kg","productname":"Item 2"},{"value":"250g","productname":"Item 3"},{"value":"1kg","productname":"Item 3"}
The issue is that a product item 5 with no weight variations is not returned. And of course I need to build in flavours too.
I then want to just make an array like {'Item 1 1kg', 'Item 2 2.1kg', 'Item 3 250g', 'Item 3 1kg'}
Any ideas? I kind of feel like I am doing the join wrong. Help would be appreciated!
Update: Thanks to comments below, some progress has been made with leftJoin. I can produce the desired results for weight or flavour, but not both. The code now is:
$product_join_weights = DB::table('products')
->leftJoin('product_weights', 'products.id', '=', 'product_weights.prodid')
->select('products.productname', 'product_weights.value')
->get();
$product_join_flavour = DB::table('products')
->leftJoin('product_flavours', 'products.id', '=', 'productattributes.prodid')
->select('products.productname', 'product_flavours.value')
->get();
Any ideas how they can be combined?
Instead of combining the two arrays, why not just chain the joins together?
$product_join = DB::table('products')
->leftJoin('product_weights', 'products.id', '=', 'product_weights.prodid')
->leftJoin('product_flavours', 'products.id', '=', 'productattributes.prodid')
->select('products.productname', 'product_flavours.value', 'products.productname', 'product_weights.value')
->get();
Left Joins fetch a complete set of records from table1, with the
matching records in table2. The
result is NULL in the right side when no matching will take place.
http://www.w3resource.com/sql/joins/perform-a-left-join.php
I think you could simply double the left join...
something like this:
$product_weights_and_flavours = DB::table('products')
->leftJoin('product_weights', 'products.id', '=', 'product_weights.prodid')
->leftJoin('product_flavours', 'products.id', '=', 'productattributes.prodid')
->select('products.productname', 'product_weights.value', 'product_flavours.value')
->get();

Categories