/** * Returns true if an object / class /interface / trait is a class / interface / trait * * All parent classes, interfaces and traits are scanned recursively * * @param $object string|object * @param $class_name string|object * @return boolean */ function isA($object, $class_name) { if (is_string($object)) { $object = Builder::className($object); } elseif (is_object($object)) { $object = get_class($object); } else { return false; } if (is_object($class_name)) { $class_name = get_class($class_name); } if (is_a($object, $class_name, true)) { return true; } $classes = class_parents($object) + class_uses($object); while ($classes) { $next_classes = []; foreach ($classes as $class) { if (is_a($class, $class_name, true)) { return true; } $next_classes += class_uses($class); } $classes = $next_classes; } return false; }
/** * Returns a new instance of an object, but sets all its properties values to empty * * The empty value depends on the type of the property, simple type get an empty value of the * same type. Object, resource, callable properties get an empty value of null. * * @param $class_name string * @return object */ public static function create($class_name) { $object = Builder::create($class_name); foreach ((new Reflection_Class($class_name))->accessProperties() as $property) { if (!$property->isStatic()) { switch ($property->getType()->asString()) { case Type::INTEGER: case Type::FLOAT: $value = 0; break; case Type::STRING: $value = ''; break; case Type::BOOLEAN: $value = false; break; case Type::_ARRAY: $value = []; break; default: $value = null; } $property->setValue($object, $value); } } return $object; }
/** * Gets/sets current environment's object * * @param $set_current mixed * @return Current */ public static function current($set_current = null) { $called_class = get_called_class(); // set current (ignore Reflection_Property : to enable use of @default Class::current) if ($set_current && !is_a($set_current, Reflection_Property::class)) { static::$current = $set_current; if (!is_a($called_class, Plugin::class, true)) { Session::current()->set($set_current, Builder::current()->sourceClassName($called_class)); } } elseif (!isset(static::$current)) { // get current plugin from plugins manager if (is_a($called_class, Plugin::class, true)) { if ($called_class === Builder::class) { static::$current = new Builder(); } else { $plugin = Session::current()->plugins->get(Builder::current()->sourceClassName($called_class)); if (!isset(static::$current)) { static::$current = $plugin; } } } else { static::$current = Session::current()->get($called_class); } } return static::$current; }
/** * @return Body */ protected function buildBody() { $body = parent::buildBody(); $row = $this->buildRow(Builder::create($this->class_name)); $row->addClass('new'); $body->addRow($row); return $body; }
/** * @param $parameters Parameters * @param $form array * @param $class_name string * @return mixed[] */ protected function getViewParameters(Parameters $parameters, $form, $class_name) { $parameters = $parameters->getObjects(); $object = reset($parameters); if (empty($object) || !is_object($object) || !is_a($object, $class_name, true)) { $object = Builder::create($class_name); $parameters = array_merge([$class_name => $object], $parameters); } return $parameters; }
/** * Returns a new instance of an object, but sets all its properties values to null * * @param $class_name string * @return object */ public static function create($class_name) { $object = Builder::create($class_name); foreach ((new Reflection_Class($class_name))->accessProperties() as $property) { if (!$property->isStatic()) { $property->setValue($object, null); } } return $object; }
/** * @param $elements Setting[] */ public function __construct($elements = null) { $settings = []; if (isset($elements)) { foreach ($elements as $setting) { $settings[$setting->code] = $setting; } } parent::__construct(Builder::className('SAF\\Framework\\Setting'), $settings); }
/** * @before SAF\Framework\Dao\Data_Link::write($this) */ public function setNumber() { if (isA($this, Has_Counter::class)) { /** @var $counter Counter */ $counter = Dao::searchOne(['class_name' => get_class($this)], Counter::class); if (!isset($counter)) { $counter = Builder::create(Counter::class, [get_class($this)]); } $this->setCounter($counter->increment()); } }
/** * Run the default json controller * * @param $parameters Parameters * @param $form array * @param $files array * @param $class_name string * @return string */ public function run(Parameters $parameters, $form, $files, $class_name) { $parameters = $parameters->getObjects(); // read all objects corresponding to class name if (!$parameters) { return json_encode(Dao::readAll(Names::setToClass($class_name, false), [Dao::sort()])); } // read object $first_parameter = reset($parameters); if (is_object($first_parameter)) { return json_encode($first_parameter); } // search objects for autocomplete combo pull-down list if (isset($parameters['term'])) { $element_class_name = Names::setToClass($class_name, false); $search = null; if (!empty($parameters['term'])) { $search = (new Search_Array_Builder())->buildMultiple(new Reflection_Class($element_class_name), $parameters['term'], '', '%'); } if (isset($parameters['filters']) && $parameters['filters']) { if (!(is_object($search) && $search->isAnd())) { $search = Dao\Func::andOp($search ? [$search] : []); } foreach ($parameters['filters'] as $filter_name => $filter_value) { $search->arguments[$filter_name] = $filter_value[0] == '!' ? Dao\Func::notEqual(substr($filter_value, 1)) : $filter_value; } if (count($search->arguments) == 1) { reset($search->arguments); $search = [key($search->arguments) => current($search->arguments)]; } } $objects = []; // first object only if (isset($parameters['first']) && $parameters['first']) { $objects = Dao::search($search, $element_class_name, [Dao::sort(), Dao::limit(1)]); $source_object = $objects ? reset($objects) : Builder::create($element_class_name); return json_encode(new Autocomplete_Entry(Dao::getObjectIdentifier($source_object), strval($source_object))); } else { $search_options = [Dao::sort()]; if (isset($parameters['limit'])) { $search_options[] = Dao::limit($parameters['limit']); } foreach (Dao::search($search, $element_class_name, $search_options) as $source_object) { $objects[] = new Autocomplete_Entry(Dao::getObjectIdentifier($source_object), strval($source_object)); } return json_encode($objects); } } elseif (isset($parameters['id'])) { $element_class_name = Names::setToClass($class_name); $source_object = Dao::read($parameters['id'], $element_class_name); return json_encode(new Autocomplete_Entry(Dao::getObjectIdentifier($source_object), strval($source_object))); } return ''; }
/** * @param $serialized string * @return void */ public function unserialize($serialized) { $this->files = []; foreach (unserialize($serialized) as $file_name => $temporary_file_name) { /** @var $file File */ $file = Builder::create(File::class); $file->name = $file_name; $file->temporary_file_name = $temporary_file_name; $this->files[] = $file; } }
/** * Load a counter linked to the class of an object from default data link and increment it * * @param $object object The object to use to format the counter * @param $identifier string The identifier of the counter ; default is get_class($object) * @return string The new counter value */ public static function increment($object, $identifier = null) { Dao::begin(); if (empty($identifier)) { $identifier = Builder::current()->sourceClassName(get_class($object)); } $counter = Dao::searchOne(['identifier' => $identifier], get_called_class()) ?: new Counter($identifier); $next_value = $counter->next($object); Dao::write($counter); Dao::commit(); return $next_value; }
/** * @param $temporary_file_name string */ public function __construct($temporary_file_name = null) { if (isset($temporary_file_name)) { if (!isset($this->name)) { $this->name = rLastParse($temporary_file_name, SL, 1, true); } $this->temporary_file_name = $temporary_file_name; } if (!isset($this->updated_on)) { $this->updated_on = Builder::create(Date_Time::class); } }
/** * Apply class name : if constructor was called without columns, this will initialize columns list * * This applies default column names if there was no default class name, or if class name changed, * or if there were no column names. * * @param $class_name string */ private function applyClassName($class_name) { if (isset($class_name) && $class_name != $this->class_name && (isset($this->class_name) || !isset($this->columns))) { $class_name = Builder::className($class_name); $this->class_name = $class_name; $columns = (new Reflection_Class($class_name))->getListAnnotation('sort')->values(); if (!$columns) { $columns = (new Reflection_Class($class_name))->getListAnnotation('representative')->values(); } $this->columns = $columns; $this->calculateReverse(); } }
/** * @param $source Reflection_Source */ public function onCompileSource(Reflection_Source $source) { Dao::begin(); foreach ($source->getClasses() as $class) { /** @var $log Compiler_Log */ $log = Builder::create(Compiler_Log::class); $log->class_name = $class->getName(); $log->date_time = Date_Time::now(); Dao::write($log); $this->log_flag = true; } Dao::commit(); }
/** * Get the object of class $class_name from session * * @param $class_name string * @param $create_default boolean Create a default object for the class name if does not exist * @return object|null */ public function get($class_name, $create_default = false) { if (isset($this->current[$class_name])) { $current = $this->current[$class_name]; if (is_array($current)) { $current = $current[1]; $this->current[$class_name] = $current = is_numeric($current) ? Dao::read($current, $class_name) : unserialize($current); } return $current; } elseif ($create_default) { return $this->current[$class_name] = Builder::create($class_name); } else { return null; } }
/** * @param $sources Reflection_Source[] Key is the file path * @return Reflection_Source[] added sources list */ public function moreSourcesToCompile(&$sources) { $added = []; foreach ($sources as $file_path => $source) { if (!strpos($file_path, SL)) { $reload = true; break; } } if (isset($reload)) { $old_compositions = Builder::current()->getCompositions(); $old_levels = Session::current()->plugins->getAll(true); if (isset(Main::$current)) { Main::$current->resetSession(); } $new_compositions = Builder::current()->getCompositions(); $new_levels = Session::current()->plugins->getAll(true); // add classes where builder composition changed foreach ($old_compositions as $class_name => $old_composition) { if (!isset($new_compositions[$class_name]) || $old_composition != $new_compositions[$class_name] || is_array($old_composition) && (array_diff($old_composition, $new_compositions[$class_name]) || array_diff($new_compositions[$class_name], $old_composition))) { $this->moreSourcesAdd($class_name, $sources, $added); } } foreach ($new_compositions as $class_name => $new_composition) { if (!isset($old_compositions[$class_name])) { $this->moreSourcesAdd($class_name, $sources, $added); } } // add classes of globally added/removed plugins foreach ($old_levels as $level => $old_plugins) { foreach ($old_plugins as $class_name => $old_plugin) { if (!isset($new_levels[$level][$class_name])) { $this->moreSourcesAdd($class_name, $sources, $added); } } } foreach ($new_levels as $level => $new_plugins) { foreach ($new_plugins as $class_name => $new_plugin) { if (!isset($old_levels[$level][$class_name])) { $this->moreSourcesAdd($class_name, $sources, $added); } } } } return $added; }
/** * Returns a new instance of a search-formatted object of given class * * This creates an object with unset properties, as only set properties are used for searches. * Private or protected properties can't be unset : they are kept with a null value. * * @param $class_name string * @return object */ public static function create($class_name) { $object = Builder::create($class_name); foreach ((new Reflection_Class(get_class($object)))->accessProperties() as $property) { if (!$property->isStatic()) { if ($property->isPublic()) { $name = $property->name; if (!isset($object->{$name}) || $object->{$name} !== $object) { unset($object->{$name}); } } else { $property->setValue($object, null); } } } return $object; }
/** * @param $form array * @param $name_element array * @param $tmp_name_element array * @return array */ private function appendToFormRecurse($form, $name_element, $tmp_name_element) { foreach ($name_element as $key => $name_sub_element) { if (is_array($name_sub_element)) { if (!isset($form[$key])) { $form[$key] = []; } $form[$key] = $this->appendToFormRecurse($form[$key], $name_sub_element, $tmp_name_element[$key]); } else { /** @var $file File */ $file = Builder::create(File::class); $file->name = $name_sub_element; $file->temporary_file_name = $tmp_name_element[$key]; $form[$key] = $file; } } return $form; }
/** * Encodes the email into MIME format * * Returns the MIME Multipart string * If the mail is plain text without attachment, the plain text is returned without any change * * @return string */ public function encode() { if ($this->email->attachments || strpos($this->email->content, '<body')) { /** @var $mail Mail_mime */ $mail = Builder::create(Mail_mime::class); $body = $this->parseImages($mail, $this->email->content); $error_reporting = error_reporting(); error_reporting(E_ALL & ~E_WARNING); $mail->setTXTBody(convert_html_to_text($this->email->content)); error_reporting($error_reporting); $mail->setHTMLBody($body); $this->addAttachments($mail); $mime_params = ['text_encoding' => '8bit', 'text_charset' => 'UTF-8', 'html_charset' => 'UTF-8', 'head_charset' => 'UTF-8']; $body = $mail->get($mime_params); $this->email->headers = $mail->headers($this->email->getHeadersAsStrings()); return $body; } return $this->email->content; }
/** * Apply namespace and use entries to the type name (if class) * * Return the full element class name, used to modify the type (multiple stays multiple) * * @param $namespace string * @param $use string[] * @return string */ public function applyNamespace($namespace, $use = []) { /** @var $this Annotation|Types_Annotation */ /** @var $values string[] */ $values = is_array($this->value) ? $this->value : [$this->value]; foreach ($values as $key => $class_name) { if (ctype_upper($class_name[0])) { if (substr($class_name, -2) == '[]') { $class_name = substr($class_name, 0, -2); $multiple = '[]'; } else { $multiple = ''; } $values[$key] = Builder::className((new Type($class_name))->applyNamespace($namespace, $use)) . $multiple; } elseif ($class_name[0] === BS) { $values[$key] = substr($class_name, 1); } } $this->value = is_array($this->value) ? $values : reset($values); }
/** * @param $template_file string * @param $parameters array * @param $feature_name string * @return string */ protected function executeTemplate($template_file, $parameters, $feature_name) { if (isset($parameters[Template::TEMPLATE])) { unset($parameters[Template::TEMPLATE]); } if (isset($parameters[Template::TEMPLATE_CLASS])) { $template_class = $parameters[Template::TEMPLATE_CLASS]; } elseif (isset($parameters[Template::TEMPLATE_NAMESPACE])) { $template_class = $parameters[Template::TEMPLATE_NAMESPACE] . BS . 'Html_Template'; unset($parameters[Template::TEMPLATE_NAMESPACE]); } else { $template_class = Template::class; } /** @var $template Template */ $template = Builder::create($template_class, [reset($parameters), $template_file, $feature_name]); $template->setParameters($parameters); $current = Framework\View::current(); if ($current instanceof Engine && ($css = $current->getCss())) { $template->setCss($css); } return $template->parse(); }
/** * When a class is compiled, all classes that extends it must be compiled too * * @param &$sources Reflection_Source[] * @return Reflection_Source[] added sources list */ public function moreSourcesToCompile(&$sources) { $added = []; // we will search all extends dependencies /** @var $dependency Dependency */ $dependency_search = Search_Object::create(Dependency::class); $dependency_search->type = Dependency::T_EXTENDS; foreach ($sources as $source) { foreach ($source->getClasses() as $class) { if (!Builder::isBuilt($class->name)) { // add all classes that extend source classes $dependency_search->dependency_name = $class->name; foreach (Dao::search($dependency_search) as $dependency) { if (!isset($sources[$dependency->file_name]) && !Builder::isBuilt($dependency->class_name)) { $added[$dependency->file_name] = new Reflection_Source($dependency->file_name); } } } } } return $added; }
/** * Includes the php file that contains the given class (must contain namespace) * * @param $class_name string class name (with or without namespace) * @return boolean */ public function autoload($class_name) { if ($i = strrpos($class_name, '\\')) { $namespace = strtolower(str_replace('\\', '/', substr($class_name, 0, $i))); $file_name = substr($class_name, $i + 1); // 'A\Class' stored into 'a/class/Class.php' if (file_exists($file1 = strtolower($namespace . '/' . $file_name) . '/' . $file_name . '.php')) { /** @noinspection PhpIncludeInspection */ $result = (include_once Include_Filter::file($file1)); } elseif (file_exists($file2 = strtolower($namespace) . '/' . $file_name . '.php')) { /** @noinspection PhpIncludeInspection */ $result = (include_once Include_Filter::file($file2)); } else { if (Builder::isBuilt($class_name)) { $file = 'cache/compiled/' . str_replace(SL, '-', Names::classToPath($class_name)); if (file_exists($file)) { /** @noinspection PhpIncludeInspection */ $result = (include_once $file); } } if (!isset($result)) { if (error_reporting()) { trigger_error('Class not found ' . $class_name . ', should be into ' . $file1 . ' or ' . $file2, E_USER_ERROR); } $result = false; } } } else { /** @noinspection PhpIncludeInspection */ $result = (include_once Include_Filter::file($class_name . '.php')); } // instantiate plugin if ($result && class_exists($class_name, false) && is_a($class_name, Plugin::class, true)) { if (Session::current()) { Session::current()->plugins->get($class_name); } } }
/** * @param $properties_list Reflection_Property[] new indices will be 'property.sub_property' * @param $property Reflection_Property * @param $object object * @param $property_name string * @param $display_prefix string * @param $blocks string[] * @return Reflection_Property[] added properties list (empty if none applies) indices are * 'property.sub_property' * @todo probably things to clean up (was patched for 'all properties as values' without controls) */ private static function expandUsingPropertyInternal(&$properties_list, $property, $object, $property_name, $display_prefix = '', $blocks = []) { $expanded = []; /** @var $integrated Integrated_Annotation */ $integrated = $property->getListAnnotation('integrated'); if ($integrated->value && !$property->isStatic()) { if ($integrated->has('block')) { $blocks[$property->path ?: $property->name] = $property->path ?: $property->name; } $integrated_simple = $integrated->has('simple'); $sub_properties_class = $property->getType()->asReflectionClass(); $expand_properties = $sub_properties_class->getProperties([T_EXTENDS, T_USE]); $value = $property->getValue($object) ?: Builder::create($property->getType()->asString()); foreach ($expand_properties as $sub_property_name => $sub_property) { if (!$sub_property->getListAnnotation('user')->has(User_Annotation::INVISIBLE)) { $display = $display_prefix . ($display_prefix ? DOT : '') . $property->name . DOT . $sub_property_name; $sub_prefix = $integrated_simple ? $display_prefix : $display; if ($more_expanded = self::expandUsingPropertyInternal($properties_list, $sub_property, $value, $property_name . DOT . $sub_property_name, $sub_prefix, $blocks)) { $expanded = array_merge($expanded, $more_expanded); } else { $sub_property = new Reflection_Property_Value($sub_property->class, $sub_property->name, $value, false, true); $sub_property->final_class = $sub_properties_class->name; $sub_property->display = $integrated_simple ? $integrated->has('alias') ? $sub_property->getAnnotation('alias')->value : $sub_property_name : $display; /** @var $block_annotation List_Annotation */ $block_annotation = $sub_property->setAnnotationLocal('block'); foreach ($blocks as $block) { $block_annotation->add($block); } $sub_property->path = $property_name . DOT . $sub_property_name; $properties_list[$property_name . DOT . $sub_property_name] = $sub_property; $expanded[$property_name . DOT . $sub_property_name] = $sub_property; } } } } return $expanded; }
/** * @param $view string * @param $view_method_name string * @param $parameters array * @param $form array * @param $files array * @param $class_name string * @param $feature_name string * @return mixed */ private static function executeView($view, $view_method_name, $parameters, $form, $files, $class_name, $feature_name) { $object = reset($parameters); $view_object = is_object($object) && isA($object, $view) ? reset($parameters) : Builder::create($view); return $view_object->{$view_method_name}($parameters, $form, $files, $class_name, $feature_name); }
/** * @param $sources Reflection_Source[] * @return Reflection_Source[] added sources list */ public function moreSourcesToCompile(&$sources) { $added = []; // search into dependencies : used classes /** @var $search Dependency */ $search = Search_Object::create(Dependency::class); $search->type = Dependency::T_USE; foreach ($sources as $source) { foreach ($source->getClasses() as $class) { if ($class->type === T_TRAIT) { $search->dependency_name = $class->name; foreach (Dao::search($search, Dependency::class) as $dependency) { while ($dependency && Builder::isBuilt($dependency->class_name)) { $search_built_parent = Search_Object::create(Dependency::class); $search_built_parent->class_name = $dependency->class_name; $search_built_parent->type = Dependency::T_EXTENDS; $dependency = Dao::searchOne($search_built_parent); if (!$dependency) { trigger_error('Not parent class for built class ' . $search_built_parent->class_name, E_USER_ERROR); } $search_built_parent->class_name = $dependency->dependency_name; $search_built_parent->type = Dependency::T_DECLARATION; $dependency = Dao::searchOne($search_built_parent); if (!$dependency) { trigger_error('Not declaration dependency for class ' . $search_built_parent->class_name, E_USER_ERROR); } } /** @var $dependency Dependency */ if (!isset($sources[$dependency->file_name])) { $source = new Reflection_Source($dependency->file_name); $sources[$dependency->file_name] = $source; $added[$dependency->file_name] = $source; } } } } } // search into dependencies : registered methods foreach ($sources as $source) { $search->file_name = $source->file_name; $search->dependency_name = Registerable::class; $search->type = Dependency::T_IMPLEMENTS; if (Dao::searchOne($search, Dependency::class)) { unset($search->dependency_name); $search->type = Dependency::T_CLASS; foreach (Dao::search($search, Dependency::class) as $dependency) { $source = Reflection_Source::of($dependency->dependency_name); if (!isset($sources[$source->file_name])) { $sources[$source->file_name] = $source; $added[$source->file_name] = $source; } } } } // classes that are already into $sources $already = []; foreach ($sources as $source) { foreach ($source->getClasses() as $class) { $already[$class->name] = true; } } // search into advices and add sources that have sources to compile as advice foreach ($this->weaver->getJoinpoints() as $class_name => $joinpoint) { if (!isset($already[$class_name])) { foreach ($joinpoint as $advices) { foreach ($advices as $advice) { if (is_array($advice = $advice[1])) { $advice_class = $advice[0]; if (is_object($advice_class)) { $advice_class = get_class($advice_class); } if (isset($already[$advice_class])) { $source = Reflection_Source::of($class_name); /* if ($source->file_name && !$source->isInternal() && !is_file($source->file_name)) { $applicant_source = Reflection_Source::of($advice_class); if ( !$source->searchFile($class_name, array_keys($applicant_source->getRequires())) ) { trigger_error( 'Reflection_Source file not found for class ' . $class_name, E_USER_ERROR ); } } */ if ($source->getClass($class_name)) { $sources[$source->file_name] = $source; $added[$source->file_name] = $source; $already[$class_name] = true; } else { trigger_error('No class ' . $class_name . ' into file ' . $source->file_name, E_USER_ERROR); } } } } } } } return $added; }
/** * Extends the list of sources to compile * * When you modify a file, all these classes may have their matching mysql structure changed : * - the class itself * - all classes that extend the class or use the trait * * @param &$sources Reflection_Source[] * @return Reflection_Source[] added sources list */ public function moreSourcesToCompile(&$sources) { $added = []; // Builder is disabled during the listing as we want to get the original linked class name when // reading class annotation @link Builder::current()->enabled = false; /** @var $search Dependency */ $search = Search_Object::create(Dependency::class); $search->file_name = Func::notLike('cache/%'); $search->type = Func::orOp([Dependency::T_EXTENDS, Dependency::T_USE]); foreach ($sources as $source) { foreach ($source->getClasses() as $class) { while ($linked_class = $class->getAnnotation('link')->value) { $source = Reflection_Class::of($linked_class)->source; if (!isset($sources[$source->file_name])) { $sources[$source->file_name] = $source; $added[$source->file_name] = $source; } $class = $source->getClass($linked_class); } $search->dependency_name = $class->name; foreach (Dao::search($search, Dependency::class) as $dependency) { /** @var $dependency Dependency */ if (!isset($sources[$dependency->file_name])) { $source = new Reflection_Source($dependency->file_name); $sources[$dependency->file_name] = $source; $added[$dependency->file_name] = $source; } } } } Builder::current()->enabled = true; return $added; }
/** * Create a clone of the object, using a built class if needed * * @param $object object * @param $class_name string if set, the new object will use the matching built class * this class name must inherit from the object's class * @param $properties_values array some properties values for the cloned object * @param $same_identifier boolean * @return object */ public static function createClone($object, $class_name = null, $properties_values = [], $same_identifier = true) { $class_name = self::className($class_name); $source_class_name = get_class($object); if (!isset($class_name)) { $class_name = self::className($source_class_name); } if ($class_name !== $source_class_name) { // initialises cloned object $clone = self::create($class_name); $destination_class = new Link_Class($class_name); // deactivate AOP if (isset($clone->_)) { $save_aop = $clone->_; unset($clone->_); } // copy official properties values from the source object $properties = (new Reflection_Class($source_class_name))->accessProperties(); foreach ($properties as $property) { if (!isset($save_aop[$property->name])) { $property->setValue($clone, $property->getValue($object)); } } // copy unofficial properties values from the source object (ie AOP properties aliases) // clone collection objects using the destination collection property type $clone_collection = []; foreach (get_object_vars($object) as $property_name => $value) { if ($property_name !== '_' && !isset($properties[$property_name])) { $clone->{$property_name} = $value; if (isset($properties[rtrim($property_name, '_')])) { $property = $properties[rtrim($property_name, '_')]; if ($property->getAnnotation('link') == Link_Annotation::COLLECTION) { $element_class_from = $property->getType()->getElementTypeAsString(); $property = $destination_class->getProperty($property->name); $element_class_to = $property->getType()->getElementTypeAsString(); if ($element_class_to != $element_class_from) { $clone_collection[substr($property_name, 0, -1)] = $element_class_to; } } } } } // reactivate AOP if (isset($save_aop)) { $clone->_ = $save_aop; } foreach ($clone_collection as $property_name => $element_class_to) { $elements = []; foreach ($object->{$property_name} as $key => $element) { $elements[$key] = Builder::createClone($element, $element_class_to, [], $same_identifier); } $clone->{$property_name} = $elements; } // linked class object to link class object : store source object to linked object $destination_class = new Link_Class($class_name); if ($linked_class_name = $destination_class->getLinkedClassName()) { if ($linked_class_name == $source_class_name) { $destination_class->getLinkProperty()->setValue($clone, $object); } } // identify destination object = source object, or disconnect destination object if ($same_identifier) { Dao::replace($clone, $object, false); } else { Dao::disconnect($clone); } } else { $clone = clone $object; } // copy added properties values to the cloned object if ($properties_values) { $properties = (new Reflection_Class($class_name))->accessProperties(); foreach ($properties_values as $property_name => $value) { $properties[$property_name]->setValue($clone, $value); } } return $clone; }
/** * @param $property_name string * @param $format_value boolean * @return mixed */ protected function parseSingleValue($property_name, $format_value = true) { $source_object = $object = reset($this->objects); if (!strlen($property_name)) { $object = $this->parseParent(); } elseif (is_numeric($property_name) && is_string($object)) { $object = substr($object, $property_name, 1); } elseif ($property_name === '#') { $object = reset($this->var_names); } elseif (strpos($property_name, '?')) { $object = $this->parseConditional($property_name); } elseif ($property_name[0] == Q && substr($property_name, -1) == Q || $property_name[0] == DQ && substr($property_name, -1) == DQ) { $object = $this->parseConstant($property_name); } elseif (isset($this->parse_class_name)) { if ($property_name === 'class') { $object = $this->parse_class_name; } elseif (method_exists($this->parse_class_name, $property_name)) { $object = $this->parseStaticMethod($this->parse_class_name, $property_name); } elseif (property_exists($this->parse_class_name, $property_name)) { $object = $this->parseStaticProperty($this->parse_class_name, $property_name); } elseif (defined($this->parse_class_name . '::' . $property_name)) { $object = constant($this->parse_class_name . '::' . $property_name); } else { $object = isA($this->parse_class_name, $this->parseClassName($property_name)); } $this->parse_class_name = null; } elseif ($property_name[0] >= 'A' && $property_name[0] <= 'Z') { if (is_array($object) && (isset($object[$property_name]) || !@class_exists($property_name))) { $object = $this->parseArrayElement($object, $property_name); } elseif (strlen($property_name) > 1 && ($property_name[1] >= 'a' && $property_name[1] <= 'z' || strpos($property_name, BS) !== false)) { $this->parse_class_name = $this->parseClassName($property_name); } else { $object = $this->parseConst($object, $property_name); } } elseif ($property_name[0] === AT) { $object = $this->parseFunc(substr($property_name, 1)); } elseif ($i = strpos($property_name, '(')) { if ((is_object($object) || ctype_upper($object[0])) && method_exists($object, substr($property_name, 0, $i))) { $object = $this->parseMethod($object, $property_name); } else { $object = $this->callFunc(reset($this->objects), $property_name); } } elseif (is_array($object)) { $object = $this->parseArrayElement($object, $property_name); } elseif (!is_object($object) && !isset($this->parameters[$property_name])) { $object = $this->parseString($object, $property_name); } elseif ((is_object($object) || is_string($object) && !empty($object) && ctype_upper($object[0])) && method_exists($object, $property_name)) { if ($property_name == 'value' && $object instanceof Reflection_Property && ($builder = $object->getAnnotation('widget')->value) && is_a($builder, Property::class, true)) { $builder = Builder::create($builder, [$object, $this->parseMethod($object, $property_name), $this]); /** @var $builder Property */ $object = $builder->buildHtml(); $format_value = false; } else { $object = $this->parseMethod($object, $property_name); } } elseif (isset($object->{$property_name})) { $object = $this->parseProperty($object, $property_name); } elseif (isset($this->parameters[$property_name])) { $object = $this->parseParameter($object, $property_name); } else { $object = $this->parseProperty($object, $property_name); } if ($format_value && $source_object instanceof Reflection_Property && $property_name == 'value') { $object = (new Reflection_Property_View($source_object))->formatValue($object); } return $object; }
/** * Parse a variable / function / include and returns its return value * * @param $property_name string can be an unique var or path.of.vars * @param $format_value boolean * @return string var value after reading value / executing specs (can be an object) */ protected function parseSingleValue($property_name, $format_value = true) { $property = $source_object = reset($this->objects); if ($property instanceof Reflection_Property_Value && $property_name == 'value') { if (($builder = $property->getAnnotation('widget')->value) && is_a($builder, Property::class, true)) { $builder = Builder::create($builder, [$property, $property->value(), $this]); /** @var $builder Property */ $builder->parameters[Feature::F_EDIT] = Feature::F_EDIT; $value = $builder->buildHtml(); if ($builder instanceof Value_Widget) { $value = (new Html_Builder_Property($property, $value))->setTemplate($this)->build(); } } else { $value = $property->getType()->isBoolean() ? $property->value() : parent::parseSingleValue($property_name, false); if (($preprop = lLastParse($property->pathAsField(), '[', 1, false)) && (!isset($this->cache[self::PARSED_ID]) || !isset($this->cache[self::PARSED_ID][$this->getFormId()]) || !isset($this->cache[self::PARSED_ID][$this->getFormId()][$preprop]))) { $this->cache[self::PARSED_ID][$this->getFormId()][$preprop] = true; if ($property instanceof Reflection_Property_Value) { $parent_object = $property->getObject(); $id = isset($parent_object) ? Dao::getObjectIdentifier($parent_object) : null; $html_builder_type = new Html_Builder_Type('id', null, $id, $preprop); $id_value = $html_builder_type->setTemplate($this)->build(); } else { $id_value = ''; } } else { $id_value = ''; } if ($property->getAnnotation('output')->value == 'string') { $property->setAnnotationLocal('var')->value = 'string'; $value = isset($value) ? strval($value) : null; $id_value = ''; } $value = $id_value . (new Html_Builder_Property($property, $value))->setTemplate($this)->build(); } } else { $value = parent::parseSingleValue($property_name); } return $value; }