Laravel many-to-many polymorphic relationship - custom methods/relationships on pivot - laravel

I have an issue with a many-to-many polymorphic relationship (diagram below). In a food shop some products have options/variants, e.g. pizza comes in variants of 7inch, 12inch, 16inch. When pizza is added to cart a variant must be selected.
When an order is saved
- bought products (without variants) are saved in the orderables table
- variants that are bought are saved in variant_orderables table
Btw, the pivot tables are called orderables and variant_orderables instead of what you might expect according to Laravel conventions, e.g. "customer_order_product", because in addition to customer_orders, the products and variants are also in a polymorphic relationship with stock_orders (where the shop buys those items from suppliers). I just didn't show all that on the diagram to keep it simple.
Anyway, bought items, be they products or variants, can have "extras" added to them in the order. E.g. A pizza can have extra cheese, or pepperoni as extras (info contained in the extras_groups_offers table).
ordered_extras is where we will list the product or variant id of the extras that have been ordered, along with the orderables or variant_orderables id that the extras are applied on.
So between variants and customer_orders, variant_orderables is the pivot, but then variant orderables has a relationship with extras_groups_offers with ordered_extras as the pivot.
I know I probably need to do something with newPivot, but as this involves a few polymorphic many-to-many relationships, I'm not exactly sure how to go about it. If anyone could give me a simple example solution, I'd be very grateful.
Basically, I am trying to reach a stage where I can eager load all the necessary information for an order, including products/variants ordered, and all the ordered extras for each product/variant that has been ordered. I just don't know how to go about it.
Thanks.

I've overcome the problem by making the orderables and variant_orderables tables as normal models. This means I do have more chaining to do in terms of relationships, but I can at least eager load multiple nested layers easily, e.g. order.orderProducts.extrasGroupsOffers
(P.S. orderables has been renamed to order_product, if you're wondering where that came from)

Related

Laravel models, database and pivot tables question

Hello I am working with Laravel,
I have to create two simple models, let's say Stores and Books.
Stores can have one or multiple Books and Books can belong to many Stores.
Of course I will use a many to many relationship, with a pivot table.
Books the can have different prices depending the store.
I think a separate table can only complicate things, in my mind the pivot table associating books and stores should have a price column, but pivot tables only contains store_id and book_id.
Should I create a book_prices and associate it with books and to stores? What is the best approach?
You are free and able to set other attributes on your pivot table. You can read more about it in the docs.
https://laravel.com/docs/9.x/eloquent-relationships#retrieving-intermediate-table-columns
You have to define the relationship accordingly, the following should clarify how this works. In this example you use the many-to-many relationship and add the price column to every retrieved pivot model.
public function books()
{
return $this->belongsToMany(Book::class)
->withPivot('price')
}
For example, you are able to access the pivot column in a loop like this
foreach ($shop->books as $book)
{
echo $book->pivot->price;
}
You can define additional columns for your pivot table in the migration for the pivot table, and then when defining the relationship use withPivot to define the additional columns so they come through in the model:
return $this->belongsToMany(Book::class)->withPivot('price');
(Adapted from the Laravel documentation, see https://laravel.com/docs/9.x/eloquent-relationships#retrieving-intermediate-table-columns)
Depends on the complexity of your case, but yes, you have two options for it. Let's say that the pivot table is called as book_store:
Directly adds price column to book_store. This is obviously the simpler option. The drawbacks are:
The history of the price changes isn't logged. You'll have to create another table for logging if you want to keep this history information.
Changes made to price will directly change the price of the related book_store record. Meaning that a price is being updated "live" e.g users cannot update the price now but "publish" it some time later just like this example in the doc.
Create a new, different table to store the price. This may seems relatively more complex, but it may also be more future-proof.
Basically, you get 2 things that you miss in the first option above.
Don't think too much about book_store being a pivot table. One way to see it is like this: book_store IS a pivot table from books and stores tables viewpoints, but it's also just a normal SQL table which could relate to any other tables using any kind of relationships.
If you want to implement this, make sure to create a primary-key in the book_store table.
Alast, it all depends on what you need. Feel free to ask if you need more insight about this. I hope this helps.

Inverse of belongsToMany

I got two Models:
Order
Invoice
Each Order can have many Invoices - and an Invoice can belong to many Orders.
So I can search for an Order and check: "Hey, which Invoices have been created for this Order?"
The other way round each Invoice can belong to multiple Orders, because maybe a customer ordered two products on the same day and so it would be great he'd only get one Invoice, which includes both orders.
So this is how I did this:
Invoice
public function orders()
{
return $this->belongsToMany(Order::class);
}
Order
public function invoices()
{
return $this->belongsToMany(Invoice::class, 'invoice_order');
}
This does work - but it does not seem right to change the table to the intermediate table invoice_order here. Do you have any thoughts on this? :-)
Thanks in advance for your thoughts :-)
Seperating the relation into a seperate pivot table is the commonly used method in laravel (and in most other frameworks) for many to many relationships.
It's easy to maintain, easy to get related models using many to many relationship, and if someone else needs to work on it in the future, they'll probably have used it in the past as well so wouldn't end up burning their heads.
The other method you could use is to create a json column on one of the tables (you can create on both tables as well if you want, but that's just extra overhead). Then you can store the ids of the related models in this json column. You can then join the tables using the json related commands provided by your database. Eloquent does not support relationships on json, but you can use this package staudenmeir/eloquent-json-relations to build relationships on json fields.
So overall, I'd suggest keeping a pivot table like the standard way, but if that just won't do, then you can try the json column method

Laravel 5 bilingual Product model

I am looking for the most straightaway solution and breaking my head about implementing a bilingual Product model with only one basic requirements: the product query should only deliver results where the product name in the app()->locale language is set.
I'm stuck right at the beginning to decide wether I should keep completely different models (Product_en and Product_es), this would make querying easiest I guess, or have just one Product model with the English texts, with hasOne() methods pointing to the Spanish translations? In the latter case, how would I effectively query for entries which have translations?
Thanks a lot for any hints. Cheers.
I would create a language property for the Product model and would add a Scope for this, where you can filter the results with the value of App::getLocale().
This way, any time you just query the product, you get the Product models on the actually selected language.

Parse Relations: which Class should own it?

Using Parse.com "Relations", how do you determine which of the 2 classes should own the Relation?
For example think of WhatsApp groups.
Should User have a relation listing all the groups it subscribes to?
Or should Group have a relation listing all the users in the group?
And, does it make sense to have a relation in each? Duplicating the data?
Depends on if you want to store some metadata in one of the Classes. It is explained quite nicely in this part of the document:
https://parse.com/docs/relations_guide#manytomany-relations
The decision point here is whether you want to attach any metadata to
the relationship between two entities. If you don’t, Parse Relation or
using Arrays are going to be the easiest alternatives. In general,
using arrays will lead to higher performance and require fewer
queries. If either side of the many-to-many relationship could lead to
an array with more than 100 or so objects, then, for the same reason
Pointers were better for one-to-many relationships, Parse Relation or
Join Tables will be better alternatives.
In the whatsapp you have given, Since you have access to user, i think it should be more like what are the groups that user belongs to. Read the many to many relations assuming group as book and users as author. It will make sense

CodeIgniter Cart ID + Options

I have a situation:
I have products that are in a CodeIgniter Cart custom store.
Each product has an ID associated with it, but also has options for it (sizes).
These sizes all have different prices. (We're talking about photos being sold at different print sizes).
Because CI Cart updates, adds and deletes based on the product ID inserted, I am not able to insert one product with 2 different sizes.
As of now, the only solution I can think of is to pass the ID to the cart as IMAGEID_OPTIONID so that it contains both IDs.
However, I thought there might be an easier, more uniform way of doing this?
Or a better solution than an ID that isn't (on it's own) associated with anything specific unless i explode it..?
I recently built a site that had these constraints. In short, you'll want to create a distinction between "products" and "product groups". Think of it as managing the most discrete data units. In reality, shirt X sized medium is actually a different thing than shirt X sized large...doubly so if you have prices that are built on these qualities (this becomes more realistic when you consider cloth patterns or colors).
So anyway, if you have a "groups" table, a "product_groups" table, and a "products" table, you can keep all of these ideas distinct. On your products table, you can have columns for "size" and "color" (and any other distinguishing property you can think of) and a column for "price". Alternatively, you can go even more hardcore and make separate pricing tables that match up prices to unique products (this would be especially useful if you want to keep track of historical prices and discounts).
Then in your cart you can simply attach product_ids to cart_ids and perform a couple of joins to determine what "group" this product is a part of, what pictures are in that group (or exist for that product), and so on. It's not a simple problem, but following this line of thought should help get you on the right path.
One last point: keeping track of unique products like this also makes inventory accounting much, much more straightforward.

Resources