/** * Copy an object * * @param mixed &$source MgdSchema object for reading the parameters * @param mixed &$parent MgdSchema parent object * @param array $defaults * @return boolean Indicating success */ public function copy_object(&$source, &$parent = null, $defaults = array()) { // Resolve the source object self::resolve_object($source); // Duplicate the object $class_name = get_class($source); $target = new $class_name(); $properties = $this->get_object_properties($source); // Copy the object properties foreach ($properties as $property) { // Skip certain fields if (preg_match('/^(_|metadata|guid|id)/', $property)) { continue; } $target->{$property} = $source->{$property}; } // Override requested root object properties if (isset($this->target->guid) && $target->guid === $this->target->guid) { foreach ($this->root_object_values as $name => $value) { $target->{$name} = $value; } } // Override with defaults if ($defaults) { foreach ($defaults as $name => $value) { $target->{$name} = $value; } } $parent_property = $this->get_parent_property($source); // Copy the link to parent if ($parent) { self::resolve_object($parent); if (!$parent || !$parent->guid) { return false; } // @TODO: Is there a sure way to determine if the parent is // GUID or is it ID? If so, please change it here. if (is_string($source->{$parent_property})) { $parent_key = 'guid'; } else { $parent_key = 'id'; } $target->{$parent_property} = $parent->{$parent_key}; } else { if (is_string($source->{$parent_property})) { $target->{$parent_property} = ''; } else { $target->{$parent_property} = 0; } } $name_property = midcom_helper_reflector::get_name_property($target); $resolver = new midcom_helper_reflector_nameresolver($target); if (!empty($name_property) && !$resolver->name_is_safe_or_empty($name_property)) { debug_add('Source object ' . get_class($source) . " {$source->guid} has unsafe name, rewriting to safe form for the target", MIDCOM_LOG_WARN); $name_property = midcom_helper_reflector::get_name_property($target); if (empty($name_property)) { $this->errors[] = sprintf($this->_l10n->get('cannot fix unsafe name for source object %s, skipping'), get_class($source) . " {$source->guid}"); return false; } $name_parts = explode('.', $target->{$name_property}, 2); if (isset($name_parts[1])) { $target->{$name_property} = midcom_helper_misc::generate_urlname_from_string($name_parts[0]) . ".{$name_parts[1]}"; // Doublecheck safety and fall back if needed if (!$resolver->name_is_safe_or_empty()) { $target->{$name_property} = midcom_helper_misc::generate_urlname_from_string($target->{$name_property}); } } else { $target->{$name_property} = midcom_helper_misc::generate_urlname_from_string($target->{$name_property}); } unset($name_parts, $name_property); } if ($this->allow_name_catenate && $name_property) { $name = $resolver->generate_unique_name(); if ($name !== $target->{$name_property}) { $target->{$name_property} = $name; } } // This needs to be here, otherwise it will be overridden $target->allow_name_catenate = true; if (!$target->create()) { $this->errors[] = $this->_l10n->get('failed to create object: ' . mgd_errstr()); return false; } // Store for later use - if ever needed $this->new_objects[] = $target; unset($name_property); // Copy parameters if (!$this->copy_parameters($source, $target) && $this->halt_on_errors) { $this->errors[] = $this->_l10n->get('failed to copy parameters'); return false; } // Copy metadata if (!$this->copy_metadata($source, $target) && $this->halt_on_errors) { $this->errors[] = $this->_l10n->get('failed to copy metadata'); return false; } // Copy attachments if (!$this->copy_attachments($source, $target) && $this->halt_on_errors) { $this->errors[] = $this->_l10n->get('failed to copy attachments'); return false; } // Copy privileges if (!$this->copy_privileges($source, $target) && $this->halt_on_errors) { $this->errors[] = $this->_l10n->get('failed to copy privileges'); return false; } return $target; }
/** * Helper method to call in the _xxx_pre_checks, handles the API * level checks and automatic operations as specified in ticket #809 * * @see http://trac.midgard-project.org/ticket/809 * Quoting the ticket API-level section: * <pre> * 1. Checks will be done in the pre-flight check phase (ie just after _on_creating/_on_updating) * 2. If name is not unique false is returned for pre-flight check, preventing create/update * 2.2 UNLESS a property in the object ('allow_name_catenate') is set to true in which case unique one is generated by catenating an incrementing number to the name. * 3. if name is empty unique name is generated from title property (unless title is empty too) * 4. if name is not URL-safe false is returned * </pre> * * @param midcom_core_dbaobject $object The DBA object we're working on * @return boolean indicating whether from our point of view everything is ok * * @see midcom_helper_reflector_nameresolver::name_is_safe_or_empty() * @see midcom_helper_reflector_nameresolver::name_is_unique_or_empty() * @see midcom_helper_reflector_nameresolver::generate_unique_name() */ private static function _pre_check_name(midcom_core_dbaobject $object) { // Make sure name is empty of unique if the object has such property $name_property = midcom_helper_reflector::get_name_property($object); if (empty($name_property)) { // This object has no name property, return early return true; } $resolver = new midcom_helper_reflector_nameresolver($object); /** * If name is empty, try to generate new, unique one * * @see http://trac.midgard-project.org/ticket/809 */ if (empty($object->{$name_property})) { // name is empty, try to generate $new_name = $resolver->generate_unique_name(); if (!empty($new_name)) { $object->{$name_property} = $new_name; } unset($new_name); } /** * Enforce URL-safe (or empty) names * * @see http://trac.midgard-project.org/ticket/809 */ if (!$resolver->name_is_safe_or_empty()) { midcom_connection::set_error(MGD_ERR_INVALID_NAME); return false; } /** * Enforce unique (or empty) names * * @see http://trac.midgard-project.org/ticket/809 */ if (!$resolver->name_is_unique_or_empty()) { if ($object->allow_name_catenate) { // Transparent catenation allowed, let's try again. $new_name = $resolver->generate_unique_name(); if (!empty($new_name)) { $object->{$name_property} = $new_name; return true; } else { debug_add('allow_name_catenate was set but midcom_helper_reflector_nameresolver::generate_unique_name() returned empty value, falling through', MIDCOM_LOG_WARN); } } midcom_connection::set_error(MGD_ERR_OBJECT_NAME_EXISTS); return false; } // All checks ok, we're fine. return true; }