Elements with common and separate properties in a database - php

I have a database with a table post, a user can submit many types of posts, and all these types share properties, and have properties of their own. For e.x: both video and standard posts have a description, but only video posts have a video link/file property.
What I did is creating a table post containing the common properties, like the creationDate and description.
And I created other tables, containing the other properties, and as the number of post types grows, I think I will have to add more tables.
Of course, the problem with this design is that when I want to retrieve one post, I have to retrieve its data from the posts table, then use its ID and Type to retrieve data from the type table (ex : videos table). And when I want to retrieve data of different types in one page I'll have to handle many tables.
Which seems not to be practical since I'm working with PHP/MySQL in an Apache server.
Is there any other better idea I can implement to get the same result?

Your design follows the technique described in class-table-inheritance. There is an outline of the technique in the info tab.
You might want to explore using shared-primary-key as a way to speed things up, and as a way to use post-id as a FK without having to have a different FK type for each post type. It also speeds up joins.
The down side is that you will have to add a new table whenever you discover a new post type. But then, if you were building an object model you would have to add a new subclass at the same discovery.

Related

Laravel CMS logic for shared functions/fields

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.

Multiple file upload Yii 2

I'm using mysql DB, I've got table "posts" with columns id, title, text, author_id, image at the moment.
I need to provide a possibility to upload several images to one post in my blog. What's the best way of organizing my DB structure in this case and how it's usually done in Yii 2?
At the moment I just have functionality for saving 1 image and keeping it's path in table field.
Should I keep an array in DB or create another relations table?
When you're working with a conventional RDBMS like MySQL:
It seems you're going from a one-to-one, to a zero- or one-to-many relation, in which case i'd recommend creating another table for your files (for example: image*), containing a foreign key image.post_id to posts.id. Added benefit is that you will be able to more neatly store some metadata about the image, instead of creating a load of extra (but perhaps unneeded columns) in the posts table.
The cleanest solution (imho) is usually to stay close to the data structure of your DMBS, instead of placing arbitrary data structures inside a text field, no matter what framework or language you use.
This is different when working with no-sql database like for example MongoDB, where depending on the use-case you may want to use an array property images on your posts document containing image objects.
*yii naming convention for tables is singular instead of plural

Is this an appropriate use of a MySQL enumeration data type?

I have recently started doing freelance PHP + MySQL development in my free time, to supplement my income from a full-time job where I write C#/SQL Server code. One of the big database-related differences I've noticed is that MySQL has an enum datatype, whereas SQL Server does not.
When I noticed the enum datatype, I immediately decided to flatten my data model in favor of having a big table that makes use of enumerations rather than many smaller tables for discrete entities and one big "bridge" sort of table.
The website I'm currently working on is for a record label. I only have one table to store the releases for the label, the "releases" table. I have used enumerations everywhere I would normally use a foreign key to a separate table--Artist name, Label name, and several others. The user has the ability to edit these enumeration columns through the backend. The major advantage I see for enumerations over using a text field for this is that artist names will be reused, which should improve data integrity. I also see an advantage in having fewer tables in the database.
Incidentally, I do still have one additional table and a bridge table--there is a "Tags" feature to add tags to a particular release, and since this is a many-to-many relationship, I feel a discrete tag table and a bridge table to join tags to releases is appropriate
Having never encountered an ENUM datatype in a database before, I wonder if I am making wise use of this feature, or if there are problems I haven't foreseen that might come back to bite me as a result of this data architecture. Experienced MySQL'ers, what do you think?
In short, this is not a good design. Foreign keys have a purpose.
From the documentation for the ENUM type:
An enumeration can have a maximum of 65,535 elements.
Your design will not allow you to store more than 65k distinct artist names.
Have you considered what happens when you add a new artist name? I assume you are running an ALTER TABLE to add new enum types? According to a similar SO question this is a very expensive operation. Contrast this with the cost of simply adding another row to the artist table.
What happens if you have more than one table that needs to refer to an artist/artist's name? How do you re-use enum values across tables?
There are many other problems with this approach as well. I think that simplifying your database design like this does you a real disservice (foreign keys or having multiple tables are not a bad thing!).
I'm going to be honest - I stopped when I read...
I have used enumerations everywhere I
would normally use a foreign key to a
separate table--Artist name, Label
name, and several others.
If I understand correctly, that means there is an enumeration of all artists. But that enumeration of artists is definitely going to be a point of variation: there will be more artists. I sincerely doubt the record label never plans on increasing or changing the list of artists ;)
As such, in my opinion, that is an incorrect use of an enumeration.
I also don't think it's appropriate to perform an ALTER TABLE for what is inevitably a rather mundane use case. (Create/Read/Update/Destroy artist) I have no numbers to back up that opinion.
You have to look at it as a question of what information is an entity or an attribute of an entity: for a record label, artists are entities, but media types may not be. Artists have lots of information associated with them (name, genre, awards, web site url, seniority...) which suggests they are an entity, not an attribute of another entity such as Release. Also, Artists are Created/Read/Updated and Destroyed as part of regular everyday use of he system, further suggesting they are entities.
Entities tend to get their own table. Now, when you look at the Media Type of these Releases, you have to ask yourself whether Media Type has any other information... if it's anything more than Name you have a new Entity. For example, if your system has to keep track of whether a media type is obsolete, now there are 2 attributes for Media Type (name, is obsolete) and it should be a separate entity. If the Medai Types only have a Name within the scope of what you're building, then it's an attribute of another entity and should only be a column, not a table. At that point I would consider using an enumeration.
I dont think you can use enumerations in fields like artists. Its like you are restricting your application from growing. It will be really hard to maintain the column. Using ENUM is not a problem its own. But will be an issue in the following situations
When you need to add additional options to the enum colum. If you are table contains lots of data, it will take good time to rebuild your table when adding an additional option
When you need to port the the database to another technology (enum is not available in all database products, for eg MSSQL)

