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?
Related
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.
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'];
Is there a best practice in getting data from multiple database tables using Zend? I would like to know rather than end up wanting to refactor the code I write in the near future. I was reading the Zend documentation and it said that:
"You can not specify columns from a
JOINed tabled to be returned in a
row/rowset. Doing so will trigger a
PHP error. This was done to ensure
the integrity of the Zend_Db_Table is
retained. i.e. A Zend_Db_Table_Row
should only reference columns derived
from its parent table."
I assume I therefore need to use multiple models -- is that correct? If, for example, I want to get out all orders for a particular user id where the date is in between two dates what would I do?
I know that it would be possible to access the two different models from a controller and then combine their respective data in the action but I would not feel happy doing this since I have been reading survivethedeepend.com and it tells me that I shouldn't do this...
Where, why, and how? :)
Thanks!
If you're reading ZFSTDE, in chapter 9 (http://www.survivethedeepend.com/zendframeworkbook/en/1.0/implementing.the.domain.model.entries.and.authors) this problem is addressed by using a data mapper.
Also, you can join 2 tables, just be sure to first call on the select object the setIntegrityCheck(false) method. The docs say that a row should reference a parent table, doesn't mean it can not :)
Stop thinking about Zend_Db_Table as your "model".
You should write your own, rich, domain-centric model classes to sit between your controllers (and views), and your persistence logic (anything that uses Zend_Db/Zend_Db_Table/Zend_Db_Select) to load/store data from the database.
Sure, you can query several db tables at the same time. Take a look at the official ZF docs here http://framework.zend.com/manual/en/zend.db.select.html#zend.db.select.building.join
As for your example with getting all orders of a single user, table relationships are the answer http://framework.zend.com/manual/en/zend.db.table.relationships.html
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.
What is the method to save and update Many to Many relationship in Yii framework?
There is a better implementation as behavior.
http://www.yiiframework.com/forum/index.php?/topic/6905-please-test-my-ar-enhancement-automatically-sync-many-many-table-when-calling-save/
Unless you create a model for the table between the two main tables, your only option is to use DAO (Database Access Object) and specify SQLs with it.
Have a look at how blog demo accomplishes this task.
use MANY_MANY relationship type to setup many to many connection between Models (An associative table is needed to break a many-to-many relationship into one-to-many relationships)
And now you can use all relational functions of Active Records
Yii Framework - The Definitive Guide to Yii: Working with Databases-Relational Active Record
The following extension does what you want...
Yii Framework - Extension: cadvancedbehavior
An important thing to note: On each update, the extension clears all previous records and creates new ones. So I wouldn't use it when the intermediatry table contains extra data other than the foreign keys.
you could set that up in mysql level..by going to relational view under each table in phpmyadmin and provide necessary relational condition..and use MANY_MANY in the model class inside relations..
The question is too common.
Usually data components with MANY to MANY relationships appear sequentially and independently. So you just need to do one insert action after another.
If your relationship needs dependent update you should user SQL triggers on the DataBase level. That'll ensure integrity of data and give a quite good separation in business logic of the application.
CREATE TRIGGER some_trigger
AFTER UPDATE ON some_table
...
END IF;
A similar way is to incapsulate relational data in one logical model on PHP level (and e.g. manipulate with 2-3 AR models there) and emulate SQL triggers logic in it.