/** * Returns the Codes that match a string * - first get all codes matching the string as Code::$code * - If none found, get all codes matching the string as Code::$name * * @param $value * @return static[] */ public static function fromString($value) { $values = Dao::search(['code' => $value], static::class); if (!$values) { $values = Dao::search(['name' => $value], static::class); } return $values; }
/** * 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 $object Framework\Logger */ public function onLoggerStop(Framework\Logger $object) { if ($this->log_flag) { Dao::begin(); foreach (Dao::search(['log' => Func::isNull()], Compiler_Log::class) as $logger) { /** @var $logger Compiler_Log */ $logger->log = $object->log_entry; Dao::write($logger, [Dao::only(['log'])]); } $this->log_flag = false; Dao::commit(); } }
/** * To use this : * - Create your own writeSubClassNames() method * - Your method has no parameters * - Your method returns nothing * - Call return writeSub('sub_class_names', 'super_class_name') using your two properties names * * @param $sub string sub property name ie 'sub_class_names' * @param $super string super property name ie 'super_class_name' */ private function writeSub($sub, $super) { $written = []; // update $super_property into new $sub_properties foreach ($this->{$sub} as $sub) { if (!Dao::is($this, $sub->{$super})) { $sub->{$super} = $this; Dao::write($sub, [Dao::only($super)]); } $written[Dao::getObjectIdentifier($sub)] = true; } // empty $super_property from removed $sub_properties $subs = Dao::search([$super => $this], Link_Class::linkedClassNameOf($this)); foreach ($subs as $sub) { if (!isset($written[Dao::getObjectIdentifier($sub)])) { $sub->{$super} = null; Dao::write($sub, [Dao::only($super)]); } } }
/** * 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; }
/** * @param $class_name string The base class name * @param $interfaces_traits string[] The interfaces and traits names list * @param $get_source boolean if true, get built [$name, $source] instead of $name * @return string|string[] the full name of the built class */ public static function build($class_name, $interfaces_traits = [], $get_source = false) { $key = join(DOT, $interfaces_traits); if (isset(self::$builds[$class_name][$key])) { return self::$builds[$class_name][$key]; } else { $interfaces = []; $traits = []; foreach ($interfaces_traits as $interface_trait) { $class = Reflection_Class::of($interface_trait); if ($class->isInterface()) { $interfaces[$interface_trait] = $interface_trait; } elseif ($class->isTrait()) { foreach ($class->getListAnnotation('implements')->values() as $implements) { $interfaces[$implements] = $implements; } $level = 0; foreach ($class->getListAnnotation('extends')->values() as $extends) { if (Dao::search(['class_name' => $extends, 'declaration' => Dependency::T_TRAIT_DECLARATION], Dependency::class)) { foreach ($traits as $trait_level => $trait_names) { if (isset($trait_names[$extends])) { $level = max($level, $trait_level + 1); } } } } $traits[$level][$interface_trait] = $interface_trait; } else { trigger_error('Unknown interface/trait ' . DQ . $interface_trait . DQ . ' while building ' . $class_name, E_USER_ERROR); } } $built_class = self::buildClass($class_name, $interfaces, $traits, $get_source); if (!$get_source) { self::$builds[$class_name][$key] = $built_class; } return $built_class; } }
/** * @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; }
/** * @param $last_time integer compile only files modified since this time */ public function compile($last_time = 0) { set_time_limit(900); clearstatcache(); $cache_dir = $this->getCacheDir(); // create data set for dependencies, check for dependencies for deleted files Dao::createStorage(Dependency::class); Dao::begin(); if (isset($_GET['Z'])) { $link = Dao::current(); if ($link instanceof Link) { $link->query('TRUNCATE TABLE `dependencies`'); } } foreach (Dao::select(Dependency::class, ['file_name' => Func::distinct()]) as $file_dependency) { /** @var $file_dependency List_Row */ $file_name = $file_dependency->getValue('file_name'); if (!file_exists($file_name)) { foreach (Dao::search(['file_name' => $file_name], Dependency::class) as $dependency) { /** @var $dependency Dependency */ Dao::delete($dependency); foreach (Dao::search(['dependency_name' => $dependency->class_name], Dependency::class) as $sub_dependency) { /** @var $sub_dependency Dependency */ Dao::delete($sub_dependency); } } } } Dao::commit(); $this->sources = array_merge($this->more_sources, $this->getFilesToCompile($last_time)); $first_group = true; foreach ($this->compilers as $compilers) { /** @var $compilers ICompiler[] */ $saved_sources = $this->sources; while ($this->sources) { // get source and update dependencies foreach ($this->sources as $source) { /** @var Reflection_Source $source inspector bug */ /** @noinspection PhpParamsInspection inspector bug (a Dependency is an object) */ (new Set())->replace($source->getDependencies(true), Dependency::class, ['file_name' => $source->file_name]); } do { $added = []; // ask each compiler for adding of compiled files, until they have nothing to add foreach ($compilers as $compiler) { if ($compiler instanceof Needs_Main) { $compiler->setMainController($this->main_controller); } $added = array_merge($added, $compiler->moreSourcesToCompile($this->sources)); } foreach ($added as $source) { /** @var Reflection_Source $source inspector bug */ /** @noinspection PhpParamsInspection inspector bug (a Dependency is an object) */ (new Set())->replace($source->getDependencies(true), Dependency::class, ['file_name' => $source->file_name]); $this->sources[$source->file_name] = $source; } if (count($compilers) == 1) { $added = []; } } while ($added); $saved_sources = array_merge($saved_sources, $this->sources); // fill in sources cache $sources_count = count($this->sources); foreach ($this->sources as $source) { foreach (array_keys($source->getClasses()) as $class_name) { $this->sources_cache[$class_name] = $source; } if ($sources_count > self::MAX_OPENED_SOURCES) { $source->free(self::SOURCES_FREE); } } // compile sources foreach ($this->sources as $source) { $this->compileSource($source, $compilers, $cache_dir, $first_group, $sources_count); } $this->sources = $this->more_sources; $this->more_sources = []; foreach ($this->sources as $source) { if (!isset($saved_sources[$source->file_name])) { $saved_sources[$source->file_name] = $source; } } } $this->sources = $saved_sources; $first_group = false; } $this->sources = null; }
/** * Gets custom settings list * * @return Custom_Settings[] key is the name of the setting, value is '' or 'selected' */ public function getCustomSettings() { $list = []; $search['code'] = $this->class_name . DOT . static::customId() . '.%'; foreach (Dao::search($search, Setting::class) as $setting) { /** @var $setting Setting */ /** @var $settings Custom_Settings */ $settings = $setting->value; $list[$settings->name] = $settings->name == $this->name ? 'selected' : ''; } ksort($list); return $list; }
/** * Login to current environment using login and password * * Returns logged user if success * To set logger user as current for environment, you must call authenticate() * * @param $login string * @param $password string * @return User|null */ public static function login($login, $password) { $search = Search_Object::create(User::class); $search->login = $login; $password = (new Password($password, (new Reflection_Property(get_class($search), 'password'))->getAnnotation('password')->value))->encrypted(); foreach (Dao::search($search) as $user) { if ($user->password === $password) { return $user; } } return null; }
/** * @param $search array|object * @param $row array * @param $class Import_Class * @param $class_properties_column integer[] * @return object */ public function importSearchObject($search, $row, Import_Class $class, $class_properties_column) { if ($this->simulation && isset($search)) { $this->simulateSearch($class, $search, $class->class_name); } $found = isset($search) ? Dao::search($search, $class->class_name) : null; if (!isset($found)) { $object = null; } elseif (count($found) == 1) { $object = $this->updateExistingObject(reset($found), $row, $class, $class_properties_column); } elseif (!count($found)) { if ($class->object_not_found_behaviour === 'create_new_value') { $object = $this->writeNewObject($row, $class, $class_properties_column); } elseif ($class->object_not_found_behaviour === 'tell_it_and_stop_import') { trigger_error('Not found ' . $class->class_name . SP . print_r($search, true), E_USER_ERROR); $object = null; } else { $object = null; } } else { echo '<pre class="error">SEARCH = ' . print_r($search, true) . '</pre>'; echo '<pre class="error">FOUND = ' . print_r($found, true) . '</pre>'; trigger_error('Multiple ' . Namespaces::shortClassName($class->class_name) . ' found', E_USER_ERROR); $object = null; } return $object; }
/** * * @param $object object * @param $read_properties string[] properties names * @return object */ public function readObject($object, $read_properties) { $objects = Dao::search($read_properties, get_class($object)); if (count($objects) > 1) { trigger_error('Unique object not found' . SP . get_class($object) . SP . print_r($read_properties, true), E_USER_ERROR); } elseif ($objects) { $new_object = reset($objects); foreach ((new Reflection_Class(get_class($object)))->accessProperties() as $property) { $property_name = $property->name; if (isset($object->{$property_name}) && !isset($read_properties[$property->name])) { $property->setValue($new_object, $property->getValue($object)); } } $object = $new_object; } return $object; }
/** * Translates a text using current language and an optionnal given context * * @param $text string * @param $context string * @return string */ public function translate($text, $context = '') { if (!trim($text) || is_numeric($text)) { return $text; } elseif (strpos($text, DOT) !== false) { $translation = []; foreach (explode(DOT, $text) as $sentence) { $translation[] = $this->translate($sentence, $context); } return join(DOT, $translation); } elseif (!isset($this->cache[$text]) || !isset($this->cache[$text][$context])) { if (substr($text, -1) === AT) { $str_uri = true; $text = substr($text, 0, -1); } else { $str_uri = false; } $search = new Translation($text, $this->language, $context); $translations = Dao::search($search); foreach ($translations as $translation) { if ($translation->text === $text) { break; } } while ($search->context && !isset($translation)) { $i = strrpos($search->context, DOT); $search->context = $i ? substr($search->context, 0, $i) : ''; $translations = Dao::search($search); foreach ($translations as $translation) { if ($translation->text === $text) { break; } } } if (!isset($translation) && strpos($text, ', ')) { $translation_parts = []; foreach (explode(', ', $text) as $text_part) { $translation_parts[] = $this->translate($text_part, $context); } $translation = new Translation($text, $this->language, $context, join(', ', $translation_parts)); } if (!isset($translation)) { $translation = $search; $translation->text = str_replace('_', SP, strtolower($translation->text)); $translation->translation = ''; Dao::write($translation); } $translation = $translation ? $translation->translation : $text; if ($str_uri) { $text .= AT; $translation = strUri($translation); } $this->cache[$text][$context] = $translation; } $translation = $this->cache[$text][$context]; return empty($translation) ? $text : (strIsCapitals($text[0]) ? ucfirsta($translation) : $translation); }