Sitewide multi object search - database design / code strategy?

I am lost on how to best approach the site search component. I have a user content site similar to yelp. People can search for local places, local events, local photos, members, etc. So if i enter "Tom" in the search box I expect the search to return results from all user objects that match with Tom. Now the word Tom can be anywhere, like a restaurant name or in the description of the restaurant or in the review, or in someone's comment, etc.
So if i design this purely using normalized sql I will need to join about 15 object tables to scan all the different user objects + scan multiple colunms in each table to search all the fields/colunms. Now I dont know if this is how it is done normally or is there a better way? I have seen stuff like Solr/Apache/Elasticsearch but I am not sure how these fit in to myusecase and even if i use these I assume i still need to scan all the 15 tables + 30-40 colunms correct? My platform is php/mysql. Also any coding / component architecture / DB design practice to follow for this? A friend said i should combine all objects into 1 table but that wont work as you cant combine photos, videos, comments, pages, profiles, etc into 1 table so I am lost on how to implement this.
Probably your friend meant combining all the searchable fields into one table.
The basic idea would be to create a table that acts as the index. One column is indexable and stores words, whereas the other column contains a list of references to objects that contain that word in one of those fields (for example, an object may be a picture, and its searchable fields might be title and comments).
The list of references can be stored in many ways, so you could for example have string of variable length, say a BLOB, and in it store a JSON-encoded array of the ids & types of objects, so that you could easily find them afterwards by doing a search for that id in the table corresponding to the type of object).
Of course, on any addition / removal / modification of indexable data, you should update your index accordingly (but you can use lazy update techniques that eventually update the index in the background - that is because most people expect indexes to be accurate within maybe a few minutes to the current state of the data. One implementation of such an index is Apache Cassandra, but I wouldn't use it for small-scale projects, where you don't need distributed databases and such).

User configurable forms with php and mysql

An online application we are building (php & mysql) requires users to be able to create their own forms for data capture and record this data in a database, respecting the existing ORM's.
If the forms where "hard coded" then we would simply set the db tables up to store the normalised data ourselves however as our users define the form fields contained in the forms, we're not sure what is the best way to proceed to implement this functionality.
Do we need to think about some kind of meta data or data abstraction layer for our DB? Google hasn't been too much help as we're unsure about how we need to go about this.
Any pointers in the right direction would be gratefully appreciated!
Many content management systems address this problem in different ways.
For example, in Drupal, users can create their own custom content (with custom forms) through the CCK module. The module defines different types of fields that the user can create, then generates tables with specific data types to store the data.
Some tips:
Define your field types - Think about giving the users a choice of different field types (e.g., select box, string, radio).
Create tables for user defined fields - Each field type will have a specific SQL data type. Define a table using these data types. For example, a select box might be mapped to an enum and a input text element might be mapped to a varchar column.
Add data to the new tables - use the new tables to store the data in a somewhat normalized way.
Obviously there are many different approaches, but these are just a few suggestions.
I think I've found a solution to my problem, so for all those people who come along a similar problem have a look at the following artcles -
http://www.adaniels.nl/articles/an-alternative-way-of-eav-modeling/
http://weblogs.sqlteam.com/davidm/articles/12117.aspx
Hope this helps.

Categories