Skip to content

Instantly share code, notes, and snippets.

@ludofleury
Created December 18, 2010 17:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ludofleury/746671 to your computer and use it in GitHub Desktop.
Save ludofleury/746671 to your computer and use it in GitHub Desktop.
lib/model/doctrine/FileRelation.class.php Relational model between object model and file model Implement LooseCoupling doctrine behavior concept from Christian Schaefer.
<?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
/**
* 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
/**
* 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);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment