PHP noob here.
I have an Item model which is responsible for adding items to my cart.. However the items I'm adding are not simple products. Each item type has a complicated formula for generating a customized quote based on the users selections and personal discount, etc.
The simplest way I can think to do this is to have functions for each product within the item model with each unique formula in. However, this will get messy very fast.
What is the best practice for splitting these into separate files and then including those files in the model, just for keeping my code clean and seperate?
So for example I have aircraft, cars, boats as categories, each product within each category has it's own formula but I at least want to keep aircraft formulas separate from boat for ease of reading.
Is it best to create an aircraft model, boats model etc and have them all use the items DB table and then once they are added I can control them all from the Item model?
I may have just answered my own question, but I don't know :D Learning loads but still a noob.
I would suggest two things:
Extract logic from models
I would extract as much of the business logic as possible from the models - to, say, several formula classes (one for each different formula), which you can easily execute wherever you need to.
If the data you will save differs between each type, you may want to look into...
Polymorphic relationships
See the laravel docs on this for specifics.
You would have a Product model, that has a polymorphic morphTo relationship (called "type", maybe) to several other "product type" models (that all have an inverse morphOne back to the Product).
Polymorphic relationships were the first thing i thought of while reading your question, but on re-reading it, the data structure for each type might not be different. If that's the case, ignore the polymorphic bit!
Related
I do not have much experience in table design. My goal is to create one or more product tables that meet the requirements below:
Support many kinds of products (TV, Phone, PC, ...). Each kind of product has a different set of parameters, like:
Phone will have Color, Size, Weight, OS...
PC will have CPU, HDD, RAM...
The set of parameters must be dynamic. You can add or edit any parameter you like.
How can I meet these requirements without a separate table for each kind of product?
You have at least these five options for modeling the type hierarchy you describe:
Single Table Inheritance: one table for all Product types, with enough columns to store all attributes of all types. This means a lot of columns, most of which are NULL on any given row.
Class Table Inheritance: one table for Products, storing attributes common to all product types. Then one table per product type, storing attributes specific to that product type.
Concrete Table Inheritance: no table for common Products attributes. Instead, one table per product type, storing both common product attributes, and product-specific attributes.
Serialized LOB: One table for Products, storing attributes common to all product types. One extra column stores a BLOB of semi-structured data, in XML, YAML, JSON, or some other format. This BLOB allows you to store the attributes specific to each product type. You can use fancy Design Patterns to describe this, such as Facade and Memento. But regardless you have a blob of attributes that can't be easily queried within SQL; you have to fetch the whole blob back to the application and sort it out there.
Entity-Attribute-Value: One table for Products, and one table that pivots attributes to rows, instead of columns. EAV is not a valid design with respect to the relational paradigm, but many people use it anyway. This is the "Properties Pattern" mentioned by another answer. See other questions with the eav tag on StackOverflow for some of the pitfalls.
I have written more about this in a presentation, Extensible Data Modeling.
Additional thoughts about EAV: Although many people seem to favor EAV, I don't. It seems like the most flexible solution, and therefore the best. However, keep in mind the adage TANSTAAFL. Here are some of the disadvantages of EAV:
No way to make a column mandatory (equivalent of NOT NULL).
No way to use SQL data types to validate entries.
No way to ensure that attribute names are spelled consistently.
No way to put a foreign key on the values of any given attribute, e.g. for a lookup table.
Fetching results in a conventional tabular layout is complex and expensive, because to get attributes from multiple rows you need to do JOIN for each attribute.
The degree of flexibility EAV gives you requires sacrifices in other areas, probably making your code as complex (or worse) than it would have been to solve the original problem in a more conventional way.
And in most cases, it's unnecessary to have that degree of flexibility. In the OP's question about product types, it's much simpler to create a table per product type for product-specific attributes, so you have some consistent structure enforced at least for entries of the same product type.
I'd use EAV only if every row must be permitted to potentially have a distinct set of attributes. When you have a finite set of product types, EAV is overkill. Class Table Inheritance would be my first choice.
Update 2019: The more I see people using JSON as a solution for the "many custom attributes" problem, the less I like that solution. It makes queries too complex, even when using special JSON functions to support them. It takes a lot more storage space to store JSON documents, versus storing in normal rows and columns.
Basically, none of these solutions are easy or efficient in a relational database. The whole idea of having "variable attributes" is fundamentally at odds with relational theory.
What it comes down to is that you have to choose one of the solutions based on which is the least bad for your app. Therefore you need to know how you're going to query the data before you choose a database design. There's no way to choose one solution that is "best" because any of the solutions might be best for a given application.
#StoneHeart
I would go here with EAV and MVC all the way.
#Bill Karvin
Here are some of the disadvantages of
EAV:
No way to make a column mandatory (equivalent of NOT NULL).
No way to use SQL data types to validate entries.
No way to ensure that attribute names are spelled consistently.
No way to put a foreign key on the values of any given attribute, e.g.
for a lookup table.
All those things that you have mentioned here:
data validation
attribute names spelling validation
mandatory columns/fields
handling the destruction of dependent attributes
in my opinion don't belong in a database at all because none of databases are capable of handling those interactions and requirements on a proper level as a programming language of an application does.
In my opinion using a database in this way is like using a rock to hammer a nail. You can do it with a rock but aren't you suppose to use a hammer which is more precise and specifically designed for this sort of activity ?
Fetching results in a conventional tabular layout is complex and
expensive, because to get attributes
from multiple rows you need to do JOIN
for each attribute.
This problem can be solved by making few queries on partial data and processing them into tabular layout with your application. Even if you have 600GB of product data you can process it in batches if you require data from every single row in this table.
Going further If you would like to improve the performance of the queries you can select certain operations like for e.g. reporting or global text search and prepare for them index tables which would store required data and would be regenerated periodically, lets say every 30 minutes.
You don't even need to be concerned with the cost of extra data storage because it gets cheaper and cheaper every day.
If you would still be concerned with performance of operations done by the application, you can always use Erlang, C++, Go Language to pre-process the data and later on just process the optimised data further in your main app.
If I use Class Table Inheritance meaning:
one table for Products, storing attributes common to all product types. Then one table per product type, storing attributes specific to that product type.
-Bill Karwin
Which I like the best of Bill Karwin's Suggestions.. I can kind of foresee one drawback, which I will try to explain how to keep from becoming a problem.
What contingency plan should I have in place when an attribute that is only common to 1 type, then becomes common to 2, then 3, etc?
For example: (this is just an example, not my real issue)
If we sell furniture, we might sell chairs, lamps, sofas, TVs, etc. The TV type might be the only type we carry that has a power consumption. So I would put the power_consumption attribute on the tv_type_table. But then we start to carry Home theater systems which also have a power_consumption property. OK its just one other product so I'll add this field to the stereo_type_table as well since that is probably easiest at this point. But over time as we start to carry more and more electronics, we realize that power_consumption is broad enough that it should be in the main_product_table. What should I do now?
Add the field to the main_product_table. Write a script to loop through the electronics and put the correct value from each type_table to the main_product_table. Then drop that column from each type_table.
Now If I was always using the same GetProductData class to interact with the database to pull the product info; then if any changes in code now need refactoring, they should be to that Class only.
You can have a Product table and a separate ProductAdditionInfo table with 3 columns: product ID, additional info name, additional info value. If color is used by many but not all kinds of Products you could have it be a nullable column in the Product table, or just put it in ProductAdditionalInfo.
This approach is not a traditional technique for a relational database, but I have seen it used a lot in practice. It can be flexible and have good performance.
Steve Yegge calls this the Properties pattern and wrote a long post about using it.
I started to develop a little Content Management System for two languages (de, en) that starts to grow bigger.
In that context, I have Posts and Pages (a bit like WordPress or actually just like WordPress). But I am also planning to add further content types like Reviews, Courses, Tutorials (Recipes) and maybe even E-Books that are purchasable.
All these objects would have in common that they are contentable, so they will be shown on the front end with their dedicated urls, like /posts/{slug} for posts, /{slug} for pages, /reviews/{slug} for reviews and so on.
On the backend, this means an auto save and revision system is offered for these content types.
So, this would leave us will the following options:
Single Table Inheritance (we would need to live with many null values) - not supported officially by Laravel, but there is a package.
Multi Table Inheritance (which is not supported in Laravel either)
Polymorphism which is supported
CMS solution (like craft CMS), which basically breaks up the logic in elements, entries, fields and so on, alternative approach would be drupal's node approach - out of scope I believe (I dont have 6-9 months time to write a CMS from the scratch)
Have on Table per Model and try to use as much logic as possible between the models by using Traits (current status, I don't like it that much...).
After some googling, searching here on stackoverflow and looking at other projects, I am thinking of the following structure:
contents table:
id
site_id
title
... (some more columns that are shared among all models)
contentable_type
contentable_id
posts
id
pages
id
home
courses
id
name
featured
difficulty
free
So, these tables would be linked to the contents table through a belongsTo relationship, and the content model would define the morphable relationship.
class Content extends Eloquent {
public function contentable(){
return $this->morphTo();
}
}
class Post extends Eloquent (or Content) {
public function content(){
return $this->morphOne('Content', 'contentable');
}
}
Working with models would mean you would always have to load the content relationships.
Sorting & Ordering must be performed by joins.
And when creating, of course, we have to first create the content type model and then save and attribute it to a content model.
I never implemented a system with that kind of (sub) logic before, and it feels a bit odd to me to have a posts table with just an id (same would be true for other content types e.g. "abouts" in case they don't have extra columns), but I think it would be the "Laravel way" to solve this issue, right?
I believe STI wouldn't work for this case, and it is also a bit against Laravel's Eloquent pattern.
Has somebody already experiences with this approach? Am I on the right track here?
Note: I got inspired by the discussion here: How can I implement single table inheritance using Laravel's Eloquent?
In case anyone finds this question. I finally decided against this approach, basically because I believe it is not worth the efforts (and also most of the packages won’t work out of the box).
It is a much better approach to use Traits et cetera to reuse as much logic as possible and follow the Eloquent ORM approach.
I'm pretty new to Laravel, so I'm struggling with the logic for what is essentially a CMS with multiple content types.
Say I have 3 content types; Food, Books and Cars. Every item in all content types has a name, URL and a couple of other fields.
I can create, update and delete any of these resources with most likely the same code replicated 3 times. The only difference would be with a create or update as the field names would differ between them.
Should I just duplicate these fields/functions for each controller, or create some common ground in one place?
The crossover of fields/functions initially will not be huge, however, it seems inefficient let's say if I had 10 content types and I want to add one field to all of them I have to update code in a large number of places.
If I had a central "Node" that contained the id's and common fields for ALL items in every content type, then have this linked to individual tables for the custom fields, I'm in a much better position when I want to add, update or delete common fields.
I've currently got 3 controllers and have only worked on one so far so I have an index(), show() and edit() function in the controller.
As a test, I created a Node model with php artisan make:model Node -mcr and simply extended the existing Controllers so they were extending NodeController. Which just threw up an error like this;
Declaration of App\Http\Controllers\FoodController::show(App\Food$food) should be compatible with App\Http\Controllers\NodeController::show(App\Node $node)
This is likely not the way to go about it anyway, but I simply do not know the recommended practice for this.
Most appropriate and standard best practice for your problem is,
have a single database table, let's say table name as node, which will contain all the common fields, and have another table as categories and relate it with node table (1-m) to categorize type of node such as car,book,food etc., and make one more table, let's say node_meta which will store all additional attributes depending on the type of node,
(you may have a look on the wordpress CMS database ER Diagram which has similar db design.)
Polymorphic relation is not a good idea for this as stated by another user above, it has some limitation when it comes to querying underlying data, for example you cannot apply whereHas query and still there is no official solution to this problem.
i am struggling with setting up my database and eloquent relationships in a certain scenario.
This certain part of my application will be handling online orders.
basically i want an order to consist of multiple configured items.
i want configured items to consist of a base item (ex. a cheesburger) and also of toppings.
i have gone through several scenarios, but I am trying to make this as simple as possible. here is the quick and dirty story of what I have now.
I want a configured item to consist of three things. 1. the order id of the order it is associated with. 2. the menu item that it relates to (ex. cheeseburger, hotdog ) 3. and the toppings.
I am considering two tables that are full of relatively static information about the menu items and the toppings to be referenced from the configured item table.
I had originally considered creating a new menu item on every configured item, but I like the idea of just being able to look up items/toppings and applying them to a configured item. Im sorry if this is unclear. I am three days into this and my brain is absolutely in pain by now.
here are the relationships i am considering.
configured_item: belongsTo Order; hasOne menu_Item;
Menu_item: belongsToMany configured_item; hasMany toppings;
Toppings: belongsToMany configured_item;
I guess in a way my configured item table is a pivot table of sorts, but then it will need to be referenced by an order as well.
i know questions have been asked about three way relationships, but I cant find any info on tables that are relatively static like i am trying to use.
I finally caved and used two pivot tables. it all works, but i cannot help but feel there is a better way to handle this. It seems a lot of people have similar issues and there is no clear cut solution.
i dont quite understand this pattern.
from what i have read, it looks like one model = one table (if you are using database to store data).
so if i've got a table called tags, i should have a tags model. and with a threads table i create a threads model.
then i got a tags controller and a threads controller right?
so what if i've got a tags_threads_map table for a many-to-many relationship.
should i have a tags_threads_map model eg. in which i get all threads containing a tag? should i have a tags_threads_map controller too?
would be great if someone could explain or give me a good breif tutorial on this.
the most tutorials just give a simple 1:1:1 example.
To fully understand MVC or any software design pattern, you really need to have a go at implementing it and see what your results are.
That said, MVC does not prescribe that one model = one table. In fact, a model could be backed by a number of tables, or even data originating in something other than a relational database (e.g. a web service, flat files, a key-value store or a graph database for example).
I would suggest that creating models and views that represent meaningful aggregates of related tables is probably a good approach. For example, to use the timeworn example of an Order and OrderLine table, an Order model might encapsulate operations on data that will ultiamtely end up in either the Order table or the OrderLine table.
Adhering to strict 1-to-1 mapping of table to Model, View and Controller will only result in an explosion of classes, some of which may not be doing much individually. Better to build Models and Controllers that are more focused on achieving some task identified by the business requirements, rather than just being a projection of the data model.
So the idea is less "one model = one table" and more that you don't want code that manages the data to be interleaved with code that manages the operations on data or code that handles user interaction. If you have some sort of persistance layer that handles mapping of objects to a database, that's enough to have a rudimentary model. If you have some separate code on top of that that does something algorithmic with that data, that's a controller. If you have a way of rendering the data for user consumption, that's a view.
Best example that comes to mind is a spreadsheet: the data in the spreadsheet is your model. If you have expressions in your sheet that manipulate the data, that can be seen as a controller. If you see the data in tabular form, or in a graph, those are two views. The views don't muck with the data or how it's calculated - they format it for your eyes. The controller doesn't format the data for your eyes - it creates / changes / calculates the data. The important part is separating out the concepts so you can, for example, write algorithms that don't care how data is stored, and views that don't care how data is calculated.
In my opinion, it's better to think of a model as a model of an object type, not of one specific table.
Generally, your MVC framework would handle your many-to-many relationships by definitions from within the models for tags and threads.
And you definitely don't need a controller for every model; controllers are generally more closely related to views (though there are usually multiple views to one controller).
This seems like it's too general of a question to be able to be answered to your satisfaction here.
A model can be more dynamic than that. For example, if you have a blog, and a blog has tags, your model might be called Blog and it can have a collection of Tags.
A model can be anything that stores the data. In the web app I'm working on there are several tables for contacts, their addresses which groups they belong to and so on. It's probably best to split them up by types, I should have made a group model but you don't strictly have to do this.
MVC relates to 3d games quite well, MVC is not only for information systems. Consider this:
In 3d graphics the model is map, the polygons and their positions and colours. The view is the camera from which the scene is viewed, a position, zoom and direction. The controller interprets the keyboard and mouse and manipulates both the camera(view) and scene(model).
If this were a shooter game then if:
A user pushes the forward button, the controller moves the camera forward.
A user pushes the throw grenade button, controller adds a grenade to the scene.
The view is presentation, the model is storage/structure and the controller is an in between which tells the view what to display and how to display it based on the state of the system.
Generally you put all the formatting in a view, data in models and logic into controllers.