I have an application that has only two tables: products and type - where each product can have multiple types as attributes. I decided to normalize the database and created another table where I intend to keep the relations between the products and types.
(Disclaimer: I'm relatively new to object oriented programming). I have a class for products, and a class for types. I have been told that I should have a class for every table that I have in the database. Does this also apply to a table created for normalization purposes? If so - what is the best way of dealing with this - should I somehow call both other classes in this third class, or keep it an independent class, and just manage the exchange of information through actual forms on the webpage, etc?
If your product_types table only holds foreign keys there is no need to map it to its own class. Since this is defining a many to many relationship between the tables you can just provide a method in your product class to get the types.
getTypes() {
// retrieve the types for this product and return
}
Then add the opposite method in the types object to get the products.
getProducts() {
// retrieve the products for this type and return
}
I have been told that I should have a class for every table that I have in the database. Does this also apply to a table created for normalization purposes?
Usually when you're designing a database, the first thing you need to do is create a conceptual data model. This will allow you do define your entities as well as defining relationships between them. Then you create a logical data model to characterize and refine your entities. The last step is the physical data model, which is the closest model there is to a database. Now in this model your entites are now tables, and some of them may or may not relate to your application domain.
For example you could have a travel agency application, where you'd have tables for destinations, flight companies etc... These would map directly to your application because they represent concrete classes. On the other hand you'd also have configurations, sparse data (billing...) or associative tables (like you have here). They don't map to your current application. This concept is called impedance mismatch. See this diagram I found online :
Finally to answer your question : no you don't need to map it to a class, because it has nothing to do in the application domain. Of course you still need to handle it some way (using DAO and SQL basically). You could also use an ORM, like suggested in the comments by #RobW, which can abstract and map directly your database.
Related
I have few lookup tables which are listed below. As of my understanding we need a Model for each database table, but does this also apply to lookup / mapping tables? what is the best practice used while creating models? Below is a sample of my lookup tables...
Transaction Customer Transaction_Lookup
id Id transection_id
date name customer_id
active active
I have created models corresponding to Transaction and Customer tables, do I need to create a corresponding model for Transaction_Lookup as well?
Also I am using Data Mapper pattern which means I will also have to create a Mapper class for each model...
Thanks for your help in advance....
One remark I would make is to not think of models as corresponding one-to-one with tables. That can be very limiting in your OOP design. That said it is true often your models will align to a single table. Look-up tables being an obvious scenario where this is true.
As for needing a concrete model for each lookup table... I would consider writing a generic Model that could be used for all objects corresponding to 'lookup' tables. You could then use that generic class, or write it as an abstract and extend it and create named concrete classes. The amount of unique code needed there could be very limited, leveraging what you already have on the parent class. If you wanted a look up table specific abstract you could abstract the fields key(id), value, friendly name, active? and map the corresponding fields on the tables to those generic properties. Really a number of ways to go about that, hope I explained it well.
I typically write two styles of mappers, ones that are essentially table row gateways like Zend_Db_Table and another that is more custom, where perhaps I use a stored procedure or complex Zend_Db_selects joining off multiple tables. Using the table row gateway style mappers I usually just need to specify a table name, adapter, and mapped object for the mapper to work with. On the custom mappers I usually need to write more of the implementation code from scratch on a case by case.
I like this approach of using a Data Mapper. Can be both convenient and powerful.
Is there any point in having both? I followed a Zend tutorial which told me to create a user model but can't I just model the user in the DB model class?
Thanks
It's part and parcel of the concept of "separation of concerns" http://en.wikipedia.org/wiki/Separation_of_concerns
Your model class takes care of business logic, validation, variable manipulation etc and your db model class should just handle dealing with the database, that way if you need to replace the db model it wont affect the main model as much, and if you replace the main model it wont affect the db model as long as the right parameters are passed into it.
Yes, you can model your user in Application_Model_DbTable_User (DbTable class) and it will work fine as long as all of the data you need is in that one table.
At some point you will likely start working with objects that should be represented in more then one table. This is when you will discover the need for a different way to do things.
A better simple example of where a mapper and domain object might matter:
The mp3 file.
At it simplest a single music file should probably be represented by at least 3 db tables:
album: a table representing the album the song comes from
artist: the artist that recorded the song
track: the information about the track itself
each artist can have multiple albums, each album will have one artist and will have multiple tracks, each track will belong to one album and one artist (different versions will be different tracks).
As you can see the database stucture of even a simple mp3 collection can become very complex very quickly. In most cases even a simple user record will spread across multiple tables depending upon how much and what kind of data is being persisted.
For some help in understanding how and why to implement mappers and models I found these resources very helpful.
Building a Domain Model, covers what a domain model is and how to build one in PHP.
Adding Mappers to a Domain Model, adds mapper function to the same domain model.
Survive the Deepend, A Zend Framework starter that focuses on models and testing.
The first two links are done in plain PHP but are still very helpful.
Some background:
This is for an MVC application built without using any frameworks, but follows the MVC paradigm.
I am using an ORM library called RedBean to talk to the database.
While RedBean represents data using "beans", it supports wrapping them into a model, so custom functions may be provided by the model:
$account = R::dispense('account');
$account->name = "john";
R::store($account);
$account->getFormattedLastUpdatedTime('America/New_York');
Now the question:
Currently, each instance of the model would represent 1 row in the database. If I have a collection of accounts, then I would have an array of "account" models.
In the application, I have a feature for custom profile fields (don't worry, I am not using EAV though :)). One of the tables stores metadata for those fields (name, description etc) for generating the form fields for those custom profile fields. Once again, each row of the metadata represents 1 form field and each row is represented by 1 model.
I now wish to write a method to convert all those rows into a form object which can then be used for rendering and processing the form. But, where should this method live? My initial thought was to place it in the model representing the custom profile field metadata.
Clarification: This function would not be in the account model, but instead in the profile_fields_meta model.
Problem
As each model should represent 1 row, it seems a bit "dirty" to have the model return an object that would be generated from MULTIPLE rows in the database. Am I correct to say this is not the best way to do it? What do you recommend I do instead?
It would be right to have extended ArrayObject (http://php.net/manual/en/class.arrayobject.php) or other container class to run methods for collection.
Try to modify query methods to return data in your custom collection class instead of array if specified.
There's nothing inherent to MVC that says "each model [instance] should represent one row." Often in MVC frameworks the model (as seen by the controller, at least) is entirely ignorant of the data store and doesn't have any concept of or direct mapping to a "row." This isn't necessarily the case with ORMs but a model needn't adhere to an ORM's constraints.
However, though it's hard to tell without knowing more about your schema and implementation, the functionality you're describing doesn't sound appropriate for your Account model. In fact, it sounds to me like you should consider having a "FormField" model such that, in Rails parlance, Account "has many" FormFields.
And for the record, EAV isn't always bad, it's just often misused.
I have few DB tables, witch are build using inheritance from one table witch is an sort of "template" for creation of new tables, and now i have set of businesses logic methods witch work on columns inherit from template, additional columns are used only as params for presentation of models, they're have no meaning for logic.
The goal is to share businesses logic methods along all of that tables, i know, now it can be done by adding another class witch extends CActiveRecord, and extend from it every model, or pack logic as a behavior and append it to models.
But this will require to write at least "dump" class file for every table/model, but those tables "live" in system, and will be deleted/created with system life cycle.
Is there a way to write some sort of "meta-model" witch will take as a param, table name, or maybe some way to create models for tables "on-the-fly" and append to it businesses logic?
I've asked this question on Yii users board, but did not find any response :/
I'm considering this as some sort of code challenge, so any help / clues are welcome :)
[EDIT]
Some samples:
tables for different client devices
hfc.cable_modem
lan.switch_port
lan.voip_gateway
(in near future, there will be more "technologies" added to system, so new tables for client devices, and there is a possibility to drop support for some of them)
every table inherits from template table client_device witch has that fields:
client_id
service_id
core_device_id
(plus some meta columns for timestampable behavior like created, updated, updater etc.)
like You see business logic operates only on ID's, and its identical for every table, rest of columns are used as device params storage/presentation information.
My goal is to have "meta-model" client device, witch will apply business logic to all this tables, and still provide for every of them, access to specific fields, without having to write model class, for every table (witch i'll have to do, every single time, when new technology will be added, or support for given technology will be dropped in a future)
Well, if I understand you right, I have a suggestion based on something similar I am doing:
I have a base "feature" model. But the feature can be a "text" feature, or an "image" feature, etc. But they all share the common "feature id" and a couple other columns as well. So I took sort of an EAV approach. I have a single "feature" table, and then I have a table for each sub-type (text, image, etc). One of the columns in the "feature" table contains the sub-type info. Then in my "afterFind()" method on the base "feature" model I look at the sub-type column. If the sub-type is "text" I attach a "text" type behavior I made. This behavior gets the variables from the sub-type table and sets them up to be accessed just like attributes of the base model.
Something like this:
client_device_table: (base table)
-client_id (primary key)
-service_id
-core_device_id
-device_type (name of the behavior, like CableModemBehavior, or VoipGatewayBehavior)
cable_modem_table
-core_device_id
-modem_info_1
-modem_into_2
voip_gateway_table
-core_device_id
-gateway_info_1
-gateway_into_2
In the ClientDevice CActiveRecord model (the base model):
protected function afterFind() {
parent::afterFind();
// remember $this->device_type holds the relevant behavior i.e. CableModemBehavior
$this->attachBehavior($this->device_type,call_user_func(array($this->device_type, 'model')));
}
And the behavior looks something like this:
class CableModemBehavior extends CActiveRecordBehavior {
public modem_info_1;
public modem_info_2;
public function attach($owner)
{
parent::attach($owner);
$connection = Yii::app()->getDb();
$command=$connection->createCommand("SELECT *
FROM cable_modem_table
WHERE core_device_id=:device_id");
$command->bindParam(':device_id',$this->owner->core_device_id);
$data=$command->queryRow();
$this->modem_info_1 = $data->modem_info_1;
$this->modem_info_2 = $data->modem_info_2;
}
}
This is untested, but what SHOULD happen now is if you get a ClientDevice model with CableModemBehavior as it's sub-type column entry, you will be able to access the modem attributes (modem_info_1) just like the regular ClientDevice attributes (client_id):
ClientDevice->modem_info_1
There is going to be more to it than this, of course. This is just for the "find" case. You will need to do some more work to get the mass attribute assignment thing to work for $_POSTs, or to transfer Relations, or to add afterDelete, validate and afterSave methods to support saving and deleting, etc, but I hope this is a helpful start.
You could also make this a lot nicer by overriding the __get and __set methods of the base model in the behaviors so that if a column from the sub-type table is requested, it goes and get's it from the text table transparently, doing a schema lookup to get the column names, etc. Better than hard coding it like I did in this example. It would be helpful to look at the EavBehavior in the yiiext repository and the AdvancedArBehavior (or similar ones) to get a handle on how to make it slicker. Instead of a behavior for each sub-type, you could have a generic behavior and just pass in the sub-types table name. (ooo I like that actually)
Cheers!
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.