MySQL Status Model -- Best Implementation? - php

So I'm working on a framework-esque system with one of my co-workers. Our current challenge is how to best implement statuses. Oftentimes, a status will carry with it unique data (a color for a table row, or text to be displayed to a user. etc). Currently, we have a statuses table which contains all this data. Contained in that table is a column: "css_class", which, whenever a record has that status, the specified CSS class is attached to the element (in this case a tr). Also, in order to assign another record a specific status, a foreign key is specified in that database table (in this case, a user has a specific status. So in the users table, there is a statuses_id foreign key). This implementation works alright, but there are a few problems. First, what if I need to perform a specific action in PHP if a record is in a specific status? The way we do it now is something like this:
if($user->status==0)
{
//execute some code
}
This really doesn't work well if statuses can change. Change one status, and the associated code either breaks or behaves differently than intended.
The other issue, and the main reason for posting a question is that the table contains the column "css_class". This is very versatile and allows us change the style of a specific status very quickly. But we really dislike the idea of putting code inside a database. Perhaps having CSS classes in a database isn't necessarily a bad thing, but I really don't know what the common practice is. Any ideas?
EDIT:
What I've gathered from the first few answers is that I should keep all my view stuff out of my model stuff in order to maintain an MVC framework. My argument is that if I keep the css_class name out of the database, then I'm checking the status id in the view in order to decide which class to assign it. So if I put the class in the database, I'm putting View information in the Model. If I don't put CSS classes in the database then I'm putting Model information in the View (checking which ID it belongs to). So by not muddying up the Model, I muddy up the view instead.......

The most elegant way I've seen this solved so far (and I've worked with a few MVC implementations now) is to store only the relevant data in the database. E.g. you'd store status="red" in the database, and leave it up to the view to know what to do with a red status, in terms of CSS. The problem is then solved by designing a sufficiently advanced View layer that creates reusable structures -- that way you don't need to always be updating things on a page-by-page basis when the css changes.
Passing this information up to the Model somewhat defeats the point of the content/presentation separation, because now your code needs to know to pull presentation information off the database and forward it along to the View level or, shudder, you'll be pulling that stuff from the database right in your View layer code, which makes maintenance a nightmare, as you've now lost control over the information flow.

If you want to continue your paradigm of storing this in the DB, you could make another table that maps VARCHAR names of the statuses to their corresponding INTEGER IDs.
However, if this was my framework. I would not be storing view information like this in the database. This would be handled by the V of my MVC setup.

From a data modelling point of view:
Have a different table for each "kind" of status; keep user statuses separate from page statuses (for example) - group the like entities together.
Don't put the CSS classes into the database, but use some form of status indicator - this could be an ENUM column, if you know the set of possible statuses up front. Transform this into the appropriate CSS class in the view layer. You don't want to end up in a situation where your CSS can't be changed because some data in the database prevents it.

Related

Is this the right development approach in CakePHP?

I would like to know, if I am following the best practices of development in CakePHP framework.
If you have for a example an Invoices Table, and you want to display the status of the Invoice, let's say you want a green label for the status of the invoice like this:
<span class="green">Paid</span>
What i do is the following. I create a virtualfield on my model named statuslabel, in that virtualfield i call a Helper that displays an element.
so it would be Model->Helper->Element
That way anywhere in my application i can call statuslabel like it was a field from that model and i would get the statuslabel.
My big question is if this is the right way to do it or i am doing it all wrong?
You should avoid violating the MVC principles in your code, in this case specifically containing presentation logic in the model code. This equally applies to CakePHP and other MVC frameworks.
You might still go ahead and create a virtual field called status which can calculate the status of your invoice based on other entity fields. If you have the status stored in the database already as a normal entity field, then you can skip the virtual field.
The view layer is where you want all your presentation code. You can either do it directly in views, or move the logic to the helper. The appropriate function in the helper would take your status field as input and output the appropriate classes into the template based on the status value.
The advantage of keeping presentation code in the view layer (template and helper classes in CakePHP) is that it is easy to replace it later on by updating your templates. CakePHP 3 also gives you the option to create themes via plugins, which is how you can easily change the UI of your application on the fly, but only if you stick to the design principles of MVC.
Generally using virtual fields are not an bad idea. Sometimes the logic behind simple answer is quite complex that it can not be done via SQL or with reasonable amount of SQL.
It is important to remember, that most of the time, using queries directly is much faster without extra PHP processing. So for what comes to your question, if you don't have any PHP logic (besides generating SQL expressions), I would say go with it but...
...There is also point for discussion about database design.
I can't really say about your database schema behind the question, but for me such simple thing than invoice status should definitely be in database directly as and int type field. So what comes to my experience about invoicing systems, database schema could be something like:
invoices
id
invoice_status_id
invoice_statuses
id
title
If you create your model associations and query your database correctly, you end up having invoice status in query results and you can use it just like described.
Btw. most of the time, using reusable elements is good practice. Less code to maintain :D

