UnifiedContainer.class.php

Go to the documentation of this file.
00001 <?php
00002 /***************************************************************************
00003  *   Copyright (C) 2005-2007 by Konstantin V. Arkhipov                     *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU Lesser General Public License as        *
00007  *   published by the Free Software Foundation; either version 3 of the    *
00008  *   License, or (at your option) any later version.                       *
00009  *                                                                         *
00010  ***************************************************************************/
00011 /* $Id: UnifiedContainer.class.php 4687 2007-12-09 18:57:18Z voxus $ */
00012 
00013 /*
00014     UnifiedContainer:
00015 
00016         child's and parent's field names:
00017             abstract public function getChildIdField()
00018             abstract public function getParentIdField()
00019 
00020         all we need from outer world:
00021             public function __construct(
00022                 Identifiable $parent, UnifiedContainer $dao, $lazy = true
00023             )
00024 
00025         if you want to apply ObjectQuery's "filter":
00026             public function setObjectQuery(ObjectQuery $oq)
00027         
00028         or Criteria (ObjectQuery will be ignored):
00029             public function setCriteria(Criteria $criteria)
00030 
00031         first you should fetch whatever you want:
00032             public function fetch()
00033 
00034         then you can get it:
00035             public function getList()
00036         
00037         set you modified list:
00038             public function setList($list)
00039 
00040         finally, sync fetched data and stored one:
00041             public function save()
00042 
00043     OneToManyLinked <- UnifiedContainer:
00044 
00045         indicates whether child can be free (parent_id nullable):
00046             protected function isUnlinkable()
00047 
00048     ManyToManyLinked <- UnifiedContainer:
00049 
00050         helper's table name:
00051             abstract public function getHelperTable()
00052 
00053         id field name at parent's primary table:
00054             protected function getParentTableIdField()
00055 */
00056 
00064     abstract class UnifiedContainer
00065     {
00066         protected $worker   = null;
00067         protected $parent   = null;
00068 
00069         protected $dao      = null;
00070         protected $daoClass = null; // sleep state
00071         
00072         protected $lazy     = true;
00073         protected $fetched  = false;
00074 
00075         protected $list     = array();
00076         protected $clones   = array();
00077         
00078         abstract public function getParentIdField();
00079         abstract public function getChildIdField();
00080         
00081         public function __construct(
00082             Identifiable $parent, GenericDAO $dao, $lazy = true
00083         )
00084         {
00085             Assert::isBoolean($lazy);
00086             
00087             $this->parent   = $parent;
00088             $this->lazy     = $lazy;
00089             $this->dao      = $dao;
00090 
00091             $childClass = $dao->getObjectName();
00092             
00093             Assert::isTrue(
00094                 new $childClass instanceof Identifiable,
00095                 "child object should be at least Identifiable"
00096             );
00097         }
00098         
00099         public function __sleep()
00100         {
00101             $this->daoClass = get_class($this->dao);
00102             return array('worker', 'parent', 'lazy', 'daoClass');
00103         }
00104         
00105         public function __wakeup()
00106         {
00107             $this->dao = Singleton::getInstance($this->daoClass);
00108         }
00109         
00110         public function getParentObject()
00111         {
00112             return $this->parent;
00113         }
00114         
00118         public function getDao()
00119         {
00120             return $this->dao;
00121         }
00122         
00123         public function isLazy()
00124         {
00125             return $this->lazy;
00126         }
00127         
00128         public function isFetched()
00129         {
00130             return $this->fetched;
00131         }
00132         
00137         public function setCriteria(Criteria $criteria)
00138         {
00139             Assert::isTrue(
00140                 $criteria->getDao() === null
00141                 || (
00142                     $criteria->getDao() === $this->dao
00143                 ),
00144                 "criteria's dao doesn't match container's one"
00145             );
00146             
00147             if (!$criteria->getDao())
00148                 $criteria->setDao($this->dao);
00149             
00150             $this->worker->setCriteria($criteria);
00151             
00152             return $this;
00153         }
00154         
00158         public function getCriteria()
00159         {
00160             return $this->worker->getCriteria();
00161         }
00162         
00169         public function setObjectQuery(ObjectQuery $oq)
00170         {
00171             Assert::isTrue(
00172                 $this->dao instanceof StorableDAO,
00173                 'you must extends from StorableDAO to be able to use ObjectQueries'
00174             );
00175             
00176             $this->worker->setObjectQuery($oq);
00177 
00178             return $this;
00179         }
00180         
00185         public function setList($list)
00186         {
00187             Assert::isArray($list);
00188             
00189             $this->list = $list;
00190             
00191             return $this;
00192         }
00193         
00197         public function mergeList(/* array */ $list)
00198         {
00199             Assert::isArray($list);
00200             
00201             return $this->importList($list);
00202         }
00203 
00204         public function getList()
00205         {
00206             if (!$this->list && !$this->isFetched())
00207                 $this->fetch();
00208             
00209             return $this->list;
00210         }
00211         
00212         public function getCount()
00213         {
00214             if (!$this->isFetched() && $this->parent->getId()) {
00215                 $row = $this->dao->getCustom($this->worker->makeCountQuery());
00216                 
00217                 return $row['count'];
00218             }
00219             
00220             return count($this->list);
00221         }
00222         
00227         public function fetch()
00228         {
00229             if (!$this->parent->getId())
00230                 throw new WrongStateException(
00231                     'save parent object first'
00232                 );
00233             
00234             try {
00235                 $this->fetchList();
00236             } catch (ObjectNotFoundException $e) {
00237                 // yummy
00238             }
00239             
00240             $this->fetched = true;
00241             
00242             return $this;
00243         }
00244         
00249         public function save()
00250         {
00251             Assert::isArray(
00252                 $this->list,
00253                 "that's not an array :-/"
00254             );
00255 
00256             if (!$this->fetched)
00257                 throw new WrongStateException(
00258                     'do not want to save non-fetched collection'
00259                 );
00260             
00261             $list   = $this->list;
00262             $clones = $this->clones;
00263             
00264             $ids = $insert = $delete = $update = array();
00265 
00266             if ($this->lazy) {
00267                 foreach ($list as $id) {
00268                     if (!isset($clones[$id]))
00269                         $insert[] = $ids[$id] = $id;
00270                     else
00271                         $ids[$id] = $id;
00272                 }
00273                 
00274                 foreach ($clones as $id) {
00275                     if (!isset($ids[$id]))
00276                         $delete[] = $id;
00277                 }
00278             } else {
00279                 foreach ($list as $object) {
00280                     $id = $object->getId();
00281                     
00282                     if (null === $id) {
00283                         $insert[] = $object;
00284                     } elseif (
00285                         isset($clones[$id])
00286                         && (
00287                             ($object !== $clones[$id])
00288                             || ($object != $clones[$id])
00289                         )
00290                     ) {
00291                         $update[] = $object;
00292                     } elseif (!isset($clones[$id])) {
00293                         $insert[] = $object;
00294                     }
00295                     
00296                     if (null !== $id)
00297                         $ids[$id] = $object;
00298                 }
00299                 
00300                 foreach ($clones as $id => $object) {
00301                     if (!isset($ids[$id]))
00302                         $delete[] = $object;
00303                 }
00304             }
00305 
00306             $db = DBPool::getByDao($this->getDao());
00307             
00308             if (!$db->inTransaction()) {
00309                 $db->queueStart()->begin();
00310 
00311                 try {
00312                     $this->worker->sync($insert, $update, $delete);
00313                     
00314                     $db->commit()->queueFlush();
00315                 } catch (DatabaseException $e) {
00316                     $db->queueDrop()->rollback();
00317                     throw $e;
00318                 }
00319             } else {
00320                 $this->worker->sync($insert, $update, $delete);
00321             }
00322 
00323             $this->clones = array();
00324             $this->syncClones();
00325             $this->dao->uncacheLists();
00326 
00327             return $this;
00328         }
00329 
00333         public function clean()
00334         {
00335             $this->list = $this->clones = array();
00336             
00337             $this->fetched = false;
00338             
00339             return $this;
00340         }
00341         
00342         /* void */ public static function destroy(UnifiedContainer $container)
00343         {
00344             unset($container->worker, $container);
00345         }
00346         
00347         protected function fetchList()
00348         {
00349             $query = $this->worker->makeFetchQuery();
00350             
00351             if ($this->lazy)
00352                 $list = $this->dao->getCustomRowList($query);
00353             else
00354                 $list = $this->dao->getListByQuery($query);
00355             
00356             $this->list = array();
00357             
00358             return $this->importList($list);
00359         }
00360         
00364         private function importList(/* array */ $list)
00365         {
00366             if ($this->lazy) {
00367                 foreach ($list as $id)
00368                     $this->list[$id] = $id;
00369             } else {
00370                 $this->list = array_merge($this->list, $list);
00371             }
00372 
00373             $this->syncClones();
00374             
00375             $this->fetched = true;
00376             
00377             return $this;
00378         }
00379     
00383         private function syncClones()
00384         {
00385             if ($this->lazy) {
00386                 foreach ($this->list as $id) {
00387                     $this->clones[$id] = $id;
00388                 }
00389             } else {
00390                 foreach ($this->list as $object) {
00391                     // don't track unsaved objects
00392                     if ($id = $object->getId())
00393                         $this->clones[$id] = clone $object;
00394                 }
00395             }
00396             
00397             return $this;
00398         }
00399     }
00400 ?>

Generated on Sun Dec 9 21:56:24 2007 for onPHP by  doxygen 1.5.4