/** * @return string */ function table() { if (!isset($this->table)) { $master_table = Dao::storeNameOf($this->property->class); $foreign_table = Dao::storeNameOf($this->property->getType()->getElementTypeAsString()); $this->table = $master_table < $foreign_table ? $master_table . '_' . $foreign_table : $foreign_table . '_' . $master_table; } return $this->table; }
/** * @param $object object * @param $foreign_object object * @return string */ public function buildQuery($object, $foreign_object) { list($table, $field1, $field2, $id1, $id2) = Map::sqlElementsOf($object, $this->property, $foreign_object); if ($this->property->getType()->getElementTypeAsString() == 'object') { $class_field = substr($field2, 3) . '_class'; return 'INSERT INTO' . SP . BQ . $table . BQ . LF . 'SET ' . $field1 . ' = ' . $id1 . ', ' . $field2 . ' = ' . $id2 . ', ' . $class_field . ' = ' . Value::escape(get_class($foreign_object)); } else { return 'INSERT INTO' . SP . BQ . $table . BQ . LF . 'SET ' . $field1 . ' = ' . $id1 . ', ' . $field2 . ' = ' . $id2; } }
/** * @param $property Reflection_Property * @param $map object[] */ public function __construct(Reflection_Property $property, $map) { $this->property = $property; $this->map = $map; $this->class_name = $this->property->getType()->getElementTypeAsString(); $class = new Reflection_Class($this->class_name); /** @var $representative Representative_Annotation */ $representative = $class->getListAnnotation('representative'); $this->properties = $representative->getProperties(); }
/** * Get current environment name possible values * * @return mixed[] */ public function values() { $type = $this->property->getType(); if ($type->isClass()) { return Dao::readAll($this->property->getType()->asString(), [Dao::sort()]); } elseif ($values = $this->property->getListAnnotation('values')->values()) { return array_combine($values, $values); } else { trigger_error("Unable to get {$this->property->name} environment values from type " . $type->asString(), E_USER_ERROR); return null; } }
/** * Property select controller, starting from a given root class * * @param $parameters Parameters * - first : the root reference class name (ie a business object) * - second : if set, the selected property path into the root reference class name * @param $form array not used * @param $files array not used * @return mixed */ public function run(Parameters $parameters, $form, $files) { $class_name = Set::elementClassNameOf($parameters->shiftUnnamed()); $property_path = $parameters->shiftUnnamed(); if (empty($property_path)) { $top_property = new Property(); $top_property->class = $class_name; $properties = $this->getProperties(new Reflection_Class($class_name)); foreach ($properties as $property) { $property->path = $property->name; } } else { $top_property = new Reflection_Property($class_name, $property_path); $properties = $this->getProperties(new Reflection_Class($top_property->getType()->getElementTypeAsString()), $top_property->final_class); foreach ($properties as $property) { $property->path = $property_path . DOT . $property->name; } if (!$parameters->getRawParameter(Parameter::CONTAINER)) { $parameters->set(Parameter::CONTAINER, 'subtree'); } } $objects = $parameters->getObjects(); array_unshift($objects, $top_property); $objects['properties'] = $properties; $objects['class_name'] = $class_name; $objects['display_full_path'] = false; /** * Objects for the view : * first Property the property object (with selected property name, or not) * 'properties' Reflection_Property[] all properties from the reference class */ return View::run($objects, $form, $files, Property::class, 'select'); }
/** * @return string */ protected function buildSingle() { if (!$this->property->getType()->isMultiple() && ($user_changes = $this->property->getAnnotations('user_change'))) { foreach ($user_changes as $user_change) { $this->on_change[] = $user_change_value = str_replace([BS, '::'], SL, $user_change->value); } } return parent::build(); }
/** * @param $value mixed * @return string */ public function formatValue($value) { $type = $this->property->getType(); if ($type->isDateTime()) { return $this->formatDateTime($value); } else { switch ($type) { case Type::BOOLEAN: return $this->formatBoolean($value); case Type::FLOAT: return $this->formatFloat($value); case Type::INTEGER: return $this->formatInteger($value); case Type::STRING: return $this->formatString($value); } return $this->formatDefault($value); } }
/** * Prepares path_classes if it is null * Must be called after prepareColumns() * * @param $property_name string */ private function preparePathClass($property_name) { $property = new Reflection_Property($this->class_name, $property_name); $class_name = $property->getType()->getElementTypeAsString(); $this->path_classes[$property_name] = $class_name; }
/** * @param $class_name string * @param $property_path string * @param $use_reverse_translation boolean if true, will try reverse translation of property names * @param $properties_alias string[] $property_path = string[string $property_alias] * @return string */ public static function propertyPathOf($class_name, $property_path, $use_reverse_translation = false, $properties_alias = null) { if (isset($properties_alias) && isset($properties_alias[$property_path])) { $property_path = $properties_alias[$property_path]; } elseif ($use_reverse_translation) { $property_class_name = $class_name; $property_names = []; foreach (explode(DOT, $property_path) as $property_name) { if ($asterisk = substr($property_name, -1) == '*') { $property_name = substr($property_name, 0, -1); } $property = null; $property_name = Names::displayToProperty($property_name); try { $property = new Reflection_Property($property_class_name, $property_name); } catch (ReflectionException $e) { $translated_property_name = Names::displayToProperty(Loc::rtr($property_name, $property_class_name)); try { $property = new Reflection_Property($property_class_name, $translated_property_name); $property_name = $translated_property_name; } catch (ReflectionException $e) { } } $property_names[] = $property_name . ($asterisk ? '*' : ''); if (!isset($property)) { break; } $property_class_name = $property->getType()->getElementTypeAsString(); } $property_path = join(DOT, $property_names); } return $property_path; }
/** * @param $object object * @param $property Reflection_Property * @return Standard_Cell */ protected function buildCell($object, Reflection_Property $property) { $value = (new Reflection_Property_View($property))->getFormattedValue($object); $cell = new Standard_Cell($value); $type = $property->getType(); if ($type->isMultiple()) { $cell->addClass('multiple'); } $cell->addClass($type->asString()); return $cell; }
/** * Write a component collection property value * * Ie when you write an order, it's implicitly needed to write it's lines * * @param $object object * @param $property Reflection_Property * @param $collection Component[] */ private function writeCollection($object, Reflection_Property $property, $collection) { // old collection $class_name = get_class($object); $old_object = Search_Object::create($class_name); $this->setObjectIdentifier($old_object, $this->getObjectIdentifier($object)); $aop_getter_ignore = Getter::$ignore; Getter::$ignore = false; $old_collection = $property->getValue($old_object); Getter::$ignore = $aop_getter_ignore; $element_class = $property->getType()->asReflectionClass(); /** @var $element_link Class_\Link_Annotation */ $element_link = $element_class->getAnnotation('link'); // collection properties : write each of them $id_set = []; if ($collection) { foreach ($collection as $key => $element) { if (!is_a($element, $element_class->getName())) { $collection[$key] = $element = Builder::createClone($element, $element_class->getName(), [$element_link->getLinkClass()->getCompositeProperty()->name => $element]); } $element->setComposite($object, $property->getAnnotation('foreign')->value); $id = $element_link->value ? $this->getLinkObjectIdentifier($element, $element_link) : $this->getObjectIdentifier($element); if (!empty($id)) { $id_set[$id] = true; } $this->write($element); } } // remove old unused elements foreach ($old_collection as $old_element) { $id = $element_link->value ? $this->getLinkObjectIdentifier($old_element, $element_link) : $this->getObjectIdentifier($old_element); if (!isset($id_set[$id])) { $this->delete($old_element); } } }
/** * @param $object object * @param $property Reflection_Property * @param $value mixed * @param $null_if_empty boolean * @return boolean */ private function buildSubObject($object, Reflection_Property $property, $value, $null_if_empty) { $is_null = $null_if_empty; $property_name = $property->name; $type = $property->getType(); if (!isset($this->builders[$property_name])) { $this->builders[$property_name] = new Object_Builder_Array($type->getElementTypeAsString(), $this->from_form); } $builder = $this->builders[$property_name]; if ($type->isMultiple()) { $is_null = $this->buildSubObjectMultiple($object, $property_name, $value, $null_if_empty, $builder); } else { $value = $builder->build($value, null, $null_if_empty); if (isset($value)) { $object->{$property_name} = $value; $is_null = false; } } return $is_null; }
/** * Builds column name from a property * * If property data type is an object, the property name will be prefixed with 'id_'. * Array properties will return null as no column should be associated to them. * * @param $property Reflection_Property * @return string|null */ public static function buildColumnName(Reflection_Property $property) { $type = $property->getType(); return $type->isBasic() ? $property->getAnnotation('storage')->value : ($type->isMultiple() ? null : 'id_' . $property->getAnnotation('storage')->value); }
/** * Gets mysql expression for a property type * * @param $property Reflection_Property * @return string */ private static function propertyTypeToMysql(Reflection_Property $property) { $property_type = $property->getType(); if ($property_type->isBasic() || $property->getAnnotation('store')->value == 'string') { if ($property_type->hasSize()) { /** @var integer $max_length */ $max_length = $property->getAnnotation('max_length')->value; $max_value = $property->getAnnotation('max_value')->value; $min_value = $property->getAnnotation('min_value')->value; $precision = $property->getAnnotation('precision')->value; $signed = $property->getAnnotation('signed')->value; $signed_length = $max_length + ($signed ? 1 : 0); if (!isset($max_length)) { if ($property_type->isNumeric()) { $max_length = 18; $signed_length = 18; } else { $max_length = 255; } } if ($property_type->isInteger()) { if (!isset($signed) && $max_value < 0 || $min_value < 0) { $signed = true; } return $max_length <= 3 && $min_value >= -128 && $max_value <= 127 && $signed ? 'tinyint(' . $signed_length . ')' : ($max_length <= 3 && $min_value >= 0 && $max_value <= 255 && !$signed ? 'tinyint(' . $max_length . ') unsigned' : ($max_length <= 5 && $min_value >= -32768 && $max_value <= 32767 ? 'smallint(' . $signed_length . ')' : ($max_length <= 5 && $min_value >= 0 && $max_value <= 65535 ? 'smallint(' . $max_length . ') unsigned' : ($max_length <= 7 && $min_value >= -8388608 && $max_value <= 8388607 ? 'mediumint(' . $signed_length . ')' : ($max_length <= 8 && $min_value >= 0 && $max_value <= 16777215 ? 'mediumint(' . $max_length . ') unsigned' : ($max_length <= 10 && $min_value >= -2147483648.0 && $max_value <= 2147483647 ? 'int(' . $signed_length . ')' : ($max_length <= 10 && $min_value >= 0 && $max_value <= 4294967295.0 ? 'int(' . $max_length . ') unsigned' : ($max_length <= 19 && $min_value >= -9.223372036854776E+18 && $max_value <= 9.223372036854776E+18 ? 'bigint(' . $signed_length . ')' : 'bigint(' . $max_length . ') unsigned')))))))); } elseif ($property_type->isFloat()) { return $precision ? 'decimal(' . $signed_length . ', ' . $precision . ')' : 'double'; } elseif ($property->getAnnotation('binary')->value) { return $max_length <= 65535 ? 'blob' : ($max_length <= 16777215 ? 'mediumblob' : 'longblob'); } else { return $max_length <= 3 ? 'char(' . $max_length . ')' : ($max_length <= 255 ? 'varchar(' . $max_length . ')' : ($max_length <= 65535 ? 'text' : ($max_length <= 16777215 ? 'mediumtext' : 'longtext'))) . ' CHARACTER SET utf8 COLLATE utf8_general_ci'; } } switch ($property_type->asString()) { case Type::_ARRAY: return null; case Type::BOOLEAN: return 'tinyint(1)'; case Type::_CALLABLE: return null; case Type::null: case Type::NULL: return null; case Type::RESOURCE: return null; case DateTime::class: case Date_Time::class: return 'datetime'; default: return 'char(255)'; } } elseif ($property_type->asString() === Type::STRING_ARRAY) { /** @var $values string[] */ $values = []; foreach ($property->getListAnnotation('values')->values() as $key => $value) { $values[$key] = str_replace(Q, Q . Q, $value); } return $values ? ($property->getAnnotation('set')->value ? 'set' : 'enum') . "('" . join("','", $values) . "')" : 'text'; } else { return 'bigint(18) unsigned'; } }
/** * Builds import settings using a recursive array coming from an input form * * @param $worksheet array * @return Import_Settings */ public static function buildForm($worksheet) { $main_class_name = null; $settings = new Import_Settings(); if (isset($worksheet['name'])) { $settings->name = $worksheet['name']; } if (isset($worksheet['classes'])) { foreach ($worksheet['classes'] as $property_path => $class) { if (ctype_upper($property_path[0])) { // the first element is always the main class name $class_name = $main_class_name = $property_path; $settings->class_name = $class_name; $property_path = ''; } else { // property paths for next elements $property_path = str_replace('>', DOT, $property_path); $property = new Reflection_Property($main_class_name, $property_path); $class_name = $property->getType()->getElementTypeAsString(); } $settings->classes[$property_path] = self::buildFormClass($class_name, $property_path, $class); } } return $settings; }
/** * @param $join Join * @param $master_path string * @param $master_property_name string * @param $foreign_path string * @return string the foreign class name * @todo use @storage to get correct master and foreign columns name */ private function addReverseJoin(Join $join, $master_path, $master_property_name, $foreign_path) { list($foreign_class_name, $foreign_property_name) = explode('->', $master_property_name); $foreign_class_name = Namespaces::defaultFullClassName($foreign_class_name, $this->classes[$master_path]); if (strpos($foreign_property_name, '=')) { list($foreign_property_name, $master_property_name) = explode('=', $foreign_property_name); $join->master_column = 'id_' . $master_property_name; } else { $join->master_column = 'id'; } $join->foreign_column = 'id_' . $foreign_property_name; $join->mode = Join::LEFT; $foreign_property = new Reflection_Property($foreign_class_name, $foreign_property_name); if ($foreign_property->getType()->isMultiple()) { $this->addLinkedJoin($join, $master_path, $foreign_path, $foreign_class_name, $foreign_property, true); } return $foreign_class_name; }
/** * Generic getter for an object * * @param $stored mixed actual value of the object, or identifier to an object, or null * @param $class_name string the object class name * @param $object object the parent object * @param $property string|Reflection_Property the parent property * @return object */ public static function getObject(&$stored, $class_name, $object = null, $property = null) { if (!(self::$ignore || is_object($stored))) { if ($property instanceof Reflection_Property) { $property_name = $property->name; } elseif (is_string($property) && is_object($object)) { $property_name = $property; $property = new Reflection_Property(get_class($object), $property_name); } if (is_object($object) && isset($property_name)) { $id_property_name = 'id_' . $property_name; if (isset($object->{$id_property_name})) { $stored = $object->{$id_property_name}; } } if (isset($stored)) { if (isset($property) && $property->getAnnotation('store')->value == 'string') { /** @var $stored_object Stringable */ $stored_object = Builder::create($property->getType()->asString()); $stored_object->fromString($stored); $stored = $stored_object; } else { $stored = isset($property) && ($dao = $property->getAnnotation('dao')->value) ? Dao::get($dao)->read($stored, $class_name) : Dao::read($stored, $class_name); } } } return $stored; }
/** * @param $property Reflection_Property * @return boolean */ public function hasRange(Reflection_Property $property) { $type_string = $property->getType()->asString(); return in_array($type_string, [Date_Time::class, Type::INTEGER, Type::STRING]); }
/** * @param $class_name string a class name * @param $property_name string a property name or a property path starting from the class * @return boolean true if the property exists */ public static function exists($class_name, $property_name) { if (strpos($property_name, DOT) !== false) { $properties_name = explode(DOT, $property_name); foreach (array_slice($properties_name, 0, -1) as $property_name) { if (!property_exists($class_name, $property_name)) { return false; } $property = new Reflection_Property($class_name, $property_name); $class_name = $property->getType()->getElementTypeAsString(); } $property_name = end($properties_name); } return property_exists($class_name, $property_name); }
/** * Changes an array into an object * * You should set only public and non-static properties values * * @param $class_name string * @param $array array * @return object */ public static function fromArray($class_name, $array) { $object = self::create($class_name); if (isset($array)) { foreach ($array as $property_name => $value) { if (is_array($value)) { $property = new Reflection_Property($class_name, $property_name); if ($property->getType()->isClass()) { $property_class_name = $property->getType()->getElementTypeAsString(); if ($property->getType()->isMultiple()) { foreach ($value as $key => $val) { $value[$key] = self::fromArray($property_class_name, $val); } } else { $value = self::fromArray($property_class_name, $value); } $property->setValue($object, $value); } } $object->{$property_name} = $value; } } return $object; }
/** * @param $property Reflection_Property * @return string */ private static function propertyReferenceTableToMysql(Reflection_Property $property) { return Dao::storeNameOf($property->getType()->asString()); }