Concrete5: User Attributes vs Custom DB-Table, what are the Pros and Cons?

I'm developing a page with C5 needing various data to be attached to the user accounts. There are two types of users, having different data. Some of the data is multi dimensional and therefor needs custom DB tables. My question is now if it makes sense to store all data in custom DB tables or to use user attributes for the one dimensional data.
Probably there is no general answer to this, but maybe some pros and cons?
I'm often asking myself where to store data in Concrete5 and would be interested how others decide ...
Yeah. I'd definitely store as user attributes for similar reasons to the one you've already identified (visible, searchable, etc).
concrete5 is extensible, but not super extensible; you can attach data to a user using attributes, but not through some totally custom object / db table that you also expect to, e.g., show up on the user profile page.
Oftentimes in c5 (like any other framework), doing it the Right way (attribute) is more difficult (especially for the first "object", but also for each additional one) than just creating a db table and linking to a user id. But, like in all frameworks, you'll reap benefits down the road that you hadn't even considered. This is in searching, upgradability, and things that might only occur to the guy who takes over development next year.
So, with all that being said, go with attributes. And not just for the one dimensional data. You can configure the attribute controller (and the db schema behind it) to store any data you wish. Look at the Address attribute. This contains multiple fields (though it's still 1D). I think there's an opensource "multi address" attribute out there which stores 1-n addresses as a single attribute. You can do this with an additional linked table, but I've recently gotten lazy with c5 and done no-mysql by dumping json_encode()ed (multi-dimensional) arrays in the "data" field. (In this case, your attribute doesn't even need its own table -- it can use the Default table.) You can then configure the editing interface and also the display value (so, e.g., it just shows a list of each sub-object's Name property). Similarly, you can configure the text that gets indexed for searching purposes.
You asked for pros/cons. Doing this custom will be quicker and more straightforward. Extending an attribute, especially to create something complex, isn't super simple, and there isn't a lot of good documentation. Also, the attribute-editing UI (on the user dashboard page) is a bit kludgy. Yes, you get to "design" whatever you want within the "table cell", but you're still limited to making the admin click on the attribute name, using your editing interface within the cell, and then (ideally) clicking on the little disk icon. (Creating a javascript dialog might solve some issues here.)

Detecting field changes - cakePHP

What I want
I want to see which fields on a table was changed and save that name into the database under the edit column.
What I have
Currently, not much. Just the standard cakePHP baked edit view and controller. I have done it previously, but not with cakePHP. What I did was retrieve the record, and if it's different to what the user entered, save the name of the column that was edited in the edit column corresponding to the row.
My Question
Could someone tell me how I would compare user input with what is on the database?
Behaviors like the "Logable" Behavior already do that and store the information separately.
I advice you to do the same. the "changes" do not necessarily need to be put into the same table. If you feel they do, though, you could make your own "modified" Logable behavior that only creates the "diff" and stores it into a field of your choice on the same record.
PS: You might also want to take a look at the RevisionBehavior.
It also contains some diff algorithm.
Then there is the WhoDidIt behavior which stores the user that last modified the record. In the same table, though. So this combined with the above should do the trick.
Either way:
use callbacks (beforeSave/afterSave) on model itself or (cleaner) as behavior
calculate diff
store the diff in a separate table or as in your case in an extra table field.
Actually writing something up here that does the job is pretty straight-forward.
The voluntary exercise here would be to write it more "generic". Maybe you want to reuse the same functionality again for other models in the future? Copy-and-paste would be pretty bad style then. The goal here would be to create some generic piece of code you can easily reuse. If your initial code works, try to rewrite it into a generic ChangesBehavior that you can attach to as many models you like. You can take the linked examples or take a look at other behaviors out there to get an idea how to do that.
Also you can publish your behavior in github/plugins.cakephp and give the community something back again. Maybe others find it useful, too.

Mysql. 1 table for all properties of all entities or 1 table per each entity

Currently, I am dealing with database structure and I would like to get a piece of advice.
I have 2 objects: banner and ad.
For them I may create banner table and ad table, which will hold all the info about each entity. As main advantage I see that everything related to 1 entity is in this entity table.
On the other hand, I may some table like:
entity_properties.
It will hold value_id entity_id property value. The main advantage is that for entities I need only some basic fields, other fields can be put in this table.
But I am not sure which is the better practice and performance?
Thanks in advance.
For the sake of normalization it is always better to have 1 table per 1 entity. Normalization is an aim or an approach to minimize redundancy and dependency in relational databases . In your case banner and ad are different entities. For now it seems that you can use them in same table. So "redundancy" is not the case. However, what if you want to add some additional fields later?
In addition code complexity and readability is another issue. For instance, when you add different types of object in same table you need to add an internal logic to differentiate them in your code. This means you have complex and probably less readable code.
That depends on the exact use of your system and the attributes/values you're trying to store.
As I see it, I think it would be good to save the important and required information in one table, your 'ad' table, and the rest in the 'ad_entities' table, with an ad_id, entity_name, entity_value, or something similar for your application.
This is a good performance choice since you'll be able to get all the information about the current Ad or all Ads using just one quite simple query, which your objects can easily figure out.

Rollback and Preview in a CMS

I am creating a CMS and am using serialize to handle publish and rollback, which seems to work fine. Basically, The normal site tables are what gets displayed and anything not displayed is serialized in a separate table. The problem however is in making the 'Preview' functions work.
Since the front end is created using normal SQL calls, and all the pre-published/rolled back data is in a separate table it would mean updating every sql statement with some fancy code to pull the version correct to the preview. It will also get especially problematic with things like limits etc and would be a nightmare for the front end.
The only other approach I can see is a separate database/table(s) for the preview copy, but many people may be using the preview function and I am loathe to create a duplicate database for every person using preview as it will very quickly get out of hand.
Is there any way of doing this that will allow preview, and rollback preview, but will not require much from the code that displays the contents of the database and also avoid the problem of mass duplication?
I'm not sure that storing your content data in more than 1 table depending on its state is the way to go.
I would store every version of the content in the same table, having a field which purpose would be to set the state of the content (old version, current version, currently being edited, whatever you want depending on your content editing workflow). That kind of status field plus a date date, would make your content versions way easier to manage.
I used this method for various applications, and was always satisfied with how easy it was to implement rollbacks, previews and even more complex stuff (cvs-like pseudo-branches, ...).
What eWolf means is that when you have a seperate model and view you can have your model supplying different data to the view and then you don't need to copy your database, but instead simply create a standard and a preview model.
The preview model doesn't have to make queries to the database but instead delivers the data that you store in it before passing it to the view.
Consider this example:
//in the controller:
$previewPage->setTitle("foo");
...
//in the view(when previewing):
$previewPage->getTitle(); // returns whatever you stored beforehand
//in the view(regular viewing):
$livePage->getTitle(); // queries the database and returns the result
To learn more about the Model-View-Controller pattern you might want to check out this article.
I hope that helps.
If you seperate Model, View and Controller, this should be no problem: You just take the model from somewhere else in the controller and pass it on to the view.

Categories