00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00015 abstract class ProtoDAO extends GenericDAO
00016 {
00017 public function getJoinPrefix($field, $prefix = null)
00018 {
00019 return $this->getJoinName($field, $prefix).'__';
00020 }
00021
00022 public function getJoinName($field, $prefix = null)
00023 {
00024 return dechex(crc32($prefix.$this->getTable())).'_'.$field;
00025 }
00026
00027 public function fetchCollections(
00028 array $collections, array $list
00029 )
00030 {
00031 Assert::isNotEmptyArray($list);
00032
00033 $ids = ArrayUtils::getIdsArray($list);
00034
00035 $mainId = DBField::create(
00036 $this->getIdName(),
00037 $this->getTable()
00038 );
00039
00040 foreach ($collections as $path => $info) {
00041 $lazy = $info['lazy'];
00042
00043 $query =
00044 OSQL::select()->get($mainId)->
00045 from($this->getTable());
00046
00047 $proto = reset($list)->proto();
00048
00049 $this->processPath($proto, $path, $query, $this->getTable());
00050
00051 if ($criteria = $info['criteria']) {
00052 $query = $criteria->setDao($this)->fillSelectQuery($query);
00053 }
00054
00055 $query->andWhere(
00056 Expression::in($mainId, $ids)
00057 );
00058
00059 $propertyPath = $info['propertyPath'];
00060
00061 $property = $propertyPath->getFinalProperty();
00062 $proto = $propertyPath->getFinalProto();
00063 $dao = $propertyPath->getFinalDao();
00064
00065 $selfName = $this->getObjectName();
00066 $self = new $selfName;
00067 $getter = 'get'.ucfirst($property->getName());
00068
00069 Assert::isTrue(
00070 $property->getRelationId() == MetaRelation::ONE_TO_MANY
00071 || $property->getRelationId() == MetaRelation::MANY_TO_MANY
00072 );
00073
00074 $table = $dao->getJoinName($property->getColumnName());
00075
00076 $id = $this->getIdName();
00077 $collection = array();
00078
00079 if ($lazy) {
00080 if ($property->getRelationId() == MetaRelation::MANY_TO_MANY) {
00081 $childId = $self->$getter()->getChildIdField();
00082 } else {
00083 $childId = $dao->getIdName();
00084 }
00085
00086 $alias = 'cid';
00087
00088 $field = DBField::create(
00089 $childId,
00090 $self->$getter()->getHelperTable()
00091 );
00092
00093 $query->get($field, $alias);
00094
00095 if (!$property->isRequired())
00096 $query->andWhere(Expression::notNull($field));
00097
00098 try {
00099 $rows = $dao->getCustomList($query);
00100
00101 foreach ($rows as $row)
00102 if (!empty($row[$alias]))
00103 $collection[$row[$id]][] = $row[$alias];
00104
00105 } catch (ObjectNotFoundException $e) {}
00106 } else {
00107 $prefix = $table.'_';
00108
00109 foreach ($dao->getFields() as $field) {
00110 $query->get(
00111 DBField::create($field, $table),
00112 $prefix.$field
00113 );
00114 }
00115
00116 if (!$property->isRequired()) {
00117 $query->andWhere(
00118 Expression::notNull(
00119 DBField::create($dao->getIdName(), $table)
00120 )
00121 );
00122 }
00123
00124 try {
00125
00126
00127 $rows = $dao->getCustomList($query);
00128
00129 foreach ($rows as $row) {
00130 $collection[$row[$id]][] =
00131 $dao->makeObject($row, $prefix);
00132 }
00133 } catch (ObjectNotFoundException $e) {}
00134 }
00135
00136 $suffix = ucfirst($property->getName());
00137 $fillMethod = 'fill'.$suffix;
00138 $getMethod = 'get'.$suffix;
00139
00140 Assert::isTrue(
00141 method_exists(reset($list), $fillMethod),
00142 'can not find filler'
00143 );
00144
00145 Assert::isTrue(
00146 method_exists(reset($list), $getMethod),
00147 'can not find getter'
00148 );
00149
00150 foreach ($list as $object) {
00151 if (!empty($collection[$object->getId()]))
00152 $object->$fillMethod($collection[$object->getId()], $lazy);
00153 else
00154 $object->$getMethod()->mergeList(array());
00155 }
00156 }
00157
00158 return $list;
00159 }
00160
00161 protected function setQueryFields(InsertOrUpdateQuery $query, $object)
00162 {
00163 $this->checkObjectType($object);
00164
00165 return $this->getProtoClass()->fillQuery($query, $object);
00166 }
00167
00168 private function processPath(
00169 AbstractProtoClass $proto,
00170 $probablyPath,
00171 JoinCapableQuery $query,
00172 $table,
00173 $parentRequired = true,
00174 $prefix = null
00175 )
00176 {
00177 $path = explode('.', $probablyPath);
00178
00179 try {
00180 $property = $proto->getPropertyByName($path[0]);
00181 } catch (MissingElementException $e) {
00182
00183 return new DBValue($probablyPath);
00184 }
00185
00186 unset($path[0]);
00187
00188 Assert::isTrue(
00189 $property->getRelationId() != null
00190 && !$property->isGenericType()
00191 );
00192
00193 Assert::classExists($property->getClassName());
00194
00195
00196 if (!method_exists($property->getClassName(), 'dao')) {
00197 if (
00198 method_exists($property->getClassName(), 'proto')
00199 && count($path) > 1
00200 ) {
00201 return
00202 $this->processPath(
00203 $property->getProto(),
00204 implode('.', $path),
00205 $query,
00206 $table
00207 );
00208 } else {
00209 return
00210 $this->guessAtom(
00211 implode('.', $path),
00212 $query,
00213 $table,
00214 $prefix
00215 );
00216 }
00217 } else {
00218 $propertyDao = call_user_func(
00219 array($property->getClassName(), 'dao')
00220 );
00221
00222 Assert::isNotNull(
00223 $propertyDao,
00224 'can not find target dao for "'.$property->getName()
00225 .'" property at "'.get_class($proto).'"'
00226 );
00227 }
00228
00229 $alias = $propertyDao->getJoinName(
00230 $property->getColumnName(),
00231 $prefix
00232 );
00233
00234 if (
00235 $property->getRelationId() == MetaRelation::ONE_TO_MANY
00236 || $property->getRelationId() == MetaRelation::MANY_TO_MANY
00237 ) {
00238 $remoteName = $property->getClassName();
00239 $selfName = $this->getObjectName();
00240 $self = new $selfName;
00241 $getter = $property->getGetter();
00242 $dao = call_user_func(array($remoteName, 'dao'));
00243
00244 if ($property->getRelationId() == MetaRelation::MANY_TO_MANY) {
00245 $helperTable = $self->$getter()->getHelperTable();
00246 $helperAlias = $helperTable;
00247
00248 if (!$query->hasJoinedTable($helperAlias)) {
00249 $logic =
00250 Expression::eq(
00251 DBField::create(
00252 $this->getIdName(),
00253 $table
00254 ),
00255
00256 DBField::create(
00257 $self->$getter()->getParentIdField(),
00258 $helperAlias
00259 )
00260 );
00261
00262 if ($property->isRequired())
00263 $query->join($helperTable, $logic, $helperAlias);
00264 else
00265 $query->leftJoin($helperTable, $logic, $helperAlias);
00266 }
00267
00268 $logic =
00269 Expression::eq(
00270 DBField::create(
00271 $propertyDao->getIdName(),
00272 $alias
00273 ),
00274
00275 DBField::create(
00276 $self->$getter()->getChildIdField(),
00277 $helperAlias
00278 )
00279 );
00280 } else {
00281 $logic =
00282 Expression::eq(
00283 DBField::create(
00284 $self->$getter()->getParentIdField(),
00285 $alias
00286 ),
00287
00288 DBField::create(
00289 $this->getIdName(),
00290 $table
00291 )
00292 );
00293 }
00294
00295 if (!$query->hasJoinedTable($alias)) {
00296 if ($property->isRequired() && $parentRequired)
00297 $query->join($dao->getTable(), $logic, $alias);
00298 else
00299 $query->leftJoin($dao->getTable(), $logic, $alias);
00300 }
00301 } else {
00302
00303
00304 if (
00305 isset($path[1])
00306 && (count($path) == 1)
00307 && ($path[1] == $propertyDao->getIdName())
00308 )
00309 return
00310 new DBField(
00311 $property->getColumnName(),
00312 $table
00313 );
00314
00315 if (!$query->hasJoinedTable($alias)) {
00316 $logic =
00317 Expression::eq(
00318 DBField::create(
00319 $property->getColumnName(),
00320 $table
00321 ),
00322
00323 DBField::create(
00324 $propertyDao->getIdName(),
00325 $alias
00326 )
00327 );
00328
00329 if ($property->isRequired() && $parentRequired)
00330 $query->join($propertyDao->getTable(), $logic, $alias);
00331 else
00332 $query->leftJoin($propertyDao->getTable(), $logic, $alias);
00333 }
00334 }
00335
00336 if ($path) {
00337 return $propertyDao->guessAtom(
00338 implode('.', $path),
00339 $query,
00340 $alias,
00341 $property->isRequired() && $parentRequired,
00342 $propertyDao->getJoinPrefix($property->getColumnName(), $prefix)
00343 );
00344 }
00345
00346
00347 }
00348
00349 public function guessAtom(
00350 $atom,
00351 JoinCapableQuery $query,
00352 $table = null,
00353 $parentRequired = true,
00354 $prefix = null
00355 )
00356 {
00357 if ($table === null)
00358 $table = $this->getTable();
00359
00360 if (is_string($atom)) {
00361 if (strpos($atom, '.') !== false) {
00362 return
00363 $this->processPath(
00364 call_user_func(
00365 array($this->getObjectName(), 'proto')
00366 ),
00367 $atom,
00368 $query,
00369 $table,
00370 $parentRequired,
00371 $prefix
00372 );
00373 } elseif (
00374 array_key_exists(
00375 $atom,
00376 $mapping = $this->getMapping()
00377 )
00378 ) {
00379 return new DBField($mapping[$atom], $table);
00380 } elseif (
00381 ($query instanceof SelectQuery)
00382 && $query->hasAliasInside($atom)
00383 ) {
00384 return new DBField($atom);
00385 }
00386 } elseif ($atom instanceof MappableObject)
00387 return $atom->toMapped($this, $query);
00388 elseif (
00389 ($atom instanceof DBValue)
00390 || ($atom instanceof DBField)
00391 ) {
00392 return $atom;
00393 }
00394
00395 return new DBValue($atom);
00396 }
00397 }
00398 ?>