Ejemplo n.º 1
0
 /**
  * Build columns list for an object, in order to instantiate this object when read
  *
  * @param $path string
  * @param $join Join
  * @param $first_property boolean
  * @return string
  */
 private function buildObjectColumns($path, Join $join, &$first_property)
 {
     $sql_columns = '';
     if ($this->expand_objects) {
         foreach ($this->joins->getProperties($path) as $property) {
             $column_name = Sql\Builder::buildColumnName($property);
             if ($column_name) {
                 if ($first_property) {
                     $first_property = false;
                 } else {
                     $sql_columns .= ', ';
                 }
                 $sql_columns .= $join->foreign_alias . DOT . BQ . $column_name . BQ . ($this->append || !$this->resolve_aliases ? '' : ' AS ' . BQ . $path . ':' . $property->name . BQ);
             }
         }
         if ($first_property) {
             $first_property = false;
         } else {
             $sql_columns .= ', ';
         }
         $sql_columns .= $join->foreign_alias . '.id' . ($this->append || !$this->resolve_aliases ? '' : ' AS ' . BQ . $path . ':id' . BQ);
     } else {
         if ($first_property) {
             $first_property = false;
         } else {
             $sql_columns .= ', ';
         }
         $sql_columns .= $join->foreign_alias . '.id' . ($this->resolve_aliases ? ' AS ' . BQ . $path . BQ : '');
     }
     return $sql_columns;
 }
Ejemplo n.º 2
0
 /**
  * Write an object into data source
  *
  * If object was originally read from data source, corresponding data will be overwritten
  * If object was not originally read from data source nor linked to it using replace(), a new
  * record will be written into data source using this object's data.
  * If object is null (all properties null or unset), the object will be removed from data source
  *
  * TODO LOWEST factorize this to become SOLID
  *
  * @param $object  object object to write into data source
  * @param $options Option[] some options for advanced write
  * @return object the written object if written, or null if the object could not be written
  */
 public function write($object, $options = [])
 {
     if ($this->beforeWrite($object, $options)) {
         if (Null_Object::isNull($object)) {
             $this->disconnect($object);
         }
         $class = new Link_Class(get_class($object));
         $id_property = 'id';
         foreach ($options as $option) {
             if ($option instanceof Only) {
                 $only = isset($only) ? array_merge($only, $option->properties) : $option->properties;
             }
         }
         do {
             /** @var $link Class_\Link_Annotation */
             $link = $class->getAnnotation('link');
             if ($link->value) {
                 $link_property = $link->getLinkClass()->getLinkProperty();
                 $link_object = $link_property->getValue($object);
                 if (!$link_object) {
                     $id_link_property = 'id_' . $link_property->name;
                     $object->{$id_link_property} = $this->write($link_object, $options);
                 }
             }
             $table_columns_names = array_keys($this->getStoredProperties($class));
             $write_collections = [];
             $write_maps = [];
             $write = [];
             $aop_getter_ignore = Getter::$ignore;
             Getter::$ignore = true;
             $exclude_properties = $link->value ? array_keys((new Reflection_Class($link->value))->getProperties([T_EXTENDS, T_USE])) : [];
             /** @var $properties Reflection_Property[] */
             $properties = $class->accessProperties();
             $properties = Replaces_Annotations::removeReplacedProperties($properties);
             foreach ($properties as $property) {
                 if (!isset($only) || in_array($property->name, $only)) {
                     if (!$property->isStatic() && !in_array($property->name, $exclude_properties)) {
                         $value = isset($object->{$property}) ? $property->getValue($object) : null;
                         $property_is_null = $property->getAnnotation('null')->value;
                         if (is_null($value) && !$property_is_null) {
                             $value = '';
                         }
                         if (in_array($property->name, $table_columns_names)) {
                             $element_type = $property->getType()->getElementType();
                             // write basic
                             if ($element_type->isBasic()) {
                                 $write[$property->getAnnotation('storage')->value] = is_array($value) ? json_encode($value) : $value;
                             } elseif ($property->getAnnotation('store')->value == 'string') {
                                 $write[$property->getAnnotation('storage')->value] = is_array($value) ? serialize($value) : strval($value);
                             } else {
                                 $column_name = 'id_' . $property->name;
                                 if (is_object($value)) {
                                     $value_class = new Link_Class(get_class($value));
                                     $id_value = $value_class->getLinkedClassName() && !$element_type->asReflectionClass()->getAnnotation('link')->value ? 'id_' . $value_class->getCompositeProperty()->name : 'id';
                                     $object->{$column_name} = $this->getObjectIdentifier($value, $id_value);
                                     if (empty($object->{$column_name})) {
                                         $object->{$column_name} = $this->getObjectIdentifier($this->write($value), $id_value);
                                     }
                                 }
                                 $write['id_' . $property->getAnnotation('storage')->value] = $property_is_null && !isset($object->{$column_name}) ? null : intval($object->{$column_name});
                             }
                         } elseif (is_array($value) && $property->getAnnotation('link')->value == Link_Annotation::COLLECTION) {
                             $write_collections[] = [$property, $value];
                         } elseif (is_array($value) && $property->getAnnotation('link')->value == Link_Annotation::MAP) {
                             foreach ($value as $key => $val) {
                                 if (!is_object($val)) {
                                     $val = Dao::read($val, $property->getType()->getElementTypeAsString());
                                     if (isset($val)) {
                                         $value[$key] = $val;
                                     } else {
                                         unset($value[$key]);
                                     }
                                 }
                             }
                             $write_maps[] = [$property, $value];
                         }
                     }
                 }
             }
             Getter::$ignore = $aop_getter_ignore;
             if ($write) {
                 // link class : id is the couple of composite properties values
                 if ($link->value) {
                     $search = [];
                     foreach ($link->getLinkProperties() as $property) {
                         $property_name = $property->getName();
                         $column_name = $property->getType()->isClass() ? 'id_' : '';
                         $column_name .= $properties[$property_name]->getAnnotation('storage')->value;
                         if (isset($write[$column_name])) {
                             $search[$property_name] = $write[$column_name];
                         } elseif (isset($write[$property_name])) {
                             $search[$property_name] = $write[$column_name];
                         } else {
                             trigger_error("Can't search {$property_name}", E_USER_ERROR);
                         }
                     }
                     if ($this->search($search, $class->name)) {
                         $id = [];
                         foreach ($search as $property_name => $value) {
                             $column_name = $properties[$property_name]->getAnnotation('storage')->value;
                             if (isset($write['id_' . $column_name])) {
                                 $column_name = 'id_' . $column_name;
                             }
                             $id[$column_name] = $value;
                             unset($write[$column_name]);
                         }
                     } else {
                         $id = null;
                     }
                 } else {
                     $id = $this->getObjectIdentifier($object, $id_property);
                 }
                 if ($write) {
                     $this->setContext($class->name);
                     if (empty($id)) {
                         $this->disconnect($object);
                         $id = $this->query(Sql\Builder::buildInsert($class->name, $write));
                         if (!empty($id)) {
                             $this->setObjectIdentifier($object, $id);
                         }
                     } else {
                         $this->query(Sql\Builder::buildUpdate($class->name, $write, $id));
                     }
                 }
             }
             foreach ($write_collections as $write) {
                 list($property, $value) = $write;
                 $this->writeCollection($object, $property, $value);
             }
             foreach ($write_maps as $write) {
                 list($property, $value) = $write;
                 $this->writeMap($object, $property, $value);
             }
             // if link class : write linked object too
             $id_property = $link->value ? 'id_' . $class->getCompositeProperty()->name : null;
             $class = $link->value ? new Link_Class($link->value) : null;
         } while ($class && !Null_Object::isNull($object, $class->name));
         /** @var $after_writes Method_Annotation[] */
         $after_writes = (new Reflection_Class(get_class($object)))->getAnnotations('after_write');
         foreach ($after_writes as $after_write) {
             if ($after_write->call($object, [$this, $options]) === false) {
                 break;
             }
         }
         return $object;
     }
     return null;
 }
