/** * @param $object object */ public function createDuplicate($object) { if ($this->dao->getObjectIdentifier($object)) { // duplicate @link Collection and Map properties values $class_name = get_class($object); $class = new Reflection_Class($class_name); /** @var $link Link_Annotation */ $link = $class->getAnnotation('link'); $exclude_properties = $link->value ? array_keys((new Reflection_Class($link->value))->getProperties([T_EXTENDS, T_USE])) : []; foreach ($class->accessProperties() as $property) { if (!$property->isStatic() && !in_array($property->name, $exclude_properties)) { $property_link = $property->getAnnotation('link')->value; // @link Collection : must disconnect objects // @link Collection | Map : duplicate and remove reference to the parent id if (in_array($property_link, [Link_Annotation::COLLECTION, Link_Annotation::MAP])) { $elements = $property->getValue($object); if ($property_link == Link_Annotation::COLLECTION) { foreach ($elements as $element) { $this->createDuplicate($element); } } $this->removeCompositeFromComponents($elements, $class_name); } } } // duplicate object $this->dao->disconnect($object); // after duplicate $this->onDuplicate($object, $class); } }
/** * @param $class Reflection_Class * @param $composite_class_name string * @return Reflection_Property_Value[] */ protected function getProperties(Reflection_Class $class, $composite_class_name = null) { $properties = []; if (isset($composite_class_name) && isA($class->name, Component::class)) { $composite_property = call_user_func([$class->name, 'getCompositeProperties'], $composite_class_name); $composite_property = reset($composite_property); } else { $composite_property = null; } if ($class->getAnnotation('link')->value) { $link_class = new Link_Class($class->name); $composite_link_property = $link_class->getCompositeProperty(); foreach ($link_class->getProperties([T_EXTENDS, T_USE]) as $property) { if ((!$composite_property || $property->name !== $composite_property->name) && (!$composite_link_property || $property->name !== $composite_link_property->name) && !$property->isStatic() && !$property->getListAnnotation('user')->has(User_Annotation::INVISIBLE)) { $properties[] = $property; } } } else { foreach ($class->getProperties([T_EXTENDS, T_USE]) as $property) { if ((empty($composite_property) || $property->name !== $composite_property->name) && !$property->isStatic() && !$property->getListAnnotation('user')->has(User_Annotation::INVISIBLE)) { $properties[] = $property; } } } return $properties; }
/** * @param $array * @param $object * @return array */ private function initLinkObject(&$array, &$object) { /** @var $link Class_\Link_Annotation */ $link = $this->class->getAnnotation('link'); if ($link->value) { $id_property_value = null; $linked_class_name = null; $link_properties = $link->getLinkProperties(); $search = []; foreach ($link_properties as $property) { if ($property->getType()->isClass()) { $property_name = $property->getName(); $id_property_name = 'id_' . $property_name; if (isset($array[$id_property_name]) && $array[$id_property_name]) { $search[$property_name] = $array[$id_property_name]; } $property_class_name = $property->getType()->asString(); if (is_a($property_class_name, $link->value, true)) { $id_property_value = isset($array[$id_property_name]) ? $array[$id_property_name] : null; $linked_class_name = $property_class_name; if (!isset($array[$id_property_name]) && !isset($array[$property_name])) { $linked_array = $array; foreach (array_keys($link_properties) as $link_property_name) { unset($linked_array[$link_property_name]); } $builder = new Object_Builder_Array($property_class_name, $this->from_form); $array[$property_name] = $builder->build($linked_array); } } } } if (count($search) >= 2) { $object = Dao::searchOne($search, $this->class->name); } if ($id_property_value && !$object) { $object = Builder::createClone(Dao::read($id_property_value, $linked_class_name), $this->class->name); } return $search; } return null; }
/** * Add a link class (using the 'link' class annotation) to joins * * @param $path string the property path * @param $class Link_Class the link class itself (which contains the @link) * @param $linked_class_name string the linked class name (the value of @link) * @param $join_mode string * @return Reflection_Property[] the properties that come from the linked class, * for further exclusion */ private function addLinkedClass($path, $class, $linked_class_name, $join_mode) { $linked_class = new Reflection_Class($linked_class_name); $join = new Join(); $join->master_alias = 't' . ($this->alias_counter - 1); $join->master_column = 'id_' . $class->getCompositeProperty($linked_class_name)->getAnnotation('storage')->value; $join->foreign_alias = 't' . $this->alias_counter++; $join->foreign_column = 'id'; $join->foreign_class = Builder::className($linked_class_name); $join->foreign_table = Dao::storeNameOf($join->foreign_class); $join->mode = $join_mode == Join::LEFT ? Join::LEFT : Join::INNER; $join->type = Join::LINK; if (!isset($this->joins[$path])) { // this ensures that the main path is set before the linked path $this->joins[$path] = null; } $this->joins[($path ? $path . '-' : '') . $join->foreign_table . '-@link'] = $join; $this->id_link_joins[$path] = $join; $this->link_joins[$path] = $join; $more_linked_class_name = $linked_class->getAnnotation('link')->value; $exclude_properties = $more_linked_class_name ? $this->addLinkedClass($path, $class, $more_linked_class_name, $join_mode) : []; foreach ($linked_class->getProperties([T_EXTENDS, T_USE]) as $property) { if (!$property->isStatic()) { if (!isset($exclude_properties[$property->name])) { $this->properties[$linked_class_name][$property->name] = $property; $property_path = ($path ? $path . DOT : '') . $property->name; $type = $property->getType(); if ($type->isClass()) { $this->classes[$property_path] = $property->getType()->getElementTypeAsString(); } $this->link_joins[$property_path] = $join; $exclude_properties[$property->name] = true; } } } return $exclude_properties; }
/** * @return string[] */ protected function getProperties() { // gets all properties from collection element class $class = new Reflection_Class($this->class_name); $properties = $class->getProperties([T_EXTENDS, T_USE]); // remove replaced properties /** @var $properties Reflection_Property[] */ $properties = Replaces_Annotations::removeReplacedProperties($properties); // remove linked class properties $linked_class = $class->getAnnotation('link')->value; if ($linked_class) { foreach (array_keys((new Reflection_Class($linked_class))->getProperties([T_EXTENDS, T_USE])) as $property_name) { unset($properties[$property_name]); } } // remove composite property $property_name = $this->property->getAnnotation('foreign')->value; if (isset($properties[$property_name])) { unset($properties[$property_name]); } // remove static and user-invisible properties foreach ($properties as $property_name => $property) { if ($property->isStatic() || $property->getListAnnotation('user')->has(User_Annotation::INVISIBLE)) { unset($properties[$property_name]); } } // returns properties return $properties; }
/** * Delete an object from current data link * * If object was originally read from data source, matching data will be overwritten. * If object was not originally read from data source, nothing is done and returns false. * * @param $object object object to delete from data source * @return boolean true if deleted * @see Data_Link::delete() */ public function delete($object) { $will_delete = true; foreach ((new Reflection_Class(get_class($object)))->getAnnotations('before_delete') as $before_delete) { /** @var $before_delete Method_Annotation */ if ($before_delete->call($object, [$this]) === false) { $will_delete = false; break; } } if ($will_delete) { $id = $this->getObjectIdentifier($object); if ($id) { $class_name = get_class($object); $class = new Reflection_Class($class_name); /** @var $link Class_\Link_Annotation */ $link = $class->getAnnotation('link'); $exclude_properties = $link->value ? array_keys((new Reflection_Class($link->value))->getProperties([T_EXTENDS, T_USE])) : []; foreach ($class->accessProperties() as $property) { if (!$property->isStatic() && !in_array($property->name, $exclude_properties)) { if ($property->getAnnotation('link')->value == Link_Annotation::COLLECTION) { if ($property->getType()->isMultiple()) { $this->deleteCollection($object, $property, $property->getValue($object)); } else { $this->delete($property->getValue($object)); trigger_error("Dead code into Mysql\\Link::delete() on {$property->name} is not so dead", E_USER_NOTICE); } } } } $this->setContext($class_name); if ($link->value) { $id = []; foreach ($link->getLinkProperties() as $link_property) { $property_name = $link_property->getName(); $column_name = ($link_property->getType()->isClass() ? 'id_' : '') . $link_property->getAnnotation('storage')->value; $id[$column_name] = $this->getObjectIdentifier($object, $property_name); } } $this->query(Sql\Builder::buildDelete($class_name, $id)); $this->disconnect($object); return true; } } return false; }
/** * The internal build method builds Table objects using a Php class definition * * It is the same than build(), but enables to add an additional field * (link field for @link classes) * * @param $class_name string * @param $more_field Column * @return Table[] */ private function buildInternal($class_name, $more_field) { $class = new Reflection_Class($class_name); $link = $class->getAnnotation('link')->value; $tables = $link ? $this->buildLinkTables($link, $class_name) : []; $tables[] = $this->buildClassTable($class, $more_field); return $tables; }