Creating nested relationships with an ORM and minimizing queries
First of all, I'm sorry to break this to you , but CodeIgniter's DataMapper is actually a variation of ActiveRecord pattern.
If you care, you compare the real DataMapper pattern with its counterpart - ActiveRecord. In short - difference is in fact that in DM pattern you Domain Object is unaware of type ( and even the existence ) of storage. It is used in manner like $mapper->store( $user );
.
"Favor object composition over class inheritance." © GoF
That said..
If i read the examples right then it should work like this:( i am assuming that relationships between 'entities' are already established )
class Project extends DataMapper{ // --- the rest of your stuff public function get_all_points() { $points = array(); $slides = $this->slide->get()->all; foreach ( $slides as $slide ) { $shapes = $slide->shape->get()->all; foreach ( $shapes as $shape ) { $points = array_merge( $point = $shape->point->get(); } } return $points; }}
Then you can use something like
$project = new Project;$all_points = $project->where( 'id' , 1 )->get_all_points();foreach ( $all_points as $point ){ $point->x = 0; $point->save();}
This should gather all th points that are related to project with ID 1, and set the X value to 0 and store each in the database .. not that any sane person would do it.
I am not using any sort of ORM, that's why i really hope i got this wrong, because this looks to me like an abomination.
I'm not sure how Datamapper does it but I have a custom GenericObject model for Codeigniter that does ORM like this:
class Article extends GenericObject{ public $relationships = array ( "has_many" => array ("comments"), "has_one" => array ("users") );}class Comments extends GenericObject{ public $relationships = array ( "belongs_to" => array ("articles", "users"), "has_one" => array ("users") );}class Users extends GenericObject{ public $relationships = array ( "has_many" => array ("comments", "articles") );}
If I want to get everything from a User then I can just do something like:
$User = new User( $some_user_id );$User->boot_relations("all");foreach ($User->Comments as $Comment){ echo $Comment->title."<br />"; echo $Comment->body."<br />"; echo "written by ".$User->username;}
So it can be fairly elegant (or at least I like to think so).
With most relational data, I typically lazy-load objects at they are needed. I'm not a PHP developer, but here's what I would do in pseudo-code.
class Projects { var slides = null; function getSlides() { if(slides == null) { slides = getSlidesForProject(this.id); } return slides; }}class Slides { var shapes = null; function getShapes() { if(shapes == null) { shapes = getShapesForSlide(this.id); } return slides; }}class Shapes { //... same as Projects.getSlides and Slides.getShapes}
Unfortunately, this causes multiple calls to the database if you needed to get all Points for a Project.
With any MVC solution, I recommend going with a light Controller and a heavy Model to make code reuse and testing easier.