Ejemplo n.º 3
0
 /**
  * Adds a property path to the joins list
  *
  * @param $path  string full path to desired property, starting from starting class
  * @param $depth integer for internal use : please do not use this
  * @return Join the added join, or null if $path does not generate any join
  */
 public function add($path, $depth = 0)
 {
     if (isset($this->joins[$path]) || array_key_exists($path, $this->joins)) {
         return $this->joins[$path];
     }
     list($master_path, $master_property_name) = Sql\Builder::splitPropertyPath($path);
     if ($master_path && !isset($this->joins[$master_path])) {
         $this->add($master_path, $depth + 1);
     }
     if (isset($this->link_joins[$path])) {
         $property_type = $this->getProperties($master_path)[$master_property_name]->getType();
         if ($property_type->isClass()) {
             $linked_master_alias = $this->link_joins[$path]->foreign_alias;
         } else {
             return $this->link_joins[$path];
         }
     }
     $join = new Join();
     $foreign_class_name = strpos($master_property_name, '->') ? $this->addReverseJoin($join, $master_path, $master_property_name, $path) : $this->addSimpleJoin($join, $master_path, $master_property_name, $path);
     $this->joins[$path] = $join->mode ? $this->addFinalize($join, $master_path, $foreign_class_name, $path, $depth) : null;
     if (isset($linked_master_alias)) {
         $join->master_alias = $linked_master_alias;
     }
     return $this->joins[$path];
 }
Ejemplo n.º 4
0
 /**
  * Build SQL WHERE section for given path and value
  *
  * @param $path        string|integer Property path starting by a root class property (may be a numeric key, or a structure keyword)
  * @param $value       mixed May be a value, or a structured array of multiple where clauses
  * @param $clause      string For multiple where clauses, tell if they are linked with 'OR' or 'AND'
  * @return string
  */
 private function buildPath($path, $value, $clause)
 {
     if ($value instanceof Func\Where) {
         $this->joins->add($path);
         list($master_path, $foreign_column) = Builder::splitPropertyPath($path);
         if ($foreign_column == 'id') {
             $prefix = '';
         } else {
             $properties = $this->joins->getProperties($master_path);
             $property = isset($properties[$foreign_column]) ? $properties[$foreign_column] : null;
             $id_links = [Link_Annotation::OBJECT, Link_Annotation::COLLECTION, Link_Annotation::MAP];
             $prefix = $property ? in_array($property->getAnnotation('link')->value, $id_links) ? 'id_' : '' : '';
         }
         return $value->toSql($this, $path, $prefix);
     } elseif ($value instanceof Date_Time) {
         // TODO a class annotation (@business? @string?) could help choose
         $value = $value->toISO(false);
     }
     switch (gettype($value)) {
         case 'NULL':
             return '';
         case 'array':
             return $this->buildArray($path, $value, $clause);
         case 'object':
             return $this->buildObject($path, $value);
         default:
             return $this->buildValue($path, $value);
     }
 }