Laravel Model Count By Relationship - php

I have an eCommerce site with a Product model and a ProductCategory model. I currently show products on the page from the Product model but would like to be able to get a list of all the categories with products in the current model and how many products are in each category. I can get the overall count but can't figure out how to get the list of categories being shown and how many results per category have been returned.
Product Model
Product_ID
Product_Name
Product_Description
Category_ID (Many-To-1: ProductCategory.Category_ID
ProductCategory Model
Category_ID
Category_Name
Currently, I access the results in the blade using...
#foreach($products->chunk(3) as $row)
<div class="item-row">
#foreach($row as $product)
<div class="item item-thumbnail" style="height: 250px;">
<a href="product_detail.html" class="item-image">
#if(empty($product->Images{0}->original_image))
<img style="width: 100px; height: 100px;"
src="https://example.com/100x100/d3d3d3/fff.gif&text=No+Image"
alt="" />
#else
<img style="width: 100px; height: 100px;"
src="https://cdn.example.com.au/products/{{$product->id}}/{{$product->Images{0}->original_image}}"
alt="" />
#endif
</a>
<div class="item-info">
<h4 class="item-title">
<a href="/store/{{$category->alias}}/{{$product->alias}}">
{{$product->product_name}}
</a>
</h4>
<p class="item-desc"> </p>
#if(empty($product->special_price))
<div class="item-price">
${{$product->normal_price}}
</div>
#else
<div class="item-price">
${{$product->special_price}}
</div>
<div class="item-discount-price">
${{$product->normal_price}}
</div>
#endif
</div>
</div>
#endforeach
</div>
#endforeach
And would like to be able to generate a list of all the categories with products displayed as...
#foreach($products->categories as $category)
<li>
{{$category->category_name}} ({{$category->count}})
</li>
#endforeach
All from within the same model.
Additional
If it helps clarify I don't want the model to change drastically in that I still want to be able to access the products in the model from the blade template as is currently done but would like to also be able to pull a list of categories such as the below example...
| Product_ID | Product_Name | Category_ID |
| ---------- | ------------ | ----------- |
| 1 | Product 1 | 1 |
| 2 | Product 2 | 1 |
| 3 | Product 3 | 2 |
| Category ID | Category Name |
| ----------- | ------------- |
| 1 | Category 1 |
| 2 | Category 2 |
And wind up with the following table on my page to show the product categories being shown in the results...
| Category Name | # Products |
| ------------- | ---------- |
| Category 1 | 2 |
| Category 2 | 1 |

It would be super helpful if you provided the code where you query the products and categories.
But here's essentially what you need to do. You need to make use of ->withCount(..):
$products = Product::with([
'categories' => function ($query) {
// Adds count of category-related products
$query->withCount('products as count');
},
])->get();
And then this would work in your view:
#foreach($products as $product)
#foreach($product->categories as $category)
<li>{{$category->category_name}} ({{$category->count}})</li>
#endforeach
#endforeach

Related

How to show single array only?

I'm making a recommendation system and I want to show only the top 1 from the recommendation instead of all of it.
this is the code
$movies = mysqli_query($db, "select * from practice");
while ($movie=mysqli_fetch_array($movies))
{
$users=mysqli_query($db,"select username from users where id =$movie[user_id]");
$username=mysqli_fetch_array($users);
$matrix[$username['username']] [$movie['image']] = $movie ['ratings'];
}
$users=mysqli_query($db,"select username from users where id=$_GET[id]");
$username=mysqli_fetch_array($users);
?>
<div class="panel panel-default">
<div class="panel-heading">
<h2>
<a class="btn btn-info" href="index.php"> Back </a>
</h2>
</div>
<div class="panel-body">
<table class="table table-striped">
<th>Clothes</th>
<th>Rating</th>
<?php
$recommendation=array();
$recommendation = getRecommendation($matrix,$username['username']);
foreach($recommendation as $movie => $rating) {
?>
<tr>
<td>
<?php echo "<img src='images/".$movie."' >"; ?>
</td>
<td>
<?php echo $rating ; ?>
</td>
</tr>
<?php } ?>
</table>
</div>
You should use the LIMIT in your sql query.
LIMIT Query
If you need only a specified number of rows from a result set, use a LIMIT clause in the >query, rather than fetching the whole result set and throwing away the extra data.
MySQL sometimes optimizes a query that has a LIMIT row_count clause and no HAVING clause
mysql> SELECT * FROM ratings ORDER BY category;
+----+----------+--------+
| id | category | rating |
+----+----------+--------+
| 1 | 1 | 4.5 |
| 5 | 1 | 3.2 |
| 3 | 2 | 3.7 |
| 4 | 2 | 3.5 |
| 6 | 2 | 3.5 |
| 2 | 3 | 5.0 |
| 7 | 3 | 2.7 |
+----+----------+--------+
mysql> SELECT * FROM ratings ORDER BY category LIMIT 1;
+----+----------+--------+
| id | category | rating |
+----+----------+--------+
| 1 | 1 | 4.5 |
+----+----------+--------+
https://dev.mysql.com/doc/refman/8.0/en/select.html

Laravel foreach same product multiple

I have some problems with Laravel foreach. Foreach as foreach is working fine, but I have foreached multiple same items that I need to put in one.
For example
I have product that can be booked for every day, and if I book it for 10 days it will foreach it 10 times that same product. I need to develop function that will take all prices per person, quantity and total price and sum it and show it in one row. It's giving correct information's and prices, I just need to sum all of that data and put it in one. Of course I need to foreeach all products, cause it can be 2 products 10 days, and foreach it every product 10 times.
If I want to check is same id for that product I have to put $change->rate_id
Here is code that i'm using in blade
#foreach($extras_changes as $iKey => $change)
#php $extraId = uniqid(); #endphp
<tr>
<td class="cell-product">
<div class="product-body">
<a data-toggle="modal" data-target="#{{$extraId}}">
<h4 class="modal-title product-title">{{$change->offerable->name}}</h4>
</a>
</div>
</td>
<td class="cell-total col-md-2 text-right">
<span class="price">
#php
$price = _amount($change->price, $change->currency, get_display_currency());
#endphp
#include('extranet.amount', ['data'=> $price])
</span>
</td>
<td class="text-center">
{{$change->quantity}}
</td>
<td class="cell-total col-md-2 text-right">
<span class="price">
#php
$amount = _amount($change->price * $change->quantity, $change->currency, get_display_currency());
$amountChange += $amount['value'];
#endphp
#include('extranet.amount', ['data'=> $amount])
</span>
</td>
</tr>
#include('frontend.planner.change_modal_new', ['id' => $extraId])
#endforeach
I will give you one more example to be more specific.
I have table like:
Product Name | Price Per Person | Quantity | Total
Dinner | EUR 9,50 | 2 | EUR 19,00
Dinner | EUR 9,50 | 2 | EUR 19,00
Dinner | EUR 9,50 | 2 | EUR 19,00
Dinner | EUR 9,50 | 2 | EUR 19,00
Dinner | EUR 9,50 | 2 | EUR 19,00
I need to show it like:
Product Name | Price Per Person | Quantity | Total
Dinner | EUR 9,50 | 10 | EUR 95,00

Making a category menu with its subcategories getting data from DB and PHP?

I am willing to do a dropdown (or a list, it doesn't matter) with categories and subcategories getting directly the data from the database.
The order should be:
CATEGORY 1
-- Subcategory 1
-- Subcategory 2
-- Subcategory 3
-- ...
CATEGORY 2
-- Subcategory 1
-- ...
...
And so on even adding future categories and subcategories.
I am using MVC and this is my code this far:
View:
<?php foreach ( $datoCategorias as $categorias ) { ?>
<div class="col">
<div class="dropdown">
<button class="col btn btn-secondary" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<?php echo $categorias['NAME'] ?></button>
<div class=" col dropdown-menu" aria-labelledby="dropdownMenuButton">
<a class="dropdown-item" href="index.php?controller=products&action=category&id="></a>
</div>
</div>
</div>
<?php } ?>
Index.php:
if ($_GET['action'] == "category") {
$controller = new productos_controller();
$controller->category();
}
Controller:
function category() {
$categorias = new productos_models();
$datoCategorias=$categorias->get_categorias();
require_once("views/products.php");
}
Model:
public function get_categorias(){
$categorias=$this->db->query("select * from CATEGORY;");
while($listaCategorias=$categorias->fetch_assoc()){
$this->cats[]=$listaCategorias;
}
return $this->cats;
}
Database table CATEGORY:
| ID | NAME | PARENTCATEGORY |
| 1 | CAT1 | null |
| 2 | CAT2 | null |
| 3 | CAT3 | null |
| 4 | SUB1 | 1 |
| 5 | SUB1 | 2 |
The problem is: How I should do the foreach or foreach'es to make the result look like the order I said before because I only managed to show the category's name.

How to show menu dynamically in Laravel

I'm trying to show menu in laravel dynamically.
I have two table, One holds Main Category and other one Holds Sub category
Here is the structure of Category table
----------------------------------
| id | title | slug | type |
| 1 | title1 | slug1 | Android |
| 2 | title2 | slug2 | Android |
| 3 | title3 | slug3 | Android |
| 4 | title4 | slug4 | Ubuntu |
| 5 | title5 | slug5 | Ubuntu |
----------------------------------
Sub Category Structure
-----------------------------------------------
| id | title | slug | category_of|
| 1 | title1 | slug1 | 1 |
| 2 | title2 | slug2 | 1 |
| 3 | title3 | slug3 | 1 |
| 4 | title4 | slug4 | 2 |
| 5 | title5 | slug5 | 1 |
-----------------------------------------------
Here is What I've tried
<?php
$category = App\Models\Menu::where('categories.type', 'Android')
->select('categories.*', 'sub_category.slug as sub_slug', 'sub_category.title')
->join('sub_category', 'sub_category.category_of', '=', 'categories.id')
->get();
?>
#foreach ($category as $value)
<li class="inner-dropdown-item">
<p>
{{ucwords(str_replace('-', ' ', $value->slug))}}
</p>
</li>
<li class="inner-dropdown-item">
{{ucwords(str_replace('-', ' ', $value->sub_slug))}}
</li>
#endforeach
The Problem I'm facing is, it is duplicating main category every time due to foreach loop, for e.g
<li class="inner-dropdown-item">
<p>
Android
</p>
</li>
<li class="inner-dropdown-item">
Calendars
</li>
<!-- /INNER DROPDOWN ITEM -->
<!-- /This Below Android category should not be shown again -->
<li class="inner-dropdown-item">
<p>
Android
</p>
</li>
<li class="inner-dropdown-item">
Database Abstractions
</li>
As you see it is duplicating main category every time sub category is shown. How can i show Main category Once and then all sub category following under it
I have another Template which has different menu HTML Structure
<!-- MENU ITEM -->
<li class="menu-item sub">
<a href="#">
Designer
<!-- SVG ARROW -->
<svg class="svg-arrow">
<use xlink:href="#svg-arrow"></use>
</svg>
<!-- /SVG ARROW -->
</a>
<div class="content-dropdown">
<!-- FEATURE LIST BLOCK -->
<?php $m_des = ''; ?>
#foreach ($design_category as $des_value)
#if($m_des != $des_value->slug)
<div class="feature-list-block">
<a href="{{ Config::get('constants.url.BASE_URL') }}category/{{$des_value->slug}}/">
<h6 class="feature-list-title">{{ucwords(str_replace('-', ' ', $des_value->slug))}}</h6></a>
<hr class="line-separator">
<?php $m_des = $des_value->slug; ?>
#endif
<!-- FEATURE LIST -->
<ul class="feature-list">
<li class="feature-list-item">
{{ucwords(str_replace('-', ' ', $des_value->sub_slug))}}
</li>
</ul>
<!-- /FEATURE LIST -->
</div>
#endforeach
</div>
</li>
<!-- /MENU ITEM -->
It is generating ul and div again and again which causes html errors
There may be a better solution for it. But you can try this. Do order by categories.id then in loop check main category is printed last time or not
<?php
$category = App\Models\Menu::where('categories.type', 'Android')
->select('categories.*', 'sub_category.slug as sub_slug', 'sub_category.title')
->join('sub_category', 'sub_category.category_of', '=', 'categories.id')
->orderBy('categories.id');
->get();
$latest_category = "";
?>
#foreach ($category as $value)
<?php if($latest_category != $value->slug){ ?>
<li class="inner-dropdown-item">
<p>
{{ucwords(str_replace('-', ' ', $value->slug))}}
</p>
</li>
<?php
$latest_category = $value->slug;
} ?>
<li class="inner-dropdown-item">
{{ucwords(str_replace('-', ' ', $value->sub_slug))}}
</li>
#endforeach
EDIT
<div class="content-dropdown">
<!-- FEATURE LIST BLOCK -->
<?php $m_des = '';
$end_div = '';
?>
#foreach ($design_category as $des_value)
#if($m_des != $des_value->slug)
{{$end_div}}
<div class="feature-list-block">
<a href="{{ Config::get('constants.url.BASE_URL') }}category/{{$des_value->slug}}/">
<h6 class="feature-list-title">{{ucwords(str_replace('-', ' ', $des_value->slug))}}</h6></a>
<hr class="line-separator">
<?php $m_des = $des_value->slug;
$end_div = "</div>";
?>
#endif
<!-- FEATURE LIST -->
<ul class="feature-list">
<li class="feature-list-item">
{{ucwords(str_replace('-', ' ', $des_value->sub_slug))}}
</li>
</ul>
<!-- /FEATURE LIST -->
#endforeach
{{$end_div}}
</div>

Laravel Eloquent ORM many to many relation doesn't work with joining with other table?

Here I have these tables
table 1 => shops
-------------
id | name
table 2 => menus
-------
id | name | category_id
table 3 (pivot table) => menu_shop
---------
id | menu_id | shop_id
table 4 => categories
----------
id | name
I want to get the menus and shops with specific category name then my query is here
$menus =Menu::with('shops')->leftJoin('categories','menus.category_id','=','categories.id')
->where('categories.name','=','Chinese')
->take(6)->get();
then I display in the blade
#foreach($menus as $chinesemenu)
<div class="col-md-6 col-sm-12">
<div class="menu">
<img src="{{ '/images/menus/'. $chinesemenu->image }}" class="menuimg">
<p class="menutitle">{{$chinesemenu->title}} - <span class="menuprice">{{$chinesemenu->price}} Ks</span>
<a data-id="{{$chinesemenu->id}}" data-name="{{$chinesemenu->title}}" data-toggle="modal" data-target="#modalEdit" class="homeorder" ><i class="mdi mdi-cart"></i> </a>
</p>
<p class='menudescription'>
{{$chinesemenu->description}}
</p>
<span class="menushop">
#foreach($chinesemenu->shops as $shop)
{{$shop->name}}
#endforeach
</span>
</div>
</div>
#endforeach
Everything is ok except I only get only one shop from {{$shop->name}} after joining with categories table but it has two shops.
But when I change the query to this
$menus =Menu::with('shops')->take(6)->get();
I got the right output. But I have to join with categories table. help!
Make query like
$menus = Menu::with('shops', 'category')->whereHas('category', function ($query) {
return $query->where('name', '=', 'Chinese');
})->take(6)->get();
And you need relation in Menu
public function category()
{
return $this->belongsTo(Category::class)
}
Now you should get only menus with category named "Chinese". :)
Laravel docs

Categories