ludofleury
12/18/2010 - 5:19 PM

lib/model/doctrine/FileRelation.class.php Relational model between object model and file model Implement LooseCoupling doctrine behavior c

lib/model/doctrine/FileRelation.class.php Relational model between object model and file model Implement LooseCoupling doctrine behavior concept from Christian Schaefer.

<?php
/**
 * Listener which cascade CRUD action on the model to the File's relations.
 */

class FileableListener extends Doctrine_Record_Listener
{
  protected $_options = array();

  public function __construct($options = null)
  {
    $this->_options = $options;
  }

  public function preDqlSelect(Doctrine_Event $event)
  {
    $query = $event->getQuery();
    $components = $this->_getDqlCallbackComponents($query);
    foreach ($components as $alias => $component)
    {
      if (isset($component['relation']))
      {
        $query->addWhere($alias.'.object_type = ?', get_class($event->getInvoker()));
      }
    }
  }

  /**
   * Cascade delete to FileRelation
   * @param Doctrine_Event $event
   */
  public function postDelete(Doctrine_Event $event)
  {
      $record = $event->getInvoker();
      
      FileRelationTable::getInstance()
        ->createQuery('f')
        ->delete()
        ->where('f.object_type = ?', get_class($record))
        ->andWhere('f.object_id = ?', $record->getPrimaryKey())
        ->execute();
  }

  /**
   * Cascade update to FileRelation
   * @param Doctrine_Event $event
   */
  public function preUpdate(Doctrine_Event $event)
  {
      $record = $event->getInvoker();
      $modified = $record->getModified();
      
      if(isset($modified['id']))
      {
          FileRelationTable::getInstance()
            ->createQuery('f')
            ->update()
            ->set('object_id',$record->getId())
            ->where('object_type = ?', get_class($record))
            ->andWhere('object_id = ?', $record->getPrimaryKey())
            ->execute();
      }
  }

  protected function _getDqlCallbackComponents($query)
  {
    $params = $query->getParams();
    $componentsBefore = array();
    if ($query->isSubquery())
    {
      $componentsBefore = $query->getQueryComponents();
    }

    $copy = $query->copy();
    $copy->getSqlQuery($params);
    $componentsAfter = $copy->getQueryComponents();

    if ($componentsBefore !== $componentsAfter)
    {
      return array_diff($componentsAfter, $componentsBefore);
    }
    else
    {
      return $componentsAfter;
    }
  }
}
<?php
/**
 * Template applied to models which are linked to File. 
 */
class Fileable extends Doctrine_Template
{
    protected $_options = array();
    protected $_files = array();

    public function __construct($options = null)
    {
        $this->_options = $options;
    }

    public function setTableDefinition()
    {
        $this->addListener(new FileableListener($this->_options));
        $this->hasMany('FileRelation as Files', array('local' => 'id', 'foreign' => 'object_id'));
    }

    # WIP : example of shortcut method
    public function getImages()
    {
        return ImageTable::getInstance()->createQuery('i INDEXBY fr.position')
                                 ->leftJoin('i.FileRelation fr ON fr.file_id = i.id')
                                 ->where('fr.file_type = ?','image')
                                 ->andWhere('fr.object_type = ?',get_class($this))
                                 ->andWhere('fr.object_id = ?',$this->getPrimaryKey())
                                 ->execute();
    }
}
<?php

/**
 * FileRelation
 *
 * 
 * @package    shop
 * @subpackage model
 * @author     Christian Schaefer <caefer@ical.ly>
 * @author     Ludovic Fleury <ludovic.fleury@w3brothers.com>
 * @version    SVN: $Id: Builder.php 7490 2010-03-29 19:53:27Z jwage $
 */
class FileRelation extends BaseFileRelation
{
    protected $_objectCache = array();
    protected $_fileCache = array();

    public function getFile()
    {
        if(false !== ($file = $this->getCachedFile($this->file_type, $this->file_id)))
        {
            return $file;
        }
        elseif($this->file_type && $this->file_id)
        {
            $file = Doctrine_Core::getTable($this->file_type)->find($this->file_id);
            $this->setCachedFile($this->file_type, $this->file_id, $file);
            return $file;
        }
        else
        {
            return null;
        }
    }

    public function setFile(File $file)
    {
        $this->file_type = $this->_findObjectType($file);
        $this->file_id   = $this->_findObjectPrimaryKey($file);

        $this->setCachedFile($this->file_type, $this->file_id, $file);
    }

    public function getCachedFile($type, $id)
    {
        if(array_key_exists($type, $this->_fileCache) && array_key_exists($id, $this->_fileCache[$type]))
        {
            return $this->_fileCache[$type][$id];
        }
        return false;
    }

    public function setCachedFile($type, $id, $file)
    {
        if(!array_key_exists($type, $this->_fileCache))
        {
            $this->_fileCache[$type] = array();
        }
        $this->_fileCache[$type][$id] = $file;
    }

    public function getObject()
    {
        if(false !== ($object = $this->getCachedObject($this->object_type, $this->object_id)))
        {
            return $object;
        }
        else if($this->object_type && $this->object_id)
        {
            $object = Doctrine_Core::getTable($this->object_type)->find($this->object_id);
            $this->setCachedObject($this->object_type, $this->object_id, $object);
            return $object;
        }
        else
        {
            return null;
        }
    }

    public function setObject($object)
    {
        $this->object_type = $this->_findObjectType($object);
        $this->object_id   = $this->_findObjectPrimaryKey($object);

        $this->setCachedObject($this->object_type, $this->object_id, $object);
    }

    public function getCachedObject($type, $id)
    {
        if(array_key_exists($type, $this->_objectCache) && array_key_exists($id, $this->_objectCache[$type]))
        {
            return $this->_objectCache[$type][$id];
        }
        return false;
    }

    public function setCachedObject($type, $id, $object)
    {
        if(!array_key_exists($type, $this->_objectCache))
        {
            $this->_objectCache[$type] = array();
        }
        $this->_objectCache[$type][$id] = $object;
    }

    protected function _findObjectType($object)
    {
        return get_class($object);
    }

    protected function _findObjectPrimaryKey($object)
    {
        $identifier = $object->identifier();

        if(1 != count($identifier))
        {
            throw new Doctrine_Record_Exception("Couldn't set identifier. LooseCoupling does not support multi column primary keys!.");
        }

        return current($identifier);
    }
}