# GenericDAO.class.php

Go to the documentation of this file.

    00001 <?php
    00002 /***************************************************************************
    00003  *   Copyright (C) 2005-2008 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
    00017     abstract class GenericDAO extends Singleton implements BaseDAO
    00018     {
    00019         private $identityMap    = array();
    00020
    00021         abstract public function getTable();
    00022         abstract public function getObjectName();
    00023
    00024         public function makeObject($array, $prefix = null)
    00025         {
    00026             if (
    00027                 isset(
    00028                     $this->identityMap[
    00029                         $array[$idName = $prefix.$this->getIdName()]
    00030                     ]
    00031                 )
    00032             ) {
    00033                 $this->getProtoClass()->skipObjectPrefetching(
    00034                     $this->identityMap[$array[$idName]]
    00035                 );
    00036
    00037                 return $this->identityMap[$array[$idName]];
    00038             }
    00039
    00040             return
    00041                 $this->completeObject(
    00042                     $this->makeOnlyObject($array, $prefix)
    00043                 );
    00044         }
    00045
    00046         public function makeOnlyObject($array, $prefix = null)
    00047         {
    00048             // adding incomplete object to identity map
    00049             // solves case with circular-dependent objects
    00050             return $this->addObjectToMap(
    00051                 $this->getProtoClass()->makeOnlyObject(
    00052                     $this->getObjectName(), $array, $prefix
    00053                 )
    00054             );
    00055         }
    00056
    00057         public function completeObject(Identifiable $object)
    00058         {
    00059             return $this->getProtoClass()->completeObject(
    00060                 // same purpose as in makeOnlyObject,
    00061                 // but for objects retrieved from cache
    00062                 $this->addObjectToMap($object)
    00063             );
    00064         }
    00065
    00072         public function getLinkName()
    00073         {
    00074             return null;
    00075         }
    00076
    00077         public function getIdName()
    00078         {
    00079             return 'id';
    00080         }
    00081
    00082         public function getSequence()
    00083         {
    00084             return $this->getTable().'_id';
    00085         }
    00086
    00090         public function getProtoClass()
    00091         {
    00092             static $protos = array();
    00093
    00094             if (!isset($protos[$className = $this->getObjectName()]))
    00095                 $protos[$className] = call_user_func(array($className, 'proto'));
    00096
    00097             return $protos[$className];
    00098         }
    00099
    00100         public function getMapping()
    00101         {
    00102             return $this->getProtoClass()->getMapping();
    00103         }
    00104
    00105         public function getFields()
    00106         {
    00107             static $fields = array();
    00108
    00109             $className = $this->getObjectName();
    00110
    00111             if (!isset($fields[$className])) {
    00112                 $fields[$className] = array_values($this->getMapping());
    00113             }
    00114
    00115             return $fields[$className];
    00116         }
    00117
    00121         public function makeSelectHead()
    00122         {
    00123             static $selectHead = array();
    00124
    00125             if (!isset($selectHead[$className = $this->getObjectName()])) {
    00126                 $table = $this->getTable();
    00127
    00128                 $object =
    00129                     OSQL::select()->
    00130                     from($table);
    00131
    00132                 foreach ($this->getFields() as $field)
    00133                     $object->get(new DBField($field, $table));
    00134
    00135                 $selectHead[$className] = $object;
    00136             }
    00137
    00138             return clone $selectHead[$className];
    00139         }
    00140
    00144         public function makeTotalCountQuery()
    00145         {
    00146             return
    00147                 OSQL::select()->
    00148                 get(
    00149                     SQLFunction::create('count', DBValue::create('*'))
    00150                 )->
    00151                 from($this->getTable());
    00152         }
    00153
    00155
    00156         public function getById($id, $expires = Cache::EXPIRES_MEDIUM)
    00157         {
    00158             Assert::isScalar($id);
    00159             Assert::isNotEmpty($id);
    00160
    00161             if (isset($this->identityMap[$id]))
    00162                 return $this->identityMap[$id];
    00163
    00164             return $this->addObjectToMap(
    00165                 Cache::worker($this)->getById($id, $expires)
    00166             );
    00167         }
    00168
    00169         public function getByLogic(
    00170             LogicalObject $logic, $expires = Cache::DO_NOT_CACHE
    00171         )
    00172         {
    00173             return $this->addObjectToMap(
    00174                 Cache::worker($this)->getByLogic($logic, $expires)
    00175             );
    00176         }
    00177
    00178         public function getByQuery(
    00179             SelectQuery $query, $expires = Cache::DO_NOT_CACHE
    00180         )
    00181         {
    00182             return $this->addObjectToMap(
    00183                 Cache::worker($this)->getByQuery($query, $expires)
    00184             );
    00185         }
    00186
    00187         public function getCustom(
    00188             SelectQuery $query, $expires = Cache::DO_NOT_CACHE
    00189         )
    00190         {
    00191             return Cache::worker($this)->getCustom($query, $expires);
    00192         }
    00193
    00194         public function getListByIds(
    00195             array $ids, $expires = Cache::EXPIRES_MEDIUM
    00196         )
    00197         {
    00198             $mapped = $remain = array();
    00199
    00200             foreach ($ids as $id) {
    00201                 if (isset($this->identityMap[$id])) {
    00202                     $mapped[] = $this->identityMap[$id];
    00203                 } else {
    00204                     $remain[] = $id;
    00205                 }
    00206             }
    00207
    00208             if ($remain) {
    00209                 $list = $this->addObjectListToMap(
    00210                     Cache::worker($this)->getListByIds($remain, $expires)
    00211                 );
    00212
    00213                 $mapped = array_merge($mapped, $list);
    00214             }
    00215
    00216             return ArrayUtils::regularizeList($ids, $mapped);
    00217         }
    00218
    00219         public function getListByQuery(
    00220             SelectQuery $query, $expires = Cache::DO_NOT_CACHE
    00221         )
    00222         {
    00223             return $this->addObjectListToMap(
    00224                 Cache::worker($this)->getListByQuery($query, $expires)
    00225             );
    00226         }
    00227
    00228         public function getListByLogic(
    00229             LogicalObject $logic, $expires = Cache::DO_NOT_CACHE
    00230         )
    00231         {
    00232             return $this->addObjectListToMap(
    00233                 Cache::worker($this)->getListByLogic($logic, $expires)
    00234             );
    00235         }
    00236
    00237         public function getPlainList($expires = Cache::EXPIRES_MEDIUM)
    00238         {
    00239             return $this->addObjectListToMap(
    00240                 Cache::worker($this)->getPlainList($expires)
    00241             );
    00242         }
    00243
    00244         public function getTotalCount($expires = Cache::DO_NOT_CACHE)
    00245         {
    00246             return Cache::worker($this)->getTotalCount($expires);
    00247         }
    00248
    00249         public function getCustomList(
    00250             SelectQuery $query, $expires = Cache::DO_NOT_CACHE
    00251         )
    00252         {
    00253             return Cache::worker($this)->getCustomList($query, $expires);
    00254         }
    00255
    00256         public function getCustomRowList(
    00257             SelectQuery $query, $expires = Cache::DO_NOT_CACHE
    00258         )
    00259         {
    00260             return Cache::worker($this)->getCustomRowList($query, $expires);
    00261         }
    00262
    00263         public function getQueryResult(
    00264             SelectQuery $query, $expires = Cache::DO_NOT_CACHE
    00265         )
    00266         {
    00267             return Cache::worker($this)->getQueryResult($query, $expires);
    00268         }
    00269
    00270         public function drop(Identifiable $object)
    00271         {
    00272             $this->checkObjectType($object);
    00273
    00274             return $this->dropById($object->getId());
    00275         }
    00276
    00277         public function dropById($id)
    00278         {
    00279             unset($this->identityMap[$id]);
    00280
    00281             $count = Cache::worker($this)->dropById($id);
    00282
    00283             if (1 != $count)
    00284                 throw new WrongStateException('no object were dropped');
    00285
    00286             return $count;
    00287         }
    00288
    00289         public function dropByIds(array $ids)
    00290         {
    00291             foreach ($ids as $id)
    00292                 unset($this->identityMap[$id]);
    00293
    00294             $count = Cache::worker($this)->dropByIds($ids);
    00295
    00296             if ($count != count($ids))
    00297                 throw new WrongStateException('not all objects were dropped');
    00298
    00299             return $count;
    00300         }
    00301
    00302         public function uncacheById($id)
    00303         {
    00304             unset($this->identityMap[$id]);
    00305
    00306             return Cache::worker($this)->uncacheById($id);
    00307         }
    00308
    00309         public function uncacheByIds($ids)
    00310         {
    00311             foreach ($ids as $id)
    00312                 unset($this->identityMap[$id]);
    00313
    00314             return Cache::worker($this)->uncacheByIds($ids);
    00315         }
    00316
    00317         public function uncacheLists()
    00318         {
    00319             $this->dropIdentityMap();
    00320
    00321             return Cache::worker($this)->uncacheLists();
    00322         }
    00324
    00328         public function dropIdentityMap()
    00329         {
    00330             $this->identityMap = array();
    00331
    00332             return $this;
    00333         }
    00334
    00335         public function dropObjectIdentityMapById($id)
    00336         {
    00337             unset($this->identityMap[$id]);
    00338
    00339             return $this;
    00340         }
    00341
    00342         protected function inject(
    00343             InsertOrUpdateQuery $query,
    00344             Identifiable $object
    00345         )
    00346         {
    00347             $this->checkObjectType($object);
    00348
    00349             return $this->doInject(
    00350                 $this->setQueryFields(
    00351                     $query->setTable($this->getTable()), $object
    00352                 ),
    00353                 $object
    00354             );
    00355         }
    00356
    00357         protected function doInject(
    00358             InsertOrUpdateQuery $query,
    00359             Identifiable $object
    00360         )
    00361         {
    00362             $db = DBPool::getByDao($this);
    00363
    00364             if (!$db->isQueueActive()) {
    00365                 $count = $db->queryCount($query);
    00366
    00367                 $this->uncacheById($object->getId());
    00368
    00369                 if ($count !== 1)
    00370                     throw new WrongStateException(
    00371                         $count.' rows affected: racy or insane inject happened: '
    00372                         .$query->toDialectString($db->getDialect())
    00373                     );
    00374             } else {
    00375                 $db->queryNull($query);
    00376
    00377                 $this->uncacheById($object->getId());
    00378             }
    00379
    00380             // clean out Identifier, if any
    00381             return $this->addObjectToMap($object->setId($object->getId()));
    00382         }
    00383
    00384         /* void */ protected function checkObjectType(Identifiable $object)
    00385         {
    00386             Assert::isSame(
    00387                 get_class($object),
    00388                 $this->getObjectName(),
    00389                 'strange object given, i can not inject it'
    00390             );
    00391         }
    00392
    00393         private function addObjectToMap(Identifiable $object)
    00394         {
    00395             return $this->identityMap[$object->getId()] = $object;
    00396         }
    00397
    00398         private function addObjectListToMap($list)
    00399         {
    00400             foreach ($list as $object)
    00401                 $this->identityMap[$object->getId()] = $object;
    00402
    00403             return $list;
    00404         }
    00405     }
    00406 ?>