MetaClassProperty.class.php

Go to the documentation of this file.
00001 <?php
00002 /***************************************************************************
00003  *   Copyright (C) 2006-2009 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 
00015     class MetaClassProperty
00016     {
00017         private $class      = null;
00018         
00019         private $name       = null;
00020         private $columnName = null;
00021         
00022         private $type       = null;
00023         private $size       = null;
00024         
00025         private $required   = false;
00026         private $identifier = false;
00027         
00028         private $relation   = null;
00029         
00030         private $strategy   = null;
00031         
00032         public function __construct(
00033             $name,
00034             BasePropertyType $type,
00035             MetaClass $class
00036         )
00037         {
00038             $this->name = $name;
00039             
00040             $this->type = $type;
00041             
00042             $this->class = $class;
00043         }
00044         
00045         public function equals(MetaClassProperty $property)
00046         {
00047             return (
00048                 ($property->getName() == $this->getName())
00049                 && ($property->getColumnName() == $this->getColumnName())
00050                 && ($property->getType() == $this->getType())
00051                 && ($property->getSize() == $this->getSize())
00052                 && ($property->getRelation() == $this->getRelation())
00053                 && ($property->isRequired() == $this->isRequired())
00054                 && ($property->isIdentifier() == $this->isIdentifier())
00055             );
00056         }
00057         
00061         public function getClass()
00062         {
00063             return $this->class;
00064         }
00065         
00066         public function getName()
00067         {
00068             return $this->name;
00069         }
00070         
00074         public function setName($name)
00075         {
00076             $this->name = $name;
00077             
00078             return $this;
00079         }
00080         
00081         public function getColumnName()
00082         {
00083             return $this->columnName;
00084         }
00085         
00089         public function setColumnName($name)
00090         {
00091             $this->columnName = $name;
00092             
00093             return $this;
00094         }
00095         
00099         public function getConvertedName()
00100         {
00101             return strtolower(
00102                 preg_replace(':([A-Z]):', '_\1', $this->name)
00103             );
00104         }
00105         
00109         public function getType()
00110         {
00111             return $this->type;
00112         }
00113         
00114         public function getSize()
00115         {
00116             return $this->size;
00117         }
00118         
00123         public function setSize($size)
00124         {
00125             if ($this->type instanceof NumericType) {
00126                 if (strpos($size, ',') !== false) {
00127                     list($size, $precision) = explode(',', $size, 2);
00128                 
00129                     $this->type->setPrecision($precision);
00130                 }
00131             }
00132             
00133             Assert::isInteger(
00134                 $size,
00135                 'only integers allowed in size parameter'
00136             );
00137             
00138             if ($this->type->isMeasurable()) {
00139                 $this->size = $size;
00140             } else
00141                 throw new WrongArgumentException(
00142                     "size not allowed for '"
00143                     .$this->getName().'::'.get_class($this->type)
00144                     ."' type"
00145                 );
00146             
00147             return $this;
00148         }
00149         
00150         public function isRequired()
00151         {
00152             return $this->required;
00153         }
00154         
00155         public function isOptional()
00156         {
00157             return !$this->required;
00158         }
00159         
00163         public function required()
00164         {
00165             $this->required = true;
00166             
00167             return $this;
00168         }
00169         
00173         public function optional()
00174         {
00175             $this->required = false;
00176             
00177             return $this;
00178         }
00179         
00180         public function isIdentifier()
00181         {
00182             return $this->identifier;
00183         }
00184         
00188         public function setIdentifier($really = false)
00189         {
00190             $this->identifier = ($really === true);
00191             
00192             return $this;
00193         }
00194         
00198         public function getRelation()
00199         {
00200             return $this->relation;
00201         }
00202         
00203         public function getRelationId()
00204         {
00205             if ($this->relation)
00206                 return $this->relation->getId();
00207             
00208             return null;
00209         }
00210         
00214         public function setRelation(MetaRelation $relation)
00215         {
00216             $this->relation = $relation;
00217             
00218             return $this;
00219         }
00220         
00224         public function setFetchStrategy(FetchStrategy $strategy)
00225         {
00226             $this->strategy = $strategy;
00227             
00228             return $this;
00229         }
00230         
00234         public function getFetchStrategy()
00235         {
00236             return $this->strategy;
00237         }
00238         
00239         public function getFetchStrategyId()
00240         {
00241             if ($this->strategy)
00242                 return $this->strategy->getId();
00243             elseif (
00244                 $this->getClass()->getFetchStrategyId()
00245                 && ($this->getRelationId() == MetaRelation::ONE_TO_ONE)
00246                 && ($this->getType() instanceof ObjectType)
00247                 && (!$this->getType()->isGeneric())
00248             )
00249                 return $this->getClass()->getFetchStrategyId();
00250             
00251             return null;
00252         }
00253         
00254         public function toMethods(
00255             MetaClass $class,
00256             MetaClassProperty $holder = null
00257         )
00258         {
00259             return $this->type->toMethods($class, $this, $holder);
00260         }
00261         
00262         public function getRelationColumnName()
00263         {
00264             if ($this->type instanceof ObjectType && !$this->type->isGeneric()) {
00265                 if ($this->relation->getId() == MetaRelation::MANY_TO_MANY)
00266                     $columnName = $this->type->getClass()->getTableName().'_id';
00267                 else
00268                     $columnName = $this->getColumnName();
00269             } elseif ($this->type instanceof InternalType) {
00270                 $out = array();
00271                 foreach ($this->type->getSuffixList() as $suffix) {
00272                     $out[] = $this->getColumnName().'_'.$suffix;
00273                 }
00274                 return $out;
00275             } else
00276                 $columnName = $this->getColumnName();
00277             
00278             return $columnName;
00279         }
00280         
00281         public function toColumn()
00282         {
00283             if (
00284                 $this->getType() instanceof ObjectType
00285                 && (
00286                     ($this->getType() instanceof InternalType)
00287                     || (
00288                         !$this->getType()->isGeneric()
00289                         && (
00290                             $this->getType()->getClass()->getPattern()
00291                                 instanceof ValueObjectPattern
00292                         )
00293                     )
00294                 )
00295             ) {
00296                 $columns = array();
00297                 
00298                 $prefix =
00299                     $this->getType() instanceof InternalType
00300                         ? $this->getColumnName().'_'
00301                         : null;
00302                 
00303                 $remote = $this->getType()->getClass();
00304                 
00305                 foreach ($remote->getAllProperties() as $property) {
00306                     $columns[] = $property->buildColumn(
00307                         $prefix.$property->getRelationColumnName()
00308                     );
00309                 }
00310                 
00311                 return $columns;
00312             }
00313             
00314             return $this->buildColumn($this->getRelationColumnName());
00315         }
00316         
00317         public function toLightProperty(MetaClass $holder)
00318         {
00319             $className = null;
00320             
00321             if (
00322                 ($this->getRelationId() == MetaRelation::ONE_TO_MANY)
00323                 || ($this->getRelationId() == MetaRelation::MANY_TO_MANY)
00324             ) {
00325                 // collections
00326                 $primitiveName = 'identifierList';
00327             } elseif ($this->isIdentifier()) {
00328                 if ($this->getType() instanceof IntegerType) {
00329                     $primitiveName = 'integerIdentifier';
00330                     $className = $holder->getName();
00331                 } elseif ($this->getType() instanceof StringType) {
00332                     $primitiveName = 'scalarIdentifier';
00333                     $className = $holder->getName();
00334                 } else
00335                     $primitiveName = $this->getType()->getPrimitiveName();
00336             } elseif (
00337                 !$this->isIdentifier()
00338                 && !$this->getType()->isGeneric()
00339                 && ($this->getType() instanceof ObjectType)
00340             ) {
00341                 $pattern = $this->getType()->getClass()->getPattern();
00342 
00343                 if ($pattern instanceof EnumerationClassPattern) {
00344                     $primitiveName = 'enumeration';
00345                 } elseif (
00346                     $pattern instanceof DictionaryClassPattern
00347                     && ($identifier = $this->getType()->getClass()->getIdentifier())
00348                 ) {
00349                     if ($identifier->getType() instanceof IntegerType) {
00350                         $primitiveName = 'integerIdentifier';
00351                     } elseif ($identifier->getType() instanceof StringType) {
00352                         $primitiveName = 'scalarIdentifier';
00353                     } else
00354                         $primitiveName = $this->getType()->getPrimitiveName();
00355                 } else 
00356                     $primitiveName = $this->getType()->getPrimitiveName();
00357             } else
00358                 $primitiveName = $this->getType()->getPrimitiveName();
00359             
00360             $inner = false;
00361             
00362             if ($this->getType() instanceof ObjectType) {
00363                 $className = $this->getType()->getClassName();
00364                 
00365                 if (!$this->getType()->isGeneric()) {
00366                     $class = $this->getType()->getClass();
00367                     $pattern = $class->getPattern();
00368                     
00369                     if ($pattern instanceof InternalClassPattern)
00370                         $className = $holder->getName();
00371                     
00372                     if (
00373                         (
00374                             ($pattern instanceof InternalClassPattern)
00375                             || ($pattern instanceof ValueObjectPattern)
00376                         ) && (
00377                             $className <> $holder->getName()
00378                         )
00379                     ) {
00380                         $inner = true;
00381                     }
00382                 }
00383             }
00384             
00385             $propertyClassName = (
00386                 $inner
00387                     ? 'InnerMetaProperty'
00388                     : 'LightMetaProperty'
00389             );
00390             
00391             if (
00392                 ($this->getType() instanceof IntegerType)
00393             ) {
00394                 $size = $this->getType()->getSize();
00395             } elseif (
00396                 ($this->getType() instanceof ObjectType)
00397                 && ($this->getRelationId() == MetaRelation::ONE_TO_ONE)
00398                 && ($identifier = $this->getType()->getClass()->getIdentifier())
00399                 && ($this->getType()->isMeasurable())
00400             ) {
00401                 $size = $identifier->getType()->getSize();
00402             } elseif ($this->getType()->isMeasurable()) {
00403                 $size = $this->size;
00404             } else {
00405                 $size = null;
00406             }
00407             
00408             return
00409                 call_user_func_array(
00410                     array($propertyClassName, 'fill'),
00411                     array(
00412                         new $propertyClassName,
00413                         $this->getName(),
00414                         $this->getName() <> $this->getRelationColumnName()
00415                             ? $this->getRelationColumnName()
00416                             : null,
00417                         $primitiveName,
00418                         $className,
00419                         $size,
00420                         $this->isRequired(),
00421                         $this->getType()->isGeneric(),
00422                         $inner,
00423                         $this->getRelationId(),
00424                         $this->getFetchStrategyId()
00425                     )
00426                 );
00427         }
00428 
00429         private function buildColumn($columnName)
00430         {
00431             if (is_array($columnName)) {
00432                 $out = array();
00433                 
00434                 foreach ($columnName as $name) {
00435                     $out[] = $this->buildColumn($name);
00436                 }
00437                 
00438                 return $out;
00439             }
00440             
00441             $column = <<<EOT
00442 addColumn(
00443     DBColumn::create(
00444         {$this->type->toColumnType($this->size)}
00445 EOT;
00446 
00447             if ($this->required) {
00448                 $column .= <<<EOT
00449 ->
00450 setNull(false)
00451 EOT;
00452             }
00453             
00454             if ($this->size) {
00455                 $column .= <<<EOT
00456 ->
00457 setSize({$this->size})
00458 EOT;
00459             }
00460             
00461             if ($this->type instanceof NumericType) {
00462                 $column .= <<<EOT
00463 ->
00464 setPrecision({$this->type->getPrecision()})
00465 EOT;
00466             }
00467             
00468             $column .= <<<EOT
00469 ,
00470 '{$columnName}'
00471 )
00472 EOT;
00473 
00474             if ($this->identifier) {
00475                 $column .= <<<EOT
00476 ->
00477 setPrimaryKey(true)
00478 EOT;
00479                 
00480                 if ($this->getType() instanceof IntegerType) {
00481                     $column .= <<<EOT
00482 ->
00483 setAutoincrement(true)
00484 EOT;
00485                 }
00486             }
00487             
00488             if ($this->type->hasDefault()) {
00489                 $default = $this->type->getDefault();
00490                 
00491                 if ($this->type instanceof BooleanType) {
00492                     if ($default)
00493                         $default = 'true';
00494                     else
00495                         $default = 'false';
00496                 } elseif ($this->type instanceof StringType) {
00497                     $default = "'{$default}'";
00498                 }
00499                 
00500                 $column .= <<<EOT
00501 ->
00502 setDefault({$default})
00503 EOT;
00504             }
00505             
00506             $column .= <<<EOT
00507 
00508 )
00509 EOT;
00510             
00511             return $column;
00512         }
00513         
00514         private function toVarName($name)
00515         {
00516             return strtolower($name[0]).substr($name, 1);
00517         }
00518     }
00519 ?>