# PrototypedBuilder.class.php

Go to the documentation of this file.

    00001 <?php
    00002 /***************************************************************************
    00003  *   Copyright (C) 2007 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
    00012     abstract class PrototypedBuilder
    00013     {
    00014         protected $proto        = null;
    00015
    00016         private $limitedPropertiesList  = null;
    00017
    00018         abstract protected function createEmpty();
    00019
    00023         abstract protected function getGetter($object);
    00024
    00028         abstract protected function getSetter(&$object);
    00029
    00030         public function __construct(EntityProto $proto)
    00031         {
    00032             $this->proto = $proto;
    00033         }
    00034
    00035         public function setLimitedPropertiesList($list)
    00036         {
    00037             if ($list !== null)
    00038                 Assert::isArray($list);
    00039
    00040             $mapping = $this->proto->getFullFormMapping();
    00041
    00042             foreach ($list as $key => $inner)
    00043                 Assert::isIndexExists($mapping, $key);
    00044
    00045             $this->limitedPropertiesList = $list;
    00046
    00047             return $this;
    00048         }
    00049
    00053         public function cloneBuilder(EntityProto $proto)
    00054         {
    00055             Assert::isTrue(
    00056                 $this->proto->isInstanceOf($proto)
    00057                 || $proto->isInstanceOf($this->proto),
    00058
    00059                 Assert::dumpArgument($proto)
    00060             );
    00061
    00062             $result = new $this($proto);
    00063
    00064             $result->limitedPropertiesList = $this->limitedPropertiesList;
    00065
    00066             return $result;
    00067         }
    00068
    00069         public function cloneInnerBuilder($property)
    00070         {
    00071             $mapping = $this->getFormMapping();
    00072
    00073             Assert::isIndexExists($mapping, $property);
    00074
    00075             $primitive = $mapping[$property];
    00076
    00077             Assert::isInstance($primitive, 'PrimitiveForm');
    00078
    00079             $result = new $this($primitive->getProto());
    00080
    00081             if (isset($this->limitedPropertiesList[$primitive->getName()])) {
    00082                 $result->setLimitedPropertiesList(
    00083                     $this->limitedPropertiesList[$primitive->getName()]
    00084                 );
    00085             }
    00086
    00087             return $result;
    00088         }
    00089
    00090         public function makeListItemBuilder($object)
    00091         {
    00092             return $this;
    00093         }
    00094
    00098         public function makeReverseBuilder()
    00099         {
    00100             throw new UnimplementedFeatureException(
    00101                 'reverse builder is not provided yet'
    00102             );
    00103         }
    00104
    00109         public function make($object, $recursive = true)
    00110         {
    00111             // FIXME: make entityProto() non-static, problem with forms here
    00112             if (
    00113                 ($object instanceof PrototypedEntity)
    00114                 || ($object instanceof Form)
    00115             ) {
    00116                 $proto = $this->proto;
    00117
    00118                 if ($object instanceof Form) {
    00119                     $objectProto = $object->getProto();
    00120                 } else
    00121                     $objectProto = $object->entityProto();
    00122
    00123                 if (
    00124                     $objectProto
    00125                     && !ClassUtils::isInstanceOf($proto, $objectProto)
    00126                 ) {
    00127                     if (!$objectProto->isInstanceOf($proto))
    00128                         throw new WrongArgumentException(
    00129                             'target proto '.get_class($objectProto)
    00130                             .' is not a child of '.get_class($proto)
    00131                         );
    00132
    00133                     $proto = $objectProto;
    00134
    00135                     return $this->cloneBuilder($proto)->
    00136                         make($object);
    00137                 }
    00138             }
    00139
    00140             if ($this->proto->isAbstract())
    00141                 throw new WrongArgumentException(
    00142                     'cannot make from abstract proto '
    00143                     .get_class($this->proto)
    00144                 );
    00145
    00146             return $this->compile($object, $recursive);
    00147         }
    00148
    00149         public function compile($object, $recursive = true)
    00150         {
    00151             $result = $this->createEmpty();
    00152
    00153             $this->initialize($object, $result);
    00154
    00155             if ($recursive)
    00156                 $result = $this->upperMake($object, $result);
    00157             else
    00158                 $result = $this->fillOwn($object, $result);
    00159
    00160             return $result;
    00161         }
    00162
    00163         public function upperMake($object, &$result)
    00164         {
    00165             if ($this->proto->baseProto()) {
    00166                 $this->cloneBuilder($this->proto->baseProto())->
    00167                     upperMake($object, $result);
    00168             }
    00169
    00170             return $this->fillOwn($object, $result);
    00171         }
    00172
    00173         public function makeList($objectsList, $recursive = true)
    00174         {
    00175             if ($objectsList === null)
    00176                 return null;
    00177
    00178             Assert::isArray($objectsList);
    00179
    00180             $result = array();
    00181
    00182             foreach ($objectsList as $id => $object) {
    00183                 $result[$id] = $this->makeListItemBuilder($object)->
    00184                     make($object, $recursive);
    00185             }
    00186
    00187             return $result;
    00188         }
    00189
    00193         public function makeOwn($object, &$result)
    00194         {
    00195             return $this->fillOwn($object, $result);
    00196         }
    00197
    00198         public function upperFill($object, &$result)
    00199         {
    00200             if ($this->proto->baseProto()) {
    00201                 $this->cloneBuilder($this->proto->baseProto())->
    00202                     upperFill($object, $result);
    00203             }
    00204
    00205             return $this->fillOwn($object, $result);
    00206         }
    00207
    00208         public function fillOwn($object, &$result)
    00209         {
    00210             if ($object === null)
    00211                 return $result;
    00212
    00213             $getter = $this->getGetter($object);
    00214             $setter = $this->getSetter($result);
    00215
    00216             foreach ($this->getFormMapping() as $id => $primitive) {
    00217
    00218                 $value = $getter->get($id);
    00219
    00220                 if ($primitive instanceof PrimitiveFormsList) {
    00221
    00222                     $setter->set(
    00223                         $id,
    00224                         $this->cloneInnerBuilder($id)->
    00225                             makeList($value)
    00226                     );
    00227
    00228                 } elseif ($primitive instanceof PrimitiveForm) {
    00229
    00230                     if (
    00231                         $primitive->isComposite()
    00232                         && ($previousValue = $setter->getGetter()->get($id))
    00233                     ) {
    00234
    00235                         $this->cloneInnerBuilder($id)->
    00236                             upperFill($value, $previousValue);
    00237
    00238                     } elseif ($value !== null || $primitive->isRequired()) {
    00239
    00240                         $setter->set(
    00241                             $id,
    00242                             $this->cloneInnerBuilder($id)->
    00243                                 make($value)
    00244                         );
    00245                     }
    00246
    00247                 } else {
    00248                     $setter->set($id, $value);
    00249                 }
    00250             }
    00251
    00252             return $result;
    00253         }
    00254
    00255         protected function initialize($object, &$result)
    00256         {
    00257             return $this;
    00258         }
    00259
    00260         protected function getFormMapping()
    00261         {
    00262             $protoMapping = $this->proto->getFormMapping();
    00263
    00264             if ($this->limitedPropertiesList === null)
    00265                 return $protoMapping;
    00266
    00267             $result = array();
    00268
    00269             foreach ($protoMapping as $id => $value) {
    00270                 if (!isset($this->limitedPropertiesList[$id]))
    00271                     continue;
    00272
    00273                 $result[$id] = $value;
    00274             }
    00275
    00276             return $result;
    00277         }
    00278     }
    00279 ?>