Laravel 4 finding collection based on relationship with 2 other models - laravel-4

I have models like this:
have a table (product_types) of product types.
have a table (products) of products with a many-to-one relationships to the product types table.
have a table (attribute_types) of attribute types.
have a table of (many-to-many) relationships between product types and attribute types
have a table (attributes) containing attribute type, attribute value.
have a table of (many-to-many) relationships between products and attributes.
There are a few main things I need to do with this collection
$product_type = ProductType::find(1);
Find all the products for a product type.
return $product_type->products;
Find all the attribute types for a product type
return $product_type->attribute_types;
Find all the attributes for the attribute type and product type. I know the problem here is I need attributes to be the children of product type and attribute type.
But, I'm not sure the best way to do this.

Setup relations like in docs http://laravel.com/docs/eloquent#relationships
Then you can get collection you want like this:
//return $product_type->products;
$product_type->load('products')->products; // returns Eloquent Collection of products
// or shorter equivalent:
$product_type->products;
//return $product_type->attribute_types;
the same as above since the relationships are identical (many-to-many)
// Then to get Attributes:
$product_type->load('products.attributes');
//then you can get all attributes as a single array (every attr as an array not model):
$attributesArray = $product_type->products->fetch('attributes')->collapse();
// or without casting merge all Attributes in a loop:
$attributesCollection = new \Illuminate\Database\Eloquent\Collection;
foreach ($product_type->products as $product)
{
$attributesCollection = $attributesCollection->merge($product->attributes);
}

Related

Eloquent custom relationship hasMany (foreign field contains text concatenated by foreign key)

I have this database structure. 2 tables: shipment_out, stock_move.
shipment_out has the typical primary key integer id field.
stock_move has a field named shipment which is string type. This field can have these values:
"stock_shipment_out,1512",
"stock_shipment_in,65400",
"sale.line,358",
(...)
The thing is the table stock_move is related to a multiple tables based on the same field, so it has this text before.
In this case I want to define the relationship: shipment_out hasMany stock_move.
So I need to join by stock_move.shipment has this value: 'stock_shipment_out,{id}'.
So how can I define this relationship? Would be something like:
public function stockMoves()
{
return $this->hasMany(StockMove::class, 'shipment', 'stock.shipment.out,id');
}
I can achieve this relationship with query builder:
$shipments = ShipmentOut
::join('public.stock_move', DB::raw('CONCAT(\'stock.shipment.out,\',public.stock_shipment_out.id)'), '=', 'stock_move.shipment')
->where('stock_shipment_out.id', '=', $shipmentOut);
But I need on a relationship too...
To solve this problem I had to define a custom attribute, and then I can define the relationship with this field.
public function getStockMoveShipmentAttribute()
{
return "stock.shipment.out,{$this->id}";
}
public function stockMoves()
{
return $this->hasMany(StockMove::class, 'shipment', 'stock_move_shipment')
}
Now I can use this relationship, but it's only one-direction...
If I want to define the same relationship as the inverse it doesn't work.
I opened another question explaining it: Laravel relationship based on custom attribute not working both directions

Is there any way to cast a relationship table attribute in laravel?

I have a users model with a carts function that returns all carts detail after joining three tables. I would like to convert an attribute to an array which is a JSON type.
Example: I have four table users, carts, item_detail_informations, and item_details tables where item_details table picture column is a JSON type. I want to convert picture JSON data to an array.
My carts function is like this.
public function carts()
{
return $this->hasMany('App\Models\Cart')
->join('item_detail_informations', 'carts.item_detail_information_id','=','item_detail_informations.id')
->join('item_details', 'item_detail_informations.item_detail_id','=','item_details.id')
->join('items', 'item_details.item_id','=','items.id')
->select('carts.user_id','carts.item_detail_information_id','item_detail_informations.size','item_detail_informations.price','item_detail_informations.item_detail_id', 'item_details.picture','item_details.item_id')
;
}
I am trying to cast picture attribute like this.
protected $casts = [
'item_details.picture' => 'array',
];
But it's not working. Is there any way to convert the picture attribute to JSON?
Remove all joins in carts method(instead use eager loading via with). And cast attribute in the ItemDetail model. it will automatically picked up when you call carst method. Hope it will help you
You need to use eager loading instead

