I have relationships like the following:
Category -> Subcategory -> Product -> Price
A Category contains X Subcategories.
A Subcategory contains X Products.
A Product contains X Prices (New Price, Old Price, One Record per Price Change)
I wanted to do the following:
#foreach($categories as $category)
[...]
#foreach($category->subcategories as $subcategory)
[...]
#foreach($subcategory->products as $product)
[...]
#foreach($product->prices as $price)
[... #endforeach x4 ...]
The 3 first levels are working. When using the 4th however ($product->prices) I get an Trying to get property of non-object error.
The relationships in the Models:
Category.php
class Category extends Model
{
public function subcategories()
{
return $this->hasMany('App\SubCategory');
}
}
SubCategory.php
class SubCategory extends Model
{
public function category()
{
return $this->belongsTo('App\Category');
}
public function products()
{
return $this->hasMany('App\Product');
}
}
Product.php
class Product extends Model
{
public function category()
{
return $this->belongsTo('App\Category');
}
public function subcategory()
{
return $this->belongsTo('App\SubCategory');
}
public function price()
{
return $this->hasMany('App\ProductPrice');
}
}
ProductPrice.php
class ProductPrice extends Model
{
public function product()
{
return $this->belongsTo('App\Product');
}
}
This is what I send to my View:
class PageController extends Controller
{
public function showMainPage()
{
$categories = Category::with('subcategories')->get();
$data = array(
"categories" => $categories,
);
return view('index')->with($data);
}
}
This worked fine, even with Products but began to have errors when using the ProductPrices.
As #GONG said, change your code for use eager load, this will run so much faster than use some foreaches.
See laravel docs: https://laravel.com/docs/5.3/eloquent-relationships#eager-loading
Related
Been having a hard time on figuring out how to implement updating records on a nested createMany based on the store method. I have these models and relations:
User Model:
class User extends Model
{
public function orders() {
return $this->hasMany(Order::class);
}
}
Order Model:
class Order extends Model
{
public function user() {
return $this->belongsTo(User::class);
}
public function subOrders() {
return $this->hasMany(SubOrder::class);
}
}
SubOrder Model:
class SubOrder extends Model
{
public function order() {
return $this->belongsTo(Order::class);
}
public function subOrderProducts() {
return $this->hasMany(SubOrderProducts::class);
}
}
SubOrderProducts Model:
class SubOrderProducts extends Model
{
public function subOrder() {
return $this->belongsTo(SubOrder::class);
}
}
Here are the tables:
orders table:
id name
sub_orders table:
id order_id date price
sub_order_products table:
id sub_orders_id product_id
Then on the store method:
public function store(StoreOrderRequest $request) {
$order = auth()->user()->orders()->create($request->validated());
$order_subs = $order->subOrders()->createMany($request->orders);
$order_sub_products = $request->only('subproducts');
foreach ($order_subs as $key => $value) {
$order_sub->subOrderProducts()->createMany($order_sub_products[$key]['products']);
}
}
What I wanted to achieve is to update or create those sub orders and sub order products. If the sub order is already existing, then update, otherwise create a new record with those corresponding sub order products.
Here's what I've tried so far:
public function store(UpdateOrderRequest $request, Order $order) {
$order->update($request->validated());
$order_subs = $order->subOrders()->updateMany($request->orders);
$order_sub_products = $request->only('subproducts');
foreach ($order_subs as $key => $value) {
$order_sub->subOrderProducts()->updateMany($order_sub_products[$key]['products']);
}
}
It's not working as expected since the order subs is only a single record. What's the best way or the right process for updating/creating these records? Thanks.
I'm developing a Laravel 5.8 project. Trying to display a Product list page that belongs to a brand. The products should be listed under their category like:
(Page of Brand 1)
Category 1
Product xxx
Product yyy
...
Category 2
Product zzz
...
I have 'products' table, 'brands' table and 'categories' table with foreigns set in migrations.
Model files are:
Product.php
class Product extends Model
{
...
public function category()
{
return $this->belongsTo('App\Category');
}
public function brand()
{
return $this->belongsTo('App\Brand');
}
}
Category.php
class Category extends Model
{
...
public function products()
{
return $this->hasMany('App\Product');
}
}
Brand.php
class Brand extends Model
{
...
public function products()
{
return $this->hasMany('App\Product');
}
}
Product controller as follows:
ProductsController.php
public function product_industrial()
{
// BRAND id IS HARDCODED, DOESN'T MATTER
$products = Product::with('category')->where('brand_id',2)->where('isActive', true)->orderBy('order', 'asc')->get();
return view('frontend.products_industrial', compact('products'));
}
product_industrial.blade.php
<!-- JUST AN EXAMPLE -->
#foreach($products as $product)
<h1>{{$product->category->name}}</h1>
#foreach($products as $product)
<h2>{{$product->name}}</h2>
<p>{{$product->text}}</p>
#endforeach
#endforeach
How can i display the products of the brand grouped by products' categories?
I would like to retrieve all products of chosen parent category.Product model have hasmany relation to product_category_mapping table.
If product have subcategory result like,
"MAinCatergory":[
{
id="",
name:"Drinks",
"ChildCategory":[
{
"id":1,
"name":"Juce",
"Products":[{
name:"apple juce",
price:10,
....
}]
}
]
}
]
}
If product under main category only return array like,
"MAinCatergory":[
{
id="",
name:"Drinks",
"Products":[{
name:"apple juce",
price:10,
....
}]
}
}
]
}
category table fields - id,name,parent_id
product table fields - id,name,price,..,
product-category-mapping table fields - id,category_id,product_id
category model
public function children()
{
return $this->hasMany('App\Models\Category', 'parent_id');
}
public function parent()
{
return $this->belongsTo('App\Models\Category', 'parent_id');
}
public function product_category()
{
return $this->hasMany('App\Models\ProductCategoryMapping', 'category_id');
}
product model
public function product_category()
{
return $this->hasMany('App\Models\ProductCategoryMapping','product_id');
}
product-category_mapping
public function product()
{
return $this->belongsTo(Product::class,'product_id','id');
}
public function category()
{
return $this->belongsTo(Category::class,'category_id','id');
}
Something like this might suffice.
App\Models\Category::with('children', 'product_category.product')->get()
Suggestion, try implement pivot many to many relation instead this product_category_mapping, then model relation would change a bit.
For pivot relation, you need to modify the Category model
public function products()
{
return $this->belongsToMany('App\Models\Product', 'product-category-mapping');
}
and in product Model
public function categories()
{
return $this->belongsToMany('App\Models\Category','product-category-mapping');
}
Note:This is not the complete integration, but to give you an idea, for full logic see https://laravel.com/docs/9.x/eloquent-relationships#many-to-many
in your product model add like this:
public function product_categorys(){
return $this->hasMany('App\Models\ProductCategoryMapping','product_id');
}
and in controller you can get inside your function like this Product::with('product_categorys')->get();
I am trying to reach the last laravel model from the first one with eloquent relationships. How can I reach the Subcategory directly from Product?
The 3 Models I have:
Product (id, category_id, etc..)
public function categories()
{
return $this->belongsTo('App\Category', 'category_id');
}
Category (id, name)
public function products()
{
return $this->hasMany('App\Product', 'category_id');
}
public function sub_categories()
{
return $this->hasMany('App\SubCategory', 'category_id');
}
SubCategory (id, category_id, name)
public function categories()
{
return $this->belongsTo('App\Category', 'category_id');
}
I would've assumed I could reach it with
Product::find(1)->categories->sub_categories;
Am I missing something obvious here?
read this docs
Product
class Product extends Model
{
public function SubCategory()
{
return $this->hasManyThrough('App\Category', 'App\SubCategory');
}
}
In Addition add the subCategories method on Product model and also a product is belongs to a category not categories
and also always try to use camel case for the methods (subCategories)
replace your code with this
Product:
public function category()
{
return $this->belongsTo('App\Category', 'category_id');
}
public function subCategories()
{
return $this->category()->subCategories;
}
Category:
public function products()
{
return $this->hasMany('App\Product', 'category_id');
}
public function subCategories()
{
return $this->hasMany('App\SubCategory', 'category_id');
}
SubCategory:
public function categories()
{
return $this->belongsTo('App\Category', 'category_id');
}
finally use this to get the subcategories
Product::find(1)->subCategories;
Product::find(1)->categories is an array. You will have to loop it to get the subcategory of each category. See below
$categories = Product::find(1)->categories;
foreach ($categories as $category {
//Get subcategories for each category
dump($category->sub_categories);
}
I have a problem with a many to many relationship and the translations of the terms.
I have 4 tables:
products
- id, price, whatever
products_lang
- id, product_id, lang, product_name
accessori
- id, active
accessori_lang
- id, accessori_id, lang, accessori_name
I'm trying to assign accessories to products with an intermediate table named:
accessori_products
this is the model for Product:
class Product extends Model {
protected $table = 'products';
public function productsLang () {
return $this->hasMany('App\ProductLng', 'products_id')->where('lang','=',App::getLocale());
}
public function productsLangAll() {
return $this->hasMany('App\ProductLng', 'products_id');
}
public function accessori() {
return $this->belongsToMany('App\Accessori', 'accessori_products');
}
}
this is the model for productLng:
class ProductLng extends Model {
protected $table = 'products_lng';
public function products() {
return $this->belongsTo('App\Product', 'products_id', 'id');
}
}
Then I have the model for Accessori:
class Accessori extends Model {
protected $table = 'accessori';
public function accessoriLang() {
return $this->hasMany('App\AccessoriLng')->where('lang','=',App::getLocale());
}
public function accessoriLangAll() {
return $this->hasMany('App\AccessoriLng');
}
public function accessoriProducts() {
return $this->belongsToMany('App\Products', 'accessori_products', 'accessori_id', 'products_id');
}
}
And the model for AccessoriLng:
class accessoriLng extends Model {
protected $table = 'accessori_lng';
public function accessori() {
return $this->belongsTo('App\Accessori', 'accessori_id', 'id');
}
}
the last model is for the relationship between the two tables above:
class ProductAccessori extends Model {
protected $table = 'accessori_products';
public function accessoriProducts() {
return $this->belongsTo('App\Product', 'accessori_id', 'products_id');
}
}
I'm trying to get the accessories of each product and to get also the translation but I'm having a lot of problem with this.
It's my first time with a many to many relation with translations too.
Can anyone put me on the right direction?
controller
$products = Product::has('accessori')->with([
'productsLang ',
'accessori' => function ($accessori){
$accessori->with([
'accessoriLang'
]);
}
])->get();
return $products;
you'll get products with accessori that has accessoriLang.