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>";
}
}
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.