Notes
Currently, the above ‘HasMany’ example will incur N+1 queries. That is, one query will be executed for each set of comments requested for each post. So if 20 posts are returned and you print the comments for all posts, 20+1 queries will be executed.
Solving the N+1 query problem is one of the primary goals of the phpDataMapper project, and will be addressed before the first official release of phpDataMapper in the very near future so that in the above situation, the maximum number of queries executed will be 2. One for all the posts, and one for all the comments related to all the posts in the result set.
Implemented Relationship Types
HasOne
One-to-one table relationships. Row ‘has one’ related row in another table. Each post ‘has one’ author.
HasMany
One-to-Many table relationships. Row ‘has many’ related rows in another table. Each post ‘has many’ comments.
Define The Relationship
Relationships must be defined in the individual models that require them. In the example below, we define a relationship in the PostsModel so that each post row object ‘HasMany’ comments. The mapper used to load the comments is ‘CommentsModel’, and the post ‘id’ field will match up with the comment ‘post_id’ field.
<?php // Post class PostsMapper extends phpDataMapper_Base { // Specify the data source protected $_datasource = "posts"; // Define your fields as public properties public $id = array('type' => 'int', 'primary' => true, 'serial' => true); public $title = array('type' => 'string', 'required' => true); public $body = array('type' => 'text', 'required' => true); public $status = array('type' => 'string', 'default' => 'draft'); public $date_created = array('type' => 'datetime'); // Comments relationship public $comments = array( 'type' => 'relation', 'relation' => 'HasMany', 'mapper' => 'CommentsMapper', 'where' => array('post_id' => 'entity.id') // Means CommentsMapper.post_id = currently loaded Post entity id ); } // Post Comments class CommentsMapper extends phpDataMapper_Base { // Specify the data source protected $_datasource = "post_comments"; // Define your fields as public properties public $id = array('type' => 'int', 'primary' => true, 'serial' => true); public $post_id = array('type' => 'int', 'key' => true, 'required' => true); public $body = array('type' => 'text', 'required' => true); public $date_created = array('type' => 'datetime'); }
Usage Example
We can now use the relationship like so:
<?php // DataMapper base model require '../phpDataMapper/Base.php'; // Setup database connection require '../phpDataMapper/Adapter/Mysql.php'; try { $adapter = new phpDataMapper_Adapter_Mysql('localhost', 'blog', 'root', ''); } catch(Exception $e) { echo $e->getMessage(); exit(); } // Instantiate the Mapper $postMapper = new PostMapper($adapter); // Find all posts with a status of 'published' $posts = $postMapper->all(array('status' => 'published')); // Loop and print posts and comments foreach($posts as $post) { echo "<h2>" . $post->title . "</h2>"; echo "<p>" . $post->body . "</p>"; echo "<hr />"; // Comments foreach($post->comments as $comment) { echo "<p>" . $comment->body . "</p>"; } }