public function prepareObject(TypeInterface $controller, $parent = null) { $config = $controller->getConfig(); $class = $config['storage']; $object = new $class(); if (null !== $parent) { $baseclass = \midcom_helper_reflector::resolve_baseclass($class); $reflector = new \midgard_reflection_property($baseclass); $up_property = \midgard_object_class::get_property_up($baseclass); if (!empty($up_property)) { $target_property = $reflector->get_link_target($up_property); $target_class = $reflector->get_link_name($up_property); if (\midcom_helper_reflector::resolve_baseclass($parent) === $target_class) { $object->{$up_property} = $parent->{$target_property}; } } $parent_property = \midgard_object_class::get_property_parent($baseclass); if (!empty($parent_property)) { $target_property = $reflector->get_link_target($parent_property); $target_class = $reflector->get_link_name($parent_property); if (\midcom_helper_reflector::resolve_baseclass($parent) === $target_class) { $object->{$parent_property} = $parent->{$target_property}; } else { $object->{$parent_property} = $parent->{$parent_property}; } } } return $object; }
/** * Get the target properties and return an array that is used e.g. in copying * * @param mixed $object MgdSchema object or MidCOM db object * @return array id, parent property, class and label of the object */ public static function get_target_properties($object) { $mgdschema_class = midcom_helper_reflector::resolve_baseclass($object); $mgdschema_object = new $mgdschema_class($object->guid); static $targets = array(); // Return the cached results if (isset($targets[$mgdschema_class])) { return $targets[$mgdschema_class]; } // Empty result set for the current class $target = array('id' => null, 'parent' => '', 'class' => $mgdschema_class, 'label' => '', 'reflector' => new midcom_helper_reflector($object)); // Try to get the parent property for determining, which property should be // used to point the parent of the new object. Attachments are a special case. if (!midcom::get('dbfactory')->is_a($object, 'midcom_db_attachment')) { $parent_property = midgard_object_class::get_property_parent($mgdschema_object); } else { $parent_property = 'parentobject'; } // Get the class label $target['label'] = $target['reflector']->get_label_property(); // Try once more to get the parent property, but now try up as a backup if (!$parent_property) { $up_property = midgard_object_class::get_property_up($mgdschema_object); if (!$up_property) { throw new midcom_error('Failed to get the parent property for copying'); } $target['parent'] = $up_property; } else { $target['parent'] = $parent_property; } // Cache the results $targets[$mgdschema_class] = $target; return $targets[$mgdschema_class]; }
/** * Gets a list of link properties and the links target info * * Link info key specification * 'class' string link target class name * 'target' string link target property (of target class) * 'parent' boolean link is link to "parent" in object tree * 'up' boolean link is link to "up" in object tree * * @return array multidimensional array keyed by property, values are arrays with link info (or false in case of failure) */ public function get_link_properties() { // Return cached results if we have them static $cache = array(); if (isset($cache[$this->mgdschema_class])) { return $cache[$this->mgdschema_class]; } debug_add("Starting analysis for class {$this->mgdschema_class}"); // Shorthands $ref =& $this->_mgd_reflector; $obj =& $this->_dummy_object; // Get property list and start checking (or abort on error) $properties = get_object_vars($obj); if (empty($properties)) { debug_add("Could not list object properties, aborting", MIDCOM_LOG_ERROR); return false; } $links = array(); $parent_property = midgard_object_class::get_property_parent($obj); $up_property = midgard_object_class::get_property_up($obj); foreach ($properties as $property => $dummy) { if ($property == 'guid') { // GUID, even though of type MGD_TYPE_GUID, is never a link continue; } if (!$ref->is_link($property) && $ref->get_midgard_type($property) != MGD_TYPE_GUID) { continue; } debug_add("Processing property '{$property}'"); $linkinfo = array('class' => null, 'target' => null, 'parent' => false, 'up' => false, 'type' => $ref->get_midgard_type($property)); if (!empty($parent_property) && $parent_property === $property) { debug_add("Is 'parent' property"); $linkinfo['parent'] = true; } if (!empty($up_property) && $up_property === $property) { debug_add("Is 'up' property"); $linkinfo['up'] = true; } $type = $ref->get_link_name($property); debug_add("get_link_name returned '{$type}'"); if (!empty($type)) { $linkinfo['class'] = $type; } unset($type); $target = $ref->get_link_target($property); debug_add("get_link_target returned '{$target}'"); if (!empty($target)) { $linkinfo['target'] = $target; } elseif ($linkinfo['type'] == MGD_TYPE_GUID) { $linkinfo['target'] = 'guid'; } unset($target); $links[$property] = $linkinfo; unset($linkinfo); } debug_print_r("Links for {$this->mgdschema_class}: ", $links); $cache[$this->mgdschema_class] = $links; return $links; }
/** * Resolves the "root level" classes, used by get_root_classes() * * @return array of classnames (or false on critical failure) */ private static function _resolve_root_classes() { $root_exceptions_notroot = midcom_baseclasses_components_configuration::get('midcom.helper.reflector', 'config')->get('root_class_exceptions_notroot'); // Safety against misconfiguration if (!is_array($root_exceptions_notroot)) { debug_add("config->get('root_class_exceptions_notroot') did not return array, invalid configuration ??", MIDCOM_LOG_ERROR); $root_exceptions_notroot = array(); } $root_classes = array(); foreach (midcom_connection::get_schema_types() as $schema_type) { if (substr($schema_type, 0, 2) == '__') { continue; } if (in_array($schema_type, $root_exceptions_notroot)) { // Explicitly specified to not be root class, skip all heuristics continue; } // Class extensions mapping $schema_type = midcom_helper_reflector::class_rewrite($schema_type); // Make sure we only add classes once if (in_array($schema_type, $root_classes)) { // Already listed continue; } $parent = midgard_object_class::get_property_parent($schema_type); if (!empty($parent)) { // type has parent set, thus cannot be root type continue; } $dba_class = midcom::get('dbclassloader')->get_midcom_class_name_for_mgdschema_object($schema_type); if (!$dba_class) { // Not a MidCOM DBA object, skip continue; } $root_classes[] = $schema_type; } unset($root_exceptions_notroot); $root_exceptions_forceroot = midcom_baseclasses_components_configuration::get('midcom.helper.reflector', 'config')->get('root_class_exceptions_forceroot'); // Safety against misconfiguration if (!is_array($root_exceptions_forceroot)) { debug_add("config->get('root_class_exceptions_forceroot') did not return array, invalid configuration ??", MIDCOM_LOG_ERROR); $root_exceptions_forceroot = array(); } if (!empty($root_exceptions_forceroot)) { foreach ($root_exceptions_forceroot as $schema_type) { if (!class_exists($schema_type)) { // Not a valid class debug_add("Type {$schema_type} has been listed to always be root class, but the class does not exist", MIDCOM_LOG_WARN); continue; } if (in_array($schema_type, $root_classes)) { // Already listed continue; } $root_classes[] = $schema_type; } } usort($root_classes, 'strnatcmp'); return $root_classes; }
/** * Get the GUID of the object's parent. This is done by reading up or parent * property values, which will give us the parent's ID. Since the ID => GUID relation * won't change, the corresponding GUID is then stored in an in-request static cache */ public static function get_parent_guid_uncached_static($object_guid, $class_name) { static $parent_mapping = array(); $class_name = midcom::get('dbclassloader')->get_mgdschema_class_name_for_midcom_class($class_name); $reflector = new midgard_reflection_property($class_name); $up_property = midgard_object_class::get_property_up($class_name); if (!empty($up_property)) { $target_property = $reflector->get_link_target($up_property); // Up takes precedence over parent $mc = new midgard_collector($class_name, 'guid', $object_guid); $mc->set_key_property($up_property); $mc->execute(); $link_values = $mc->list_keys(); if (!empty($link_values)) { list($link_value, $dummy) = each($link_values); unset($mc, $link_values, $dummy); if (!empty($link_value)) { if (!array_key_exists($class_name, $parent_mapping)) { $parent_mapping[$class_name] = array(); } if (array_key_exists($link_value, $parent_mapping[$class_name])) { return $parent_mapping[$class_name][$link_value]; } $mc2 = new midgard_collector($class_name, $target_property, $link_value); $mc2->set_key_property('guid'); $mc2->execute(); $guids = $mc2->list_keys(); if (!is_array($guids)) { unset($mc2, $guids, $link_value); $parent_mapping[$class_name][$link_value] = null; return $parent_mapping[$class_name][$link_value]; } list($parent_guid, $dummy) = each($guids); $parent_mapping[$class_name][$link_value] = $parent_guid; unset($mc2, $guids, $link_value, $dummy); return $parent_guid; } } else { unset($mc, $link_values); } } $parent_property = midgard_object_class::get_property_parent($class_name); if (!empty($parent_property) && $reflector->get_link_target($parent_property)) { $target_property = $reflector->get_link_target($parent_property); $target_class = $reflector->get_link_name($parent_property); $mc = new midgard_collector($class_name, 'guid', $object_guid); $mc->set_key_property($parent_property); $mc->execute(); $link_values = $mc->list_keys(); if (!empty($link_values)) { list($link_value, $dummy) = each($link_values); unset($mc, $link_values, $dummy); if (!empty($link_value)) { if (!array_key_exists($target_class, $parent_mapping)) { $parent_mapping[$target_class] = array(); } if (array_key_exists($link_value, $parent_mapping[$target_class])) { return $parent_mapping[$target_class][$link_value]; } $mc2 = new midgard_collector($target_class, $target_property, $link_value); $mc2->set_key_property('guid'); $mc2->execute(); $guids = $mc2->list_keys(); if (!is_array($guids)) { unset($mc2, $guids, $link_value); $parent_mapping[$target_class][$link_value] = null; return $parent_mapping[$target_class][$link_value]; } list($parent_guid, $dummy) = each($guids); $parent_mapping[$target_class][$link_value] = $parent_guid; unset($mc2, $guids, $link_value, $dummy); return $parent_guid; } } else { unset($mc, $link_values); } } // FIXME: Handle GUID linking return null; }
private function getChildTypes($midgard_class) { $mgdschemas = $this->getTypes(); $child_types = array(); foreach ($mgdschemas as $mgdschema) { if ($mgdschema == 'midgard_attachment' || $mgdschema == 'midgard_parameter') { continue; } $link_properties = array('parent' => \midgard_object_class::get_property_parent($mgdschema), 'up' => \midgard_object_class::get_property_up($mgdschema)); $ref = new \midgard_reflection_property($mgdschema); foreach ($link_properties as $type => $property) { $link_class = $ref->get_link_name($property); if (empty($link_class) && $ref->get_midgard_type($property) === MGD_TYPE_GUID) { $child_types[] = $mgdschema; continue; } if ($link_class == $parent_class) { $child_types[] = $mgdschema; } } } return $child_types; }