One To Many with pivot not possible. How to redesign relationships?

I would like to do the following:
Product can have one Supplier. The Supplier contains some data like a name. Additionally there is a pivot-value that should be stored for Supplier that is assigned to Product (e.g. a delivery_service-string).
Example:
Product: A yummy Banana
Supplier: Banana Inc
-> If the Product "A yummy Banana" is supplied by Supplier it should be delivered by DHL. The important thing: You can not add DHL as a field to Supplier, as each Product to Supplier-relation should have it's own delivery-service-field.
As there can be many Products but each Product can only have one Supplier I thought about something like this:
Product
Schema:
- id
- supplier_id
Relation
public function supplier()
{
return $this->belongsTo(Supplier::class);
}
Supplier
Schema:
- id
- name
Relation
public function products()
{
return $this->hasMany(Product::class);
}
This works, but unfortunately I can not store pivot data in the supplier() relation.
At the moment I could imagine to store the value not in a pivot table but in a new row in the Product's schema. But I don't think this is the best way.
Any suggestions? :-)
One item have many childs
This is one-to-many
You need to store item_id in your child table
Item Table
id, name
Child Table
id, item_id, type
If you have a case EG
Each child can have a favorite item then you will have to create a many-to-many relation between them. (Which will be a separate relation)
Create a table "child_item" (pivot)
Child Item Table
child_id, item_id
then create a relation in your laravel
class User extends Model{
...
public function favorites(){
return $this->belongsToMany(Items::class); // Include the path using "use" on top
}
}
So now you get your 2 relations between child and item
One item can have many children
Many children can mark items as favorites

belongsToMany with nullable foreign - Laravel 5.8

in my Laravel project i get this database structure:
Products
Id
Name
Orders
Id
Total
Order_Product
Product_id (nullable)
Order_Id
Details
In my Order model I make belongsToMany retaltionship with Product model:
public function products() {
return $this->belongsToMany(Product::class)->withPivot('Details');
}
The Problem is when I try to get the Order Products Collection
$order->products();
I don't get rows with nullable product_id, Any solution please ? Thank you.
Laravel support "Null Object Pattern" since version 5.5 which allows you to define a default model that will be returned if the given relationship is null.
Try using the following code:
public function products() {
return $this->belongsToMany(Product::class)->withDefault()->withPivot('Details');
}
Most likely, you don't get "nullable" products because you have a relation Order->Products. When you call $order->products(), eloquent tries to get all Product entities that are connected to your Order via product_id field. So, if field is empty, then you can't get Product because there is no connection.
One of the solutions is:
create another entity like OrderLine(Order_Product table); add methods like $orderLine->details() and relation to Product like $orderLine->product()
add relation to OrderLine inside Order - $order->line() or $order->info() etc. -> Order hasMany OrderLine
then use $order->line() to get an order's details and products (if exists)
p.s. I've compiled it in my head so it might need some code adjustments.
Good luck

Replace the column name in the magento collection while loading it

I have a custom module and I am loading a collection like following
$collection = Mage::getModel('module/product')->getCollection()
->addFieldToFilter('sku',$sku);
There is field named as prod_id in the database. Can I get this as entity_id while loading the collection?
If yes. Please help how to do this.
First of all all
addAttributeToFilter() is used to filter EAV collections.
addFieldToFilter() is used to filter Non-EAV collections.
EAV-models are for example product, customer, sales, etc so you can use use addAttributeToFilter() for those entities.
addFieldToFilter() is mapped to `addAttributeToFilter()` for `EAV` entities. So you can just use `addFieldToFiler().`
You can have a look in app/code/core/Mage/Eav/Model/Entity/Collection/Abstract.php where the Mapping is done:
public function addFieldToFilter($attribute, $condition = null) {
return $this->addAttributeToFilter($attribute, $condition);
}
If you are using custom module then you can directly use addFieldToFilter() with your column name
Like
$collection = Mage::getModel('module/model')->getCollection()
->addFieldToFilter('column_name',$data);
Let me know if you have any query

Resources