The Hulme Ramblings of a web developer

29Oct/110

Model Relationships Part 1

Here is my first tutorial for what I did to get some model relationships working in Zend Framework 1.11.11

Overview

The basic idea I am going to implement here is that I have Albums and Images. An album can have many images, and an image belongs to one album. So before we start, we should make sure that we have set up our tables and DbTable models, as well a controller and a view where we can test our relationships.

How To

Lets start with making sure we have a working controller and view working, by printing out all the albums and images.

For this tutorial I am testing my output in a album view and controller. Here is my index action in my AlbumsController.php:

public function indexAction()    {
       $albums = new Application_Model_DbTable_Albums();
      $this->view->albums = $albums->fetchAll();
      $images = new Application_Model_DbTable_Image(); 
      $this->view->images = $images->fetchAll();    
}

So as we can see, all I do is create a new instance of the Albums DbTable model and run fetchAll and assign it to the view. Same with the Image Image DbTable model. Then in my view I loop through the results and echo them out:

<?php foreach( $this->albums as $album ): ?>
<b>Album:</b> <?php echo $album->title; ?><br />
<?php endforeach; ?>

<b>Images&ltl/b><br />
<?php foreach( $this->images as $image ): ?>
<?php echo $image->title; ?>,
<?php endforeach; ?>

With this in place, we should just be getting a basic output listing the albums and images that we have in our database. Great!

The next thing we will do is edit the Album DbTable model telling it that it has a table that depends on it, and let it know what it's row class is. So at the top of the model, below the "$_name=" line add:

protected $_rowClass = 'Application_Model_Row_Album';
protected $_dependentTables = array('Application_Model_DbTable_Image');

This tells the model that it's row class is the model "Application_Model_Row_Album" (which we will create in a bit) and that the table that it has many to one relationship with is in the class "Application_Model_DbTable_Image" (Because our album has many images).

Next we will edit the image DbTable model to tell it what it's row class is, and what table it has a relationship to. Similarly to the above, underneath the "$_name=" line add:

protected $_rowClass = 'Application_Model_Row_Image';

protected $_referenceMap = array(
'Album' => array(
'columns' => 'album_id', // the column in the 'albums' table which is used for the join
'refTableClass' => 'Application_Model_DbTable_Albums', // the Albums table class
'refColumns' => 'id' // the primary key of the albums table
)
);

Next we need to move on to creating our Row Model classes. If the folder doesn't already exist, create one at "application/models/Row". Inside there create two files "Album.php" and "Image.php".

In Album.php add the following:

class Application_Model_Row_Album extends Zend_Db_Table_Row_Abstract
{
private $images = null;

/**
* @return Model_Row_Image
*/
public function getImages()
{
if (!$this->images) {
$this->images = $this->findDependentRowset('Application_Model_DbTable_Image');
}

return $this->images;
}
}

As we can see, this contains the function to get the images related to this model.

In the Image.php add:

class Application_Model_Row_Image extends Zend_Db_Table_Row_Abstract
{
private $album = null;

/**
* @return Model_Row_Album
*/
public function getAlbum()
{
if (!$this->album) {
$this->album = $this->findParentRow('Application_Model_DbTable_Albums');
}

return $this->album;
}
}

Finally if we update our view file to the below, we should see our relationships getting on fine:

<?php foreach( $this->albums as $album ): ?>
<b>Album:</b> <?php echo $album->title; ?><br />

<b>Images</b><br />
<?php foreach( $album->getImages() as $image ): ?>
<?php echo $image->title; ?>,
<?php endforeach; ?>

<?php endforeach; ?>

<b>Images</b><br />
<?php foreach( $this->images as $image ): ?>
<?php $al = $image->getAlbum(); echo $al->title; ?>,
<?php endforeach; ?>