own ORM: database records in case of JOIN? - php

We are doing our own framework with ORM capability. The database tables are classes now, but how about records? Lets imagine two tables:
Users
ID,USERNAME
Emails
USER_ID,ADDRESS
so, a record object will have getID(), getUSERNAME() methods, etc but if the two tables are JOIN-ed, it cant have two types right? Since there is no multiple inheritance. And what about field collision?

DBIx::Class handles this by having a Class for each table, and joins are represented by a method that gets an object matching the other table..
$myAddress = $myUser->emails->address;

I think every class should represent a record and a whole table should be an array (or some other collection) of objects. Take a look at http://www.doctrine-project.org/ to get some ideas.
And for JOIN, you should have some mechanism for defining aliases. That way, you can deal with field collision.
And for getters and setters, you can use __call, __get and __set. See http://php.net/manual/en/language.oop5.overloading.php for more info.

I'm providing some insight based on the Model/ORM implementation of this PHP UI Framework . Here are some suggestions from me:
Don't decide blindly to map functions into fields. Why not use get('field') and set('field'). There is no downside (apart from lack of IDEs hinting), but you can avoid code generation or catch-all which usually is slower.
When joining you wouldn't necessarily want multiple objects. In my ORM a single Model can work with joined tables. This introduces transparency and when you call $model->set('address') it might be associated with joined table. Im still using sub-instance of a dynamic query for sub-selects but for joins there is no need.
I've see a lot of power of inheritance and ability to re-shape parent models in parent model. Each table can have multiple models depending on your business uses.
Models and ORM should be separated but should play together very closely. I've also managed to make everything play well with generic views and generic controllers, which is a great time-saver.
Hopefully this would help find your own way or to decide on not implementing your own ORM. It's not an easy task.

Related

Should models be created for lookup tables in Zend Framework?

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.

Clean way to implement eager loading in Active Record style ORM?

I'm in the process of writing a very light-weight ActiveRecord implementation in PHP. I have the basics working, but I want to implement eager loading of at least the one-to-one relationships. I've been brainstorming on a clean way to do this.
If I'm eager loading a single one-to-one relationship, I will have to know the columns for both tables and will have to alias the columns following some convention that will allow me to map the results back into the correct objects.
I'm looking for suggestions on how to alias the columns from each table such that mapping them back to their respective objects is as painless as possible.
My initial thoughts are to alias the base table's columns as "base_column_name" and the related tables columns as "user_email" (if "User" is the name of the related object). Is there a better way to do this that I'm overlooking?
A second option I have considered is to get all of the objects off of the base table, and then gather the related objects in one "WHERE IN" using the keys from the base table. But, would this cause performance problems?
CakePHP uses php's flexible associative arrays in its ActiveRecord implementation. So a one to many relationship could be
array('Tablename'=>array('columnname'=>'columnvalue'),
'AssociatedTable'=>array('0',
array('columnname'=>'columnvalue')));
It does put one more layer in everything so you have to do $data['tablename']['columnname'];

Does every single table in Zend have to map to its own Class?

I am not suggesting that all models are tables.
What I am asking is whether every single table must also have its own class defined specifically for it when using Zend? Is there any way of getting away from this awkward boiler-plate coding. We're just starting to look into Zend (hoping to leave procedural PHP land!) and my colleague thinks this could end up being pretty time-consuming.
Is this the reason for people using ORM solutions? Is there any other way around this?
Thanks for your replies.
The Zend Table classes follow the Table Data Gateway pattern, which by definition
... holds all the SQL for accessing a single table or view: selects, inserts, updates, and deletes. Other code calls its methods for all interaction with the database.
In the book, Fowler is not that rigid about that, saying that
for very simple cases, you can have a single TDG that handles all methods for all tables. You can even have one for views or even for interesting queries that aren't kept in the database as views.
However, except for being able to use Views, Zend_Db_Table does not accomodate for this. You can create queries to multiple tables, but those would have to be made through the Zend_Db_Adapter directly or - when using joins - by switching off the integrity check. Otherwise, you have to use the API offered by Zend_Db_Table Relationships
So yes, one instance should correspond to one table or view. You do not need to create classes for that though if you dont plan on extending the classes. Zend_Db_Table_Definitions allow you to configure Zend_Db_Table instances on the fly.
Note that TDG is a DataSource Architectural Pattern and not an Object-Relational pattern. It's purpose is not to help with impedance-mismatch, but with separating database access code from business logic.

PHP Doctrine relationships and inheritance

I've been looking at Doctrine and it seems like a good way to manage models in my OO PHP application.
I would like to create Models that have some optional properties. Rather than having null values in my database, I would like to create separate tables for some (all?) of these properties and give them a foreign key of the node which they relate to. Then when querying the data, perform outer joins on the optional values.
Is there a way to implement something like this in Doctrine?
I've not looked at the documentation thoroughly yet but can one model effectively be defined within multiple tables? The examples I've seen did not appear to mention this.
I hope that makes sense!
Any advice appreciated.
Thanks.
Doctrine supports both inner and left (outer) joins as part of the Doctrine Query Language. You can also write your own custom queries if you need to but still use the models for the results.
Doctrine's join documentation
Use one-to-many relation with properties table.
ModelProperty
~~~~~~~~~~~~~~~~~~~~
modelproperty_id
modelproperty_model_id
modelproperty_property_name
modelproperty_property_value
Is that what you are going to achieve?

What do you think of returning select object instead of statement result?

I would have liked to know if it was a good idea to return a select object from a method like '$selectObj = getSomethingByName($name)' to then pass it to another method like 'getResult($selectObj)' which will do the trick.
The idea is to be able to pass the select object to any usefull function like 'setLimit(10)' or addCriteria('blabla') depending on my model...
But is it a good idea to do this ? it could be 'unsecure' because user will be able to modify the object himself, and i should not want to this..
I used to do simple method before like above but returning the result as a row... but it's sometimes painfull when you have complex statement depending on different tables..
The problem you are facing (complex statements depending on different tables) is an old and widespread problem with ORM frameworks in general. There are lots of things SQL can do, that an ORM doesn't do very well. Inevitably, you have to make up the different in complexity by writing lots of complicated code in your Controller or your View.
Instead, use a Domain Model pattern and encapsulate the complex multi-table database logic into one place, so your Controllers and Views don't have to know about all the sundry details. They just know about the interface of your Domain Model class, and that class has the sole responsibility to know how to fetch the information from the database.
Remember: a Model "HAS-A" table (or multiple tables) -- instead of Model "IS-A" table.

Categories