00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00015 abstract class AbstractProtoClass extends Singleton
00016 {
00017 private $depth = 0;
00018 private $storage = array();
00019 private $skipList = array();
00020
00021 abstract protected function makePropertyList();
00022
00026 public function beginPrefetch()
00027 {
00028 $this->storage[++$this->depth] = array();
00029 $this->skipList[$this->depth] = array();
00030
00031 return $this;
00032 }
00033
00037 public function skipObjectPrefetching(Identifiable $object)
00038 {
00039 if ($this->depth) {
00040 if (!isset($this->skipList[$this->depth][$object->getId()]))
00041 $this->skipList[$this->depth][$object->getId()] = 1;
00042 else
00043 ++$this->skipList[$this->depth][$object->getId()];
00044 }
00045
00046 return $this;
00047 }
00048
00049 public function endPrefetch(array $objectList)
00050 {
00051 if (!$this->depth)
00052 throw new WrongStateException('prefetch mode is already off');
00053
00054 foreach ($this->storage[$this->depth] as $setter => $innerList) {
00055 Assert::isEqual(
00056 count($objectList),
00057 count($innerList) + array_sum($this->skipList[$this->depth])
00058 );
00059
00060 $ids = array();
00061
00062 foreach ($innerList as $inner)
00063 if ($inner)
00064 $ids[] = $inner->getId();
00065
00066
00067 foreach ($innerList as $inner)
00068 if ($inner)
00069 break;
00070
00071 if (!$inner)
00072 continue;
00073
00074
00075 $inner->dao()->getListByIds($ids);
00076
00077 $skippedMap = $this->skipList[$this->depth];
00078
00079 $i = $j = 0;
00080
00081 foreach ($objectList as $object) {
00082 $objectId = $object->getId();
00083
00084 if (isset($skippedMap[$objectId])) {
00085 if ($skippedMap[$objectId] == 1)
00086 unset($skippedMap[$objectId]);
00087 else
00088 --$skippedMap[$objectId];
00089 ++$j;
00090 continue;
00091 }
00092
00093 if ($innerList[$i]) {
00094 try {
00095
00096
00097
00098 $object->$setter(
00099 $innerList[$i]->dao()->getById(
00100 $innerList[$i]->getId()
00101 )
00102 );
00103 } catch (ObjectNotFoundException $e) {
00104 throw new WrongStateException(
00105 'possible corruption found: '.$e->getMessage()
00106 );
00107 }
00108 }
00109
00110 ++$i;
00111 }
00112
00113 Assert::isEqual(
00114 $i,
00115 count($objectList) - $j
00116 );
00117 }
00118
00119 unset($this->skipList[$this->depth], $this->storage[$this->depth--]);
00120
00121 return $objectList;
00122 }
00123
00124 public static function makeOnlyObject($className, $array, $prefix = null)
00125 {
00126 return self::assemblyObject(new $className, $array, $prefix);
00127 }
00128
00129 public static function completeObject(Prototyped $object)
00130 {
00131 return self::fetchEncapsulants($object);
00132 }
00133
00134 final public function getPropertyList()
00135 {
00136 static $lists = array();
00137
00138 $className = get_class($this);
00139
00140 if (!isset($lists[$className])) {
00141 $lists[$className] = $this->makePropertyList();
00142 }
00143
00144 return $lists[$className];
00145 }
00146
00147 final public function getExpandedPropertyList($prefix = null)
00148 {
00149 static $lists = array();
00150
00151 $className = get_class($this);
00152
00153 if (!isset($lists[$className])) {
00154 foreach ($this->makePropertyList() as $property) {
00155 if ($property instanceof InnerMetaProperty) {
00156 $lists[$className] =
00157 array_merge(
00158 $lists[$className],
00159 $property->getProto()->getExpandedPropertyList(
00160 $property->getName().':'
00161 )
00162 );
00163 } else {
00164 $lists[
00165 $className
00166 ][
00167 $prefix.$property->getName()
00168 ]
00169 = $property;
00170 }
00171 }
00172 }
00173
00174 return $lists[$className];
00175 }
00176
00181 public function getPropertyByName($name)
00182 {
00183 if ($property = $this->safePropertyGet($name))
00184 return $property;
00185
00186 throw new MissingElementException(
00187 "unknown property requested by name '{$name}'"
00188 );
00189 }
00190
00191 public function isPropertyExists($name)
00192 {
00193 return $this->safePropertyGet($name) !== null;
00194 }
00195
00199 public function makeForm($prefix = null)
00200 {
00201 $form = Form::create();
00202
00203 foreach ($this->getPropertyList() as $property) {
00204 $property->fillForm($form, $prefix);
00205 }
00206
00207 return $form;
00208 }
00209
00213 public function fillQuery(
00214 InsertOrUpdateQuery $query, Prototyped $object
00215 )
00216 {
00217 foreach ($this->getPropertyList() as $property) {
00218 $property->fillQuery($query, $object);
00219 }
00220
00221 return $query;
00222 }
00223
00224 public function getMapping()
00225 {
00226 static $mappings = array();
00227
00228 $className = get_class($this);
00229
00230 if (!isset($mappings[$className])) {
00231 $mapping = array();
00232 foreach ($this->getPropertyList() as $property) {
00233 $mapping = $property->fillMapping($mapping);
00234 }
00235 $mappings[$className] = $mapping;
00236 }
00237
00238 return $mappings[$className];
00239 }
00240
00241 public function importPrimitive(
00242 $path,
00243 Form $form,
00244 BasePrimitive $prm,
00245 $object,
00246 $ignoreNull = true
00247 )
00248 {
00249 if (strpos($path, ':') !== false) {
00250 return $this->forwardPrimitive(
00251 $path, $form, $prm, $object, $ignoreNull
00252 );
00253 } else {
00254 $property = $this->getPropertyByName($path);
00255 $getter = $property->getGetter();
00256
00257 if (
00258 !$property->isFormless()
00259 && ($property->getFetchStrategyId() == FetchStrategy::LAZY)
00260 && !$object->{$getter.'Id'}()
00261 ) {
00262 return $object;
00263 }
00264
00265 $value = $object->$getter();
00266
00267 if (!$ignoreNull || ($value !== null)) {
00268 $form->importValue($prm->getName(), $value);
00269 }
00270 }
00271
00272 return $object;
00273 }
00274
00275 public function exportPrimitive(
00276 $path,
00277 BasePrimitive $prm,
00278 $object,
00279 $ignoreNull = true
00280 )
00281 {
00282 if (strpos($path, ':') !== false) {
00283 return $this->forwardPrimitive(
00284 $path, null, $prm, $object, $ignoreNull
00285 );
00286 } else {
00287 $property = $this->getPropertyByName($path);
00288 $setter = $property->getSetter();
00289 $value = $prm->getValue();
00290
00291 if (
00292 !$ignoreNull || ($value !== null)
00293 ) {
00294 if ($property->isIdentifier()) {
00295 $value = $value->getId();
00296 }
00297
00298 $dropper = $property->getDropper();
00299
00300 if (
00301 ($value === null)
00302 && method_exists($object, $dropper)
00303 && (
00304 !$property->getRelationId()
00305 || (
00306 $property->getRelationId()
00307 == MetaRelation::ONE_TO_ONE
00308 )
00309 )
00310 ) {
00311 $object->$dropper();
00312
00313 return $object;
00314 } elseif (
00315 (
00316 $property->getRelationId()
00317 == MetaRelation::ONE_TO_MANY
00318 ) || (
00319 $property->getRelationId()
00320 == MetaRelation::MANY_TO_MANY
00321 )
00322 ) {
00323 if ($value === null)
00324 $value = array();
00325
00326 $getter = $property->getGetter();
00327 $object->$getter()->setList($value);
00328
00329 return $object;
00330 }
00331
00332 $object->$setter($value);
00333 }
00334 }
00335
00336 return $object;
00337 }
00338
00339 private static function fetchEncapsulants(Prototyped $object)
00340 {
00341 $proto = $object->proto();
00342
00343 foreach ($proto->getPropertyList() as $property) {
00344 if (
00345 $property->getRelationId() == MetaRelation::ONE_TO_ONE
00346 && ($property->getFetchStrategyId() != FetchStrategy::LAZY)
00347 ) {
00348 $getter = $property->getGetter();
00349 $setter = $property->getSetter();
00350
00351 if (($inner = $object->$getter()) instanceof DAOConnected) {
00352 if ($proto->depth)
00353 $proto->storage[$proto->depth][$setter][] = $inner;
00354 else
00355 $object->$setter(
00356 $inner->dao()->getById(
00357 $inner->getId()
00358 )
00359 );
00360 } elseif (
00361 $proto->depth
00362
00363 && method_exists($property->getClassName(), 'dao')
00364 )
00365 $proto->storage[$proto->depth][$setter][] = null;
00366 }
00367 }
00368
00369 return $object;
00370 }
00371
00372 private static function assemblyObject(
00373 Prototyped $object, $array, $prefix = null
00374 )
00375 {
00376 if ($object instanceof DAOConnected)
00377 $dao = $object->dao();
00378 else
00379 $dao = null;
00380
00381 $proto = $object->proto();
00382
00383 foreach ($proto->getPropertyList() as $property) {
00384 $setter = $property->getSetter();
00385
00386 if ($property instanceof InnerMetaProperty) {
00387 $object->$setter(
00388 $property->toValue($dao, $array, $prefix)
00389 );
00390 } elseif ($property->isBuildable($array, $prefix)) {
00391 if ($property->getRelationId() == MetaRelation::ONE_TO_ONE) {
00392 if (
00393 $property->getFetchStrategyId()
00394 == FetchStrategy::LAZY
00395 ) {
00396 $columnName = $prefix.$property->getColumnName();
00397
00398 $object->
00399 {$setter.'Id'}($array[$columnName]);
00400
00401 continue;
00402 }
00403 }
00404
00405 $object->$setter($property->toValue($dao, $array, $prefix));
00406 }
00407 }
00408
00409 return $object;
00410 }
00411
00412 private function forwardPrimitive(
00413 $path,
00414 Form $form = null,
00415 BasePrimitive $prm,
00416 $object,
00417 $ignoreNull = true
00418 )
00419 {
00420 list($propertyName, $path) = explode(':', $path, 2);
00421
00422 $property = $this->getPropertyByName($propertyName);
00423
00424 Assert::isTrue($property instanceof InnerMetaProperty);
00425
00426 $getter = $property->getGetter();
00427
00428 if ($form)
00429 return $property->getProto()->importPrimitive(
00430 $path, $form, $prm, $object->$getter(), $ignoreNull
00431 );
00432 else
00433 return $property->getProto()->exportPrimitive(
00434 $path, $prm, $object->$getter(), $ignoreNull
00435 );
00436 }
00437
00438 private function safePropertyGet($name)
00439 {
00440 $list = $this->getPropertyList();
00441
00442 if (isset($list[$name]))
00443 return $list[$name];
00444
00445 return null;
00446 }
00447 }
00448 ?>