Get data from relationship's table - laravel

I am developing webshop. I have the following relations in my model.
shoppingCart -> hasMany -> shoppingCartItem
shoppingCartItem -> belongTo -> shoppingCart
I have in my controller function to get the product_id
$product = Product::find($request->get('product_id'))->first();
in the product table I have relation with the image. I store the image in different table which has only product_id and image_id.
Now my question is can I get
public function getCart(Request $request)
{
// get the shoppingCart
$shoppingCart = $this->loadShoppingCart($request->get('key'));
$carts = [
'amount' => $shoppingCart->total_products,
'price'=>$shoppingCart->total_price
];
// get theimage of the product
$productImage = Image::with('image_id', $request->get('image_id'));
return response()->json(['carts','productImage']);
}

I fixed like that.
$shoppingCart = ShoppingCart::where('key' ,$key)->with('shoppingCartItems', 'shoppingCartItems.product', 'shoppingCartItems.product.images')->first();

Related

Problem in inserting data into many to many relationships using attach() function laravel

i have two tables (orders & products) and one pivot table (order_product).
i have made many to many relationship b\w them using following code.
class Product extends Model{
protected $fillable = ['name', 'price', 'is_iframe_product'];
public function orders() {
return $this->belongsToMany(Order::class);
}
}
class Order extends Model{
public $guaded = ['id'];
protected $fillable = ['is_iframe_order','price', 'status', 'address_id','user_id'];
public function products () {
return $this->belongsToMany(Product::class);
}
}
i am using following code to insert records in CheckoutController.php
$Product = array('name' => $item['item_name'], "price" => $item['price'], "is_iframe_product" => "1");
$saved = order()->products()->attach([$Product]);
but getting this error:
exception: "Symfony\Component\Debug\Exception\FatalThrowableError"
file: "C:\wamp3\www\jewellery\jewellery\app\Http\Controllers\CheckoutController.php"
line: 63
message: "Call to undefined function App\Http\Controllers\order()"
Here's what to do:
First save the product into the database
$product = Product::create(array('name' => $item['item_name'], "price" =>$item['price'], "is_iframe_product" => "1"));
Then attach the saved product with the product's id
$saved = $order->products()->attach($product->id);
What you need to do is create the order first:
$order = new Order;
// set some attributes
$order->save();
Then you can attach the specified product:
$product = Product::find(1);
$order->products()->attach($product->getKey());
If you are creating the product on the fly:
$product = Product::create(array('name' => $item['item_name'], "price" =>$item['price'], "is_iframe_product" => "1"));
$order->products()->attach($product->getKey());
You're using a function: order()->...
And the error says the function doesn't exist: Call to undefined function ... order()
Did you mean to reference a variable, like this? $order->...
It would be helpful if you included the rest of the controller, since I don't know what variables you're using.
Also, your Order model has a typo: $guaded should be $guarded.

One-to-Many relationship between multiple tables

I'm trying to make a relationship between Product and Brand models with an intermediate model BrandProduct, intermediate model also contains some additional info like product_model etc.
My aim is to access all the products that belong to a specific brand with additional manufacturer info and also I want to access the brand of a specific product with additional info.
I've a Model named Product with these attributes
id
name
sku
quantity
etc.....
Another Model named Brand with following attributes
id
name
logo
And an intermediate Model named BrandProduct with attributes
id
brand_id
product_id
model
etc.....
I'm registering Brands and Products separately and making a relationship between them by BrandProduct Model with additional attributes like product_model.
Brand.php model contains:
public function products(){
return $this->hasMany('App\Models\BrandProduct');
}
Product.php model contains:
public function manufacturer(){
return $this->hasOne('App\Models\BrandProduct');
}
And BrandProduct.php model contains:
public function data(){
return $this->belongsTo('App\Models\Product', 'product_id', 'id');
}
public function brand(){
return $this->belongsTo('App\Models\Brand', 'brand_id', 'id');
}
Now I can successfully retrieve Product > Manufacturer by
$p = Product::find(id)->manufacturer
But I can't get inverse relation BrandProduct > Data by trying
$p = BrandProduct::find(id)->data
Similarly I can retrieve all the Brand > Products by
$p = Brand::find(id)->products
But can't get inverse relation
$b = BrandProduct::find(id)->brand
In the end I'd like to achieve something like this:
//For Brand > Products
$p = Brand::find(id)->products;
$product_model = $p[0]->model;
$product_name = $p[0]->data->name;
//For Product > Manufacturer
$p = Product::find(id)->manufacturer;
$product_model = $p->model;
$brand_name = $p->brand->name;
Please tell me what's wrong with my approach all other relationships are working fine except this one.

