/** * Escape a column value, in order to insert it into a SQL query * * @param $value mixed * @param $double_backquote boolean * @return string */ public static function escape($value, $double_backquote = false) { // no is_numeric(), as sql numeric search make numeric conversion of string fields // ie WHERE NAME = 500 instead of '500' will give you '500' and '500L', which is not correct if (is_integer($value) || is_float($value)) { $string_value = strval($value); } elseif (is_bool($value)) { $string_value = $value ? '1' : '0'; } elseif ($value === null) { $string_value = 'NULL'; } elseif (is_array($value)) { $do = false; $string_value = ''; foreach ($value as $object_value) { if ($object_value !== null) { if ($do) { $string_value .= ','; } $string_value .= str_replace(DQ, DQ . DQ, $object_value); $do = true; } } $string_value = substr($string_value, 2); } elseif ($value instanceof Date_Time) { $string_value = DQ . ($value->toISO() ?: '0000-00-00 00:00:00') . DQ; } else { $string_value = DQ . Dao::current()->escapeString($value) . DQ; } return $double_backquote ? str_replace(BS, BS . BS, $string_value) : $string_value; }
/** * Builds a Table object using a Php class definition * * This takes care of excluded properties, so buildLinkTable() should be called * before buildClassTable(). * * @param $class Reflection_Class * @param $more_field Column * @return Table */ private function buildClassTable(Reflection_Class $class, $more_field) { $table_name = Dao::current()->storeNameOf($class->name); $table = new Table($table_name); if (!in_array('id', $this->excluded_properties)) { $table->addColumn(Column::buildId()); } if ($more_field) { $table->addColumn($more_field); } if ($class->isAbstract()) { $table->addColumn(new Column('class', 'varchar(255)')); } else { foreach ($class->accessProperties() as $property) { if (!in_array($property->name, $this->excluded_properties)) { $type = $property->getType(); if (($type->isMultipleString() || !$type->isMultiple()) && !$property->isStatic()) { $table->addColumn(Column::buildProperty($property)); if ($property->getAnnotation('link')->value == Link_Annotation::OBJECT && $property->getAnnotation('store')->value != 'string') { $class_name = $property->getType()->asString(); $this->dependencies_context[$class_name] = $class_name; $table->addForeignKey(Foreign_Key::buildProperty($table_name, $property)); $table->addIndex(Index::buildLink($property->getAnnotation('storage')->value)); } } } } } return $table; }
/** * Default run method for default 'write-typed' controller * * Save data from the posted form into the first parameter object using standard method. * Create a new instance of this object if no identifier was given. * * @param $parameters Parameters * @param $form array * @param $files array * @param $class_name string * @return string * @throws Exception */ public function run(Parameters $parameters, $form, $files, $class_name) { $object = $parameters->getMainObject($class_name); Dao::begin(); try { $builder = new Post_Files(); $form = $builder->appendToForm($form, $files); $builder = new Object_Builder_Array(); $builder->null_if_empty_sub_objects = true; $builder->build($form, $object); $write_objects = []; foreach ($builder->getBuiltObjects() as $write_object) { if ($write_object == $object || Dao::getObjectIdentifier($write_object)) { $write_objects[] = $write_object; } } $write_error = false; foreach ($write_objects as $write_object) { if (!Dao::write($write_object)) { $write_error = true; break; } } $write_error ? Dao::rollback() : Dao::commit(); } catch (Exception $exception) { Dao::rollback(); throw $exception; } $parameters = $this->getViewParameters($parameters, $class_name, $write_error); return View::run($parameters, $form, $files, $class_name, Feature::F_WRITE); }
/** * 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; }
public function testWriteAnnotations() { $tests = new Tests(); $tests->data = 'test'; Dao::write($tests, [Dao::only(['data'])]); Dao::delete($tests); $this->assume(__METHOD__, $tests->data, 'test+locbefore(data)+disbefore(data)+locafter(data)+disafter(data)'); }
/** * @param Parameters $parameters * @return array */ protected function getViewParameters(Parameters $parameters) { $article = $parameters->getMainObject(Article::class); $articles = Dao::readAll(Article::class); $parameters = $parameters->getObjects(); $parameters = array_merge($parameters, ['articles' => $articles, 'uri' => $this->imageUri() . 'images/', 'general_buttons' => $this->getGeneralButtons($article, $parameters)]); return $parameters; }
/** * Stop logging : write end date-time and duration */ public function stop() { $this->antiloop--; if (!$this->antiloop) { $this->log_entry->stop(); Dao::write($this->log_entry); } }
/** * @return string */ function table() { if (!isset($this->table)) { $master_table = Dao::storeNameOf($this->property->class); $foreign_table = Dao::storeNameOf($this->property->getType()->getElementTypeAsString()); $this->table = $master_table < $foreign_table ? $master_table . '_' . $foreign_table : $foreign_table . '_' . $master_table; } return $this->table; }
/** * @param $object object * @return string[] combo filters */ protected function getFilters($object) { $filters = ['id' => Func::notEqual(Dao::getObjectIdentifier($object))]; foreach ((new Reflection_Class(get_class($object)))->getProperties([T_EXTENDS, T_USE]) as $property) { if ($property->getAnnotation('replace_filter')->value) { $filters[$property->name] = Dao::getObjectIdentifier($object, $property->name); } } return $filters; }
/** * Search the first result of several search objects list * Try each search object. When one is found, then return the first result object * * @param $objects object[]|array[]|array * @param $class_name string * @return object */ public static function searchOne($objects, $class_name = null) { foreach ($objects as $object) { $object = Dao::searchOne($object, $class_name); if (isset($object)) { return $object; } } return null; }
/** * @param $configuration array */ public function __construct($configuration) { if (isset($configuration[self::LINKS_LIST])) { self::$list = $configuration[self::LINKS_LIST]; unset($configuration[self::LINKS_LIST]); } $class_name = $configuration[Configuration::CLASS_NAME]; unset($configuration[Configuration::CLASS_NAME]); Dao::current(new $class_name($configuration)); }
/** * Build SQL tables list, based on calculated joins for where array properties paths * * @return string */ public function build() { $tables = BQ . Dao::current()->storeNameOf($this->class_name) . BQ . SP . 't0'; foreach ($this->joins->getJoins() as $join) { if ($join) { $tables .= $join->toSql(); } } return $tables; }
/** * @param $class_name string * @param $sources Reflection_Source[] * @param $added Reflection_Source[] */ private function moreSourcesAdd($class_name, &$sources, &$added) { /** @var $dependency Dependency */ $dependency = Dao::searchOne(['class_name' => $class_name, 'dependency_name' => $class_name], Dependency::class); if (!isset($sources[$dependency->file_name])) { $source = new Reflection_Source($dependency->file_name); $sources[$dependency->file_name] = $source; $added[$dependency->file_name] = $source; } }
/** * 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 ''; }
/** * @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()); } }
/** * Get current environment name possible values * * @return mixed[] */ public function values() { $type = $this->property->getType(); if ($type->isClass()) { return Dao::readAll($this->property->getType()->asString(), [Dao::sort()]); } elseif ($values = $this->property->getListAnnotation('values')->values()) { return array_combine($values, $values); } else { trigger_error("Unable to get {$this->property->name} environment values from type " . $type->asString(), E_USER_ERROR); return null; } }
/** * 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 $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(); } }
/** * Gets sql elements for a mapping between two objects * * @example * list($table, $field1, $field2, $id1, $id2) = Sql_Map_Builder::sqlElementsOf( (...) ); * * @param $object object the source object * @param $property Reflection_Property the property of the source object used for the mapping * @param $foreign_object object the mapped object * @return array */ public static function sqlElementsOf($object, $property, $foreign_object) { // build table and fields $sql_link = new Link_Table($property); $table = $sql_link->table(); $field1 = $sql_link->masterColumn(); $field2 = $sql_link->foreignColumn(); // build values $id1 = Dao::getObjectIdentifier($object, 'id'); $id2 = Dao::getObjectIdentifier($foreign_object, 'id'); // return elements return [$table, $field1, $field2, $id1, $id2]; }
/** * Set identifier unique */ public function uniqueIdentifier() { if (isset($this->identifier)) { /** @var $search Identifier */ $search = Search_Object::create(Identifier::class); $search->name = $this->identifier->name; if ($find = Dao::searchOne($search)) { Dao::replace($this->identifier, $find, false); } else { Dao::disconnect($this->identifier); } } }
/** * Builds a Foreign_Key for a column name that links to a given class name * * @param $table_name string the table name * @param $column_name string the column name linking to the foreign key (with or without 'id_') * @param $class_name string the foreign class name * @param $constraint string CASCADE, NO ACTION, RESTRICT, SET NULL * @return Foreign_Key */ public static function buildLink($table_name, $column_name, $class_name, $constraint = 'CASCADE') { if (substr($column_name, 0, 3) !== 'id_') { $column_name = 'id_' . $column_name; } $foreign_key = new Foreign_Key(); $foreign_key->Constraint = substr($table_name . DOT . $column_name, 0, 64); $foreign_key->Fields = $column_name; $foreign_key->On_delete = $constraint; $foreign_key->On_update = $constraint; $foreign_key->Reference_fields = 'id'; $foreign_key->Reference_table = Dao::storeNameOf($class_name); return $foreign_key; }
/** * Remove an object from an objects array * * @param $element object|object[] */ public function remove($element) { if (is_array($element)) { foreach ($element as $elem) { $key = Dao::getObjectIdentifier($elem); if (isset($this->objects[$key]) || array_key_exists($key, $this->objects)) { unset($this->objects[$key]); } } } else { $key = Dao::getObjectIdentifier($element); if (isset($this->objects[$key]) || array_key_exists($key, $this->objects)) { unset($this->objects[$key]); } } }
/** * @param $parameters Parameters * @param $form array * @param $files array * @param $class_name string * @return mixed */ public function run(Parameters $parameters, $form, $files, $class_name) { $replaced = $parameters->getMainObject(); $objects = $parameters->getObjects(); if ($id_replace_with = $parameters->getRawParameter('id_replace_with')) { $objects['replace_with'] = $replacement = Dao::read($id_replace_with, $class_name); Dao::begin(); if ((new Delete_And_Replace())->deleteAndReplace($replaced, $replacement)) { Dao::commit(); $objects['done'] = true; } else { Dao::rollback(); $objects['error'] = true; } } return View::run($objects, $form, $files, $class_name, 'deleteAndReplace'); }
/** * @param $parameters Parameters * @param $form array * @param $files array * @param $class_name string * @return mixed */ public function run(Parameters $parameters, $form, $files, $class_name) { $parameters = $parameters->getObjects(); Dao::begin(); $deleted = 0; foreach ($parameters as $object) { if (is_object($object)) { if (!Dao::delete($object)) { $deleted = 0; break; } $deleted++; } } Dao::commit(); $parameters['deleted'] = $deleted ? true : false; return View::run($parameters, $form, $files, $class_name, Feature::F_DELETE); }
/** * Returns the Dao function as SQL * * @param $builder Builder\Where the sql query builder * @param $property_path string the property path * @param $prefix string * @return string */ public function toSql(Builder\Where $builder, $property_path, $prefix = '') { $joins = $builder->getJoins(); // sub-query $class_name = $joins->getStartingClassName(); $properties = $this->properties + [$property_path => Func::max()]; $sub_builder = new Builder\Select($class_name, $properties, null, $builder->getSqlLink(), [Dao::groupBy($this->properties)]); // join $join = new Subquery($sub_builder); $joins->addJoin($join); // where $where = ''; foreach (array_merge($this->properties, [$property_path]) as $property) { $where .= ' AND ' . $join->foreign_alias . DOT . BQ . rLastParse($property, DOT, 1, true) . BQ . ' = ' . $builder->buildColumn($property, $prefix); } $join->where = substr($where, 5); return null; }
/** * 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; }