CustomizableDaoSynchronizer.class.php

Go to the documentation of this file.
00001 <?php
00002 /***************************************************************************
00003  *   Copyright (C) 2009 by Ivan Y. Khvostishkov                            *
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 
00015     class CustomizableDaoSynchronizer
00016     {
00017         protected $dryRun           = false;
00018         protected $reallyDelete     = false;
00019         
00020         protected $master           = null;
00021         protected $slave            = null;
00022         
00023         private $masterProjection   = null;
00024         private $slaveProjection    = null;
00025         
00026         private $masterKeyProperty  = 'id';
00027         private $slaveKeyProperty   = 'id';
00028         
00029         private $totalUpdated       = 0;
00030         private $totalInserted      = 0;
00031         private $totalDeleted       = 0;
00032         
00036         public static function create()
00037         {
00038             return new self;
00039         }
00040         
00044         public function setDryRun($dryRun)
00045         {
00046             $this->dryRun = $dryRun;
00047             
00048             return $this;
00049         }
00050         
00051         public function isDryRun()
00052         {
00053             return $this->dryRun;
00054         }
00055         
00059         public function setReallyDelete($reallyDelete)
00060         {
00061             $this->reallyDelete = $reallyDelete;
00062             
00063             return $this;
00064         }
00065         
00066         public function isReallyDelete()
00067         {
00068             return $this->reallyDelete;
00069         }
00070         
00074         public function setMaster(GenericDAO $master)
00075         {
00076             $this->master = $master;
00077             
00078             return $this;
00079         }
00080         
00084         public function getMaster()
00085         {
00086             return $this->master;
00087         }
00088         
00092         public function setSlave(GenericDAO $slave)
00093         {
00094             $this->slave = $slave;
00095             
00096             return $this;
00097         }
00098         
00102         public function getSlave()
00103         {
00104             return $this->slave;
00105         }
00106         
00110         public function setMasterKeyProperty($masterKeyProperty)
00111         {
00112             $this->masterKeyProperty = $masterKeyProperty;
00113             
00114             return $this;
00115         }
00116         
00117         public function getMasterKeyProperty()
00118         {
00119             return $this->masterKeyProperty;
00120         }
00121         
00125         public function setSlaveKeyProperty($slaveKeyProperty)
00126         {
00127             $this->slaveKeyProperty = $slaveKeyProperty;
00128             
00129             return $this;
00130         }
00131         
00132         public function getSlaveKeyProperty()
00133         {
00134             return $this->slaveKeyProperty;
00135         }
00136         
00140         public function setMasterProjection(ObjectProjection $masterProjection)
00141         {
00142             $this->masterProjection = $masterProjection;
00143             
00144             return $this;
00145         }
00146         
00150         public function getMasterProjection()
00151         {
00152             return $this->masterProjection;
00153         }
00154         
00158         public function setSlaveProjection(ObjectProjection $slaveProjection)
00159         {
00160             $this->slaveProjection = $slaveProjection;
00161             
00162             return $this;
00163         }
00164         
00168         public function getSlaveProjection()
00169         {
00170             return $this->slaveProjection;
00171         }
00172         
00176         public function run()
00177         {
00178             $masterIterator = new DaoIterator();
00179             $slaveIterator = new DaoIterator();
00180             
00181             $masterIterator->setDao($this->master);
00182             $slaveIterator->setDao($this->slave);
00183             
00184             if ($this->masterKeyProperty)
00185                 $masterIterator->setKeyProperty($this->masterKeyProperty);
00186             
00187             if ($this->slaveKeyProperty)
00188                 $slaveIterator->setKeyProperty($this->slaveKeyProperty);
00189             
00190             if ($this->masterProjection)
00191                 $masterIterator->setProjection($this->masterProjection);
00192             
00193             if ($this->slaveProjection)
00194                 $slaveIterator->setProjection($this->slaveProjection);
00195             
00196             $this->totalDeleted = 0;
00197             $this->totalInserted = 0;
00198             $this->totalUpdated = 0;
00199             
00200             while ($masterIterator->valid() || $slaveIterator->valid()) {
00201                 $masterObject = $masterIterator->current();
00202                 $slaveObject = $slaveIterator->current();
00203                 
00204                 $masterObject = $this->convertMasterObjectToSlave($masterObject);
00205                 
00206                 $masterGetter = 'get'.ucfirst($this->masterKeyProperty);
00207                 $slaveGetter = 'get'.ucfirst($this->slaveKeyProperty);
00208                 
00209                 if (
00210                     $masterObject && $slaveObject
00211                     && (
00212                         $masterObject->$masterGetter()
00213                             == $slaveObject->$slaveGetter()
00214                     )
00215                 ) {
00216                     if ($this->sync($slaveObject, $masterObject))
00217                         $this->totalUpdated++;
00218                     
00219                     $masterIterator->next();
00220                     $slaveIterator->next();
00221                 } elseif (
00222                     !$masterObject
00223                     || (
00224                         $slaveObject
00225                         && $this->compareKeys(
00226                             $masterObject->$masterGetter(),
00227                             $slaveObject->$slaveGetter()
00228                         ) > 0
00229                     )
00230                 ) {
00231                     if ($this->delete($slaveObject))
00232                         $this->totalDeleted++;
00233                     
00234                     $slaveIterator->next();
00235                 } elseif (
00236                     !$slaveObject
00237                     || (
00238                         $masterObject
00239                         && $this->compareKeys(
00240                             $masterObject->$masterGetter(),
00241                             $slaveObject->$slaveGetter()
00242                         ) < 0
00243                     )
00244                 ) {
00245                     if ($this->insert($masterObject))
00246                         $this->totalInserted++;
00247                     
00248                     $masterIterator->next();
00249                     
00250                 } else {
00251                     Assert::isUnreachable('how did you get here?');
00252                 }
00253             }
00254             
00255             return $this;
00256         }
00257         
00258         public function getTotalInserted()
00259         {
00260             return $this->totalInserted;
00261         }
00262         
00263         public function getTotalDeleted()
00264         {
00265             return $this->totalDeleted;
00266         }
00267         
00268         public function getTotalUpdated()
00269         {
00270             return $this->totalUpdated;
00271         }
00272         
00273         protected function sync($old, $object)
00274         {
00275             if (!$this->dryRun)
00276                 $this->slave->merge($object);
00277             
00278             return true;
00279         }
00280         
00281         protected function delete($slaveObject)
00282         {
00283             $slaveGetter = 'get'.ucfirst($this->slaveKeyProperty);
00284             
00285             Assert::methodExists($slaveObject, $slaveGetter);
00286             
00287             if (!$this->dryRun && $this->reallyDelete)
00288                 $this->slave->dropById($slaveObject->$slaveGetter());
00289             
00290             return true;
00291         }
00292         
00293         protected function insert($masterObject)
00294         {
00295             if (!$this->dryRun)
00296                 $this->slave->import($masterObject);
00297             
00298             return true;
00299         }
00300         
00301         protected function compareKeys($min, $sub)
00302         {
00303             if ($min > $sub)
00304                 return 1;
00305             elseif ($min < $sub)
00306                 return -1;
00307             
00308             return 0;
00309         }
00310         
00311         private function convertMasterObjectToSlave($masterObject)
00312         {
00313             if (
00314                 $masterObject
00315                 && (
00316                     call_user_func(
00317                         array($this->slave->getObjectName(), 'create')
00318                     )
00319                     instanceof SynchronizableObject
00320                 )
00321             )
00322                 $masterObject = call_user_func(
00323                     array(
00324                         $this->slave->getObjectName(),
00325                         'createFromMasterObject'
00326                     ),
00327                     $masterObject
00328                 );
00329             
00330             return $masterObject;
00331         }
00332     }
00333 ?>