Find Records Based on Distant belongsToMany > belongsTo Relationship

I'm attempting to display a product page with a list of assets that match a specific asset type. For example, for product "Acme Cream", there are two assets: nutrition-facts.pdf (of type Document) and marketing-video.mp4 (of type Video). On the product page, I'd like to display the first asset that match the 'Video' asset type (if any exist).
I have the following relationships:
The Product model includes a DB column asset_id.
class Product extends Model
{
/**
* The assets that belong to the product.
*/
public function assets()
{
return $this->belongsToMany('App\Asset', 'product_asset');
}
}
The Asset model includes DB columns id and asset_type_id.
class Asset extends Model
{
/**
* Get the asset type that owns the asset.
*/
public function asset_type()
{
return $this->belongsTo('App\AssetType');
}
/**
* The products that belong to the asset.
*/
public function products()
{
return $this->belongsToMany('App\Product', 'product_asset');
}
}
The AssetType model has two DB columns id and name.
class AssetType extends Model
{
/**
* A asset type can have many assets
*/
public function assets()
{
return $this->hasMany('App\Asset');
}
}
How can I efficiently fetch the one product asset by filtering on asset_type? Keep in mind, I've already queried the DB using Product::find(id) and passed that data into the view. Will this require another query (eager loading might help with that). I know I could use a foreach loop, but it seems to me there's gotta be a nicer, more 'eloquent' way.
I'm trying to use it in this situation (pseudo code) on the product detail page (show.blade.php):
if assets matching type 'Video', then display first in this div. Else, don't display the div.
It seems like it should be a simple line:
$product->assets()->asset_type()->where('name', '=', 'Video')->first()
The closest I've come so far to this is this ugly looking thing:
>>> $product = App\Product::with(['assets'])->find(1)
>>> $product->assets()->with(['asset_type' => function ($query) { $query->where('name', '=', 'Video'); }])->get()
However, it still returns all assets, except the "asset_type" attribute is null for those that don't match. Adding ->whereNotNull('asset_type')->get() only results in an error that asset_type column cannot be found.
Also, this sounds like a chance to use the "Has Many Through" relationship, but I'm unclear how to set this up.
Any help is greatly appreciated! Thanks.
You need to eager-load your relationship with filtering:
Assuming you fetch the relationship with your product info
$typeName = 'Video';
$product = App\Product::with([
'asset' => function($query) use($typeName) {
//Filter asset by type
//See: https://laravel.com/docs/5.6/eloquent-relationships#constraining-eager-loads
return $query->whereHas('asset_type',function($query) use($typeName) {
//Filter where the type's name equals..
//Each query is relative to its scope, in this case the 'type' relationship which refers to your 'type' Model
return $query->where('name','=',$typeName);
});
},
//Nested relationship loading: https://laravel.com/docs/5.6/eloquent-relationships#querying-relations
'assets.asset_type'
])
->find(1);
$assets = $product->assets;
Assuming you fetch only the assets
$productId = 1;
$typeName = 'Video';
//Returns a collection of eloquent models
$assets = Asset::whereHas('product',function($query) use ($productId) {
//Filter product by its id
return $query->where('id','=',$productId);
})
->whereHas('asset_type',function($query) use ($typeName) {
//Filter type by its name
return $query->where('name','=',$typeName);
})
->get();

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.

Eloquent relationship in custom pivot table

I might be overcomplicating things, but here's relationship I'm trying to write in Eloquent (Laravel 5):
I have a list of products and price lists. Each product can have many price lists. This is easy to do, but here's another thing - for every product <> price list assignment I can have many prices based on quantity, so it's like:
productID: 1010
priceListId: 1
min quantity: 1 -> price 10.00
min quantity: 5 -> price 9.50
min quantity: 10 -> price 9.00
productID: 1010
priceListId: 2
min quantity: 1 -> price 15.00
min quantity: 40 -> price 14.00
min quantity: 90 -> price 12.00
I think I know how to create custom pivot table although I don't know how to use it. I followed this link now I'm not sure if my code is correct and how to use it.
At the moment I have:
Product model:
class Product extends Model {
public function pricelists()
{
return $this->belongsToMany('PriceList');
}
public function newPivot(Model $parent, array $attributes, $table, $exists)
{
if ($parent instanceof PriceList)
{
return new ProductPricePivot($parent, $attributes, $table, $exists);
}
return parent::newPivot($parent, $attributes, $table, $exists);
}
}
PriceList model:
class PriceList extends Model {
public function products()
{
return $this->belongsToMany('Product');
}
public function newPivot(Model $parent, array $attributes, $table, $exists)
{
if ($parent instanceof Product)
{
return new ProductPricePivot($parent, $attributes, $table, $exists);
}
return parent::newPivot($parent, $attributes, $table, $exists);
}
}
Pivot:
class ProductPricePivot extends Pivot {
public function product()
{
return $this->belongsTo('Product');
}
public function pricelist()
{
return $this->belongsTo('PriceList');
}
public function prices()
{
return $this->hasMany('ProductPrice');
}
}
Now ProductPrice extends Model again and is just a standard model without any additional methods.
Is this correct? If so, then following example from above, how can I add new quantity/price level to price list 1 on product 1010?
At the moment, when creating relationships, I'm doing:
$productID = 1010;
$priceListID = 1;
$priceList = PriceList::find($priceListID);
$priceList->products()->attach($productID);
$productToPriceList = $priceList->products()->find($productID);
And I'm lost here... I find this relationship, but how can I now attach next quantity <> price level to it?
Can someone please give an example of how to use such relationship or links to pages where I can find something more about it? And yes, I check Laravel documentation, and yes, I googled it as well.
Thank you!
As you described the case, I see here two types of relationships:
Many-to-Many relationship between Product & PriceList
Many-to-One relationship between PriceList & ProductPrice (which holds the "min-quantity" and "price") values.
I'm assuming that you don't need the same price condition for many "price-list"s. Every list will have it's price conditions.
Many-to-one relationship doesn't require pivot table.
Follow this link, you'll find that laravel Eloquent system helps you much.
You need 4 tables: products, price_lists, product_prices, products_to_pricelists (the pivot)
the products_to_pricelists table look like that:
*====*============*===============*
| id | product_id | price_list_id |
*====*============*===============*
Now the models:
Products:
class Product extends Eloquent {
protected $table = 'products';
public function price_lists()
{
return $this->belongsToMany('PriceList', 'products_to_pricelists', 'price_list_id');
}
}
Price lists:
class PriceList extends Eloquent {
protected $table = 'price_lists';
public function prices()
{
return $this->hasMany('ProductPrice');
}
}
Prices:
class ProductPrice extends Eloquent {
protected $table = 'product_prices';
}
Now it's easy:
$productID = 1010;
$list_id = 1;
$theProduct = Product::find( $productID );
$theProductPriceLists = $theProduct->price_lists; // Don't use parens
$theList = Product::find( $productID )->price_lists()->where('price_lists.id', $list_id)->first(); // Here you use parens
$theListPrices = $theList->prices; // Again no parens
Laravel just manage for you the pivot-connection!
Hope that's help

Resources