/** * @param $file_name string */ public function runFile($file_name) { $class_name = Names::pathToClass(substr($file_name, 0, -4)); if (is_subclass_of($class_name, Test::class)) { $this->runClass($class_name); } }
/** * @param $object object|string object or class name * @param $parameters string[] parameters * @return Button[] */ protected function getGeneralButtons($object, $parameters) { $buttons = parent::getGeneralButtons($object, $parameters); $close_link = View::link(Names::classToSet(get_class($object))); list($close_link) = $this->prepareThen($object, $parameters, $close_link); return array_merge($buttons, [Feature::F_CLOSE => new Button('Close', $close_link, Feature::F_CLOSE, [new Color('close'), Target::MAIN])]); }
/** * @return string */ function masterColumn() { if (!isset($this->master_column)) { $this->master_column = 'id_' . Names::setToSingle($this->property->getAnnotation('foreign')->value); } return $this->master_column; }
/** * @param $value string * @param $class_property Reflection * @param $annotation_name string */ public function __construct($value, Reflection $class_property, $annotation_name) { if (!empty($value)) { $class = $class_property instanceof Reflection_Property ? $class_property->getFinalClass() : $class_property; if ($pos = strpos($value, '::')) { $type_annotation = new Type_Annotation(substr($value, 0, $pos), $class); if ($type_annotation->value == 'composite') { /** @var $composite_property Reflection_Property */ $composite_property = call_user_func([$class->getName(), 'getCompositeProperty']); $type_annotation->value = $composite_property->getType()->asString(); } // if the property is declared into the final class : try using the class namespace name if (!$class_property instanceof Reflection_Property || $class_property->getDeclaringTraitName() === $class_property->getFinalClassName()) { $type_annotation->applyNamespace($class->getNamespaceName()); } if (!@class_exists($type_annotation->value)) { $this->searchIntoDeclaringTrait($class_property, $type_annotation, $value, $pos); } if (!@class_exists($type_annotation->value)) { $this->searchIntoFinalClass($class_property, $type_annotation, $value, $pos); } if (!@class_exists($type_annotation->value)) { trigger_error(sprintf('Not found full class name for Method_Annotation %1 value %2 class %3 property %4', $annotation_name, $value, $class->getName(), $class_property->getName()), E_USER_ERROR); } $value = $type_annotation->value . substr($value, $pos); $this->static = true; } else { if ($value === true) { $value = Names::propertyToMethod($annotation_name); } $value = $class->getName() . '::' . $value; } } parent::__construct($value); }
/** * @param $view_name string the view name is the associated data class name * @param $feature_names string[] feature and inherited feature which view will be searched * @param $template string if a specific template is set, the view named with it will be * searched into the view / feature namespace first * @return callable */ private static function getView($view_name, $feature_names, $template = null) { $view_engine_name = get_class(View::current()); $view_engine_name = Namespaces::shortClassName(Namespaces::of($view_engine_name)); if (isset($template)) { foreach ([$view_engine_name . '_View', 'View'] as $suffix) { foreach ($feature_names as $feature_name) { list($class, $method) = Getter::get($view_name, $feature_name, Names::methodToClass($template) . '_' . $suffix, 'php'); if (isset($class)) { break 2; } } } } if (!isset($class)) { foreach ([$view_engine_name . '_View', 'View'] as $suffix) { foreach ($feature_names as $feature_name) { list($class, $method) = Getter::get($view_name, $feature_name, $suffix, 'php'); if (isset($class)) { break 2; } } } } if (!isset($class)) { list($class, $method) = [__CLASS__ . BS . $view_engine_name . BS . 'Default_View', 'run']; } /** @noinspection PhpUndefinedVariableInspection if $class is set, then $method is set too */ return [$class, $method]; }
/** * 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 $class_name string * @param $property_path string[] * @param $object_not_found_behaviour string create_new_value, do_nothing, tell_it_and_stop_import */ public function __construct($class_name = null, $property_path = null, $object_not_found_behaviour = null) { if (isset($class_name)) { $this->class_name = $class_name; $this->name = Names::classToDisplay($class_name); } if (isset($object_not_found_behaviour)) { $this->object_not_found_behaviour = $object_not_found_behaviour; } if (isset($property_path)) { $this->property_path = $property_path; } }
/** * @param $value string * @param $caption string */ public function __construct($value = null, $caption = null) { parent::__construct('option', true); if (isset($value)) { if (!isset($caption)) { $this->setContent(Names::propertyToDisplay($value)); } $this->setAttribute('value', $value); } if (isset($caption)) { if (!isset($value)) { $this->setAttribute('value', $value); } $this->setContent($caption); } }
/** * @param $parameters Parameters * @param $form array * @param $files array * @return mixed */ public function run(Parameters $parameters, $form, $files) { $parameters->set(Parameter::CONTAINER, 'inside_tree'); $search = $parameters->getRawParameter('search'); if (empty($search)) { return parent::run($parameters, $form, $files); } $search = strtolower(str_replace([DOT, '*', '?'], [BS . DOT, '.*', '.?'], strSimplify($search, '.*? ' . BS))); $class_name = Names::setToClass($parameters->shift()); $properties = $this->searchProperties($class_name, $search); $top_property = new Property(); $top_property->class = $class_name; $objects = $parameters->getObjects(); array_unshift($objects, $top_property); $objects['class_name'] = $class_name; $objects['properties'] = $properties; $objects['display_full_path'] = true; return View::run($objects, $form, $files, Property::class, 'select'); }
/** * 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); } } }
/** * Create a table in database, which has no associated class, using fields names * * @param $mysqli mysqli * @param $table_name string * @param $column_names string[] * @return boolean * @todo mysqli context should contain sql builder (ie Select) in order to know if this was * an implicit link table. If then : only one unique index should be built */ private function createImplicitTable(mysqli $mysqli, $table_name, $column_names) { $only_ids = true; $table = new Table($table_name); $ids_index = new Index(); $ids_index->setType(Index::UNIQUE); $indexes = []; foreach ($column_names as $column_name) { $table->addColumn($column_name === 'id' ? Column::buildId() : Column::buildLink($column_name)); if (substr($column_name, 0, 3) === 'id_') { if ($mysqli instanceof Contextual_Mysqli && is_array($mysqli->context)) { $ids_index->addKey($column_name); $index = Index::buildLink($column_name); foreach ($mysqli->context as $context_class) { $id_context_property = 'id_' . Names::classToProperty(Names::setToSingle(Dao::storeNameOf($context_class))); $id_context_property_2 = 'id_' . Names::classToProperty(Names::setToSingle(Namespaces::shortClassName($context_class))); if (in_array($column_name, [$id_context_property, $id_context_property_2])) { $table->addForeignKey(Foreign_Key::buildLink($table_name, $column_name, $context_class)); break; } } $indexes[] = $index; } } else { $only_ids = false; } } if ($only_ids) { $table->addIndex($ids_index); } else { foreach ($indexes as $index) { $table->addIndex($index); } } $mysqli->query((new Create_Table($table))->build()); return true; }
/** * Gets a Reflection_Source knowing its class _name. * Uses sources cache, or router's getClassFilename() and fill-in cache. * * @param $class_name string * @return Reflection_Source */ public function getClassFilename($class_name) { if (isset($this->sources_cache[$class_name])) { return $this->sources_cache[$class_name]; } else { /** @var $router Router */ $router = Session::current()->plugins->get(Router::class); if (Builder::isBuilt($class_name)) { $file_name = $this->getCacheDir() . SL . str_replace(SL, '-', Names::classToPath($class_name)); } else { $file_name = $router->getClassFilename($class_name); } $source = new Reflection_Source($file_name, $this, $class_name); foreach (array_keys($source->getClasses()) as $class_name) { $this->sources_cache[$class_name] = $source; if (count($this->sources_cache) > self::MAX_OPENED_SOURCES) { $source->free(self::SOURCES_FREE); } } return $this->sources_cache[$class_name]; } }
/** * Defines multiple annotations classes * A very little bit faster than multiple calls to setAnnotation() * * @param $context string Parser::T_CLASS, Parser::T_METHOD, Parser::T_VARIABLE * @param $annotations_classes string[] key is the annotation name, value is the annotation class */ public function setAnnotations($context, $annotations_classes) { // instantiates Parser, in order to call its __destruct() method at the script end if (!isset($GLOBALS['parser'])) { $GLOBALS['parser'] = new Parser(); } // add annotation $namespace = 'SAF\\Framework\\Reflection\\Annotation' . BS . $context; foreach ($annotations_classes as $annotation_name => $annotation_class) { $class_name = Names::propertyToClass($annotation_name) . '_Annotation'; Parser::$additional_annotations[$namespace . BS . $class_name] = $annotation_class; } }
/** * @param $configuration array */ public function __construct($configuration = []) { foreach ($configuration as $block_key => $items) { if ($block_key == self::TITLE) { foreach ($items as $item) { if (substr($item, 0, 1) == SL) { $this->title_link = $item; } elseif (substr($item, 0, 1) == '#') { $this->title_link_target = $item; } else { $this->title = $item; } } } else { $block = new Block(); if (substr($block_key, 0, 1) == SL) { $block->title_link = $block_key; } else { $block->title = $block_key; } foreach ($items as $item_key => $item) { if ($item_key == self::MODULE) { $block->module = $item; } elseif ($item_key == self::TITLE) { $block->title = $item; } elseif ($item_key == self::LINK) { $block->title_link = $item; } elseif ($item_key == self::TARGET) { $block->title_link_target = $item; } else { $menu_item = new Item(); $menu_item->link = $item_key; if (is_array($item)) { foreach ($item as $property_key => $property) { if (is_numeric($property_key)) { if (substr($property, 0, 1) == SL) { $menu_item->link = $property; } elseif (substr($property, 0, 1) == '#') { $menu_item->link_target = $property; } else { $menu_item->caption = $property; } } } } else { $menu_item->caption = $item; } $block->items[] = $menu_item; } } if (!isset($block->module)) { $block->module = Names::displayToProperty($block_key); } $this->blocks[] = $block; } } }
/** * Gets the store name for records typed as $class_name * * @param $class_name string * @return string */ public function storeNameOf($class_name) { return strtolower(Namespaces::shortClassName(Names::classToSet($class_name))); }
/** * @param $controller_name string the name of the data class which controller we are looking for * @param $feature_name string the feature which controller we are looking for * @param $sub_feature string if set, the sub feature controller is searched into the feature * controller namespace * @return callable */ private function getController($controller_name, $feature_name, $sub_feature = null) { if (isset($sub_feature)) { list($class, $method) = Getter::get($controller_name, $feature_name, Names::methodToClass($sub_feature) . '_Controller', 'php'); } if (!isset($class)) { list($class, $method) = Getter::get($controller_name, $feature_name, 'Controller', 'php'); } if (!isset($class)) { list($class, $method) = [Default_Controller::class, 'run']; } /** @noinspection PhpUndefinedVariableInspection if $class is set, then $method is set too */ return [$class, $method]; }
public function testDeleteControllers() { $controller_uri = new Uri('/SAF/Framework/Widget/Tab/remove/' . Names::classToSet(Order::class) . SL . Feature::F_LIST . '/date/number', [Parameter::AS_WIDGET => true, '_' => 2]); $this->assume(__METHOD__, ['controller_name' => $controller_uri->controller_name, 'feature_name' => $controller_uri->feature_name, 'parameters' => $controller_uri->parameters->getRawParameters()], ['controller_name' => Tab::class, 'feature_name' => Feature::F_REMOVE, 'parameters' => (new Parameters())->addValue(Names::classToSet(Order::class))->addValue(Feature::F_LIST)->addValue('date')->addValue('number')->set(Parameter::AS_WIDGET, true)->set('_', 2)->getRawParameters()]); }
/** * Gets replacement class name for a parent class name or a list of traits to implement * * @param $class_name string can be short or full class name * @return string */ private function replacementClassName($class_name) { if ($this->enabled) { $result = isset($this->replacements[$class_name]) ? $this->replacements[$class_name] : $class_name; if (is_array($result)) { if ($this->build) { $this->compositions[$class_name] = $result; $built_class_name = Class_Builder::builtClassName($class_name); if (file_exists(Application::current()->getCacheDir() . '/compiled/' . str_replace('/', '-', Names::classToPath($built_class_name)))) { $result = $built_class_name; } else { $result = Class_Builder::build($class_name, $result); } $this->replacements[$class_name] = $result; } else { $result = $class_name; } } elseif (!$this->build && self::isBuilt($result)) { $result = $class_name; } } else { $result = $class_name; } return $class_name != $result && !self::isBuilt($result) ? $this->replacementClassName($result) : $result; }
/** * Gets annotation name (the displayable root of the annotation class name, when set) * * @return string */ public function getAnnotationName() { return Names::classToDisplay(lLastParse(Namespaces::shortClassName(get_class($this)), '_Annotation')); }
/** * @param $multiline boolean keep this value empty, it is not used because the @multiline * annotation is automatically used * @param $values string[] keep this value empty, it is not used because the @values annotation * is automatically used * @return Element */ protected function buildString($multiline = false, $values = null) { $values_captions = []; $values = $this->property->getListAnnotation('values')->values(); foreach ($values as $value) { $values_captions[$value] = Names::propertyToDisplay($value); } if ($values_captions && !in_array($this->value, $values_captions)) { $values_captions[$this->value] = $this->value; } $element = parent::buildString($this->property->getAnnotation('multiline')->value, $values_captions); if ($this->property->getAnnotation('mandatory')->value) { $element->setAttribute('required', true); } if ($this->property->getAnnotation('password')->value) { $element->setAttribute('type', 'password'); $element->setAttribute('value', strlen($this->value) ? Password::UNCHANGED : ''); } return $element; }
/** * Gets annotation class name (including namespace) for a given annotation name * * @param $reflection_object Has_Doc_Comment * @param $annotation_name string * @return string */ private static function getAnnotationClassName(Has_Doc_Comment $reflection_object, $annotation_name) { $reflection_class = get_class($reflection_object); $pos = strrpos($reflection_class, '_'); $reflection_class = substr($reflection_class, $pos + 1); if ($reflection_class == 'Class') { $reflection_class .= '_'; } elseif ($reflection_class == 'Value') { $reflection_class = 'Property'; } $annotation_class = __NAMESPACE__ . BS . $reflection_class . BS . Names::propertyToClass($annotation_name) . '_Annotation'; /** @noinspection PhpUsageOfSilenceOperatorInspection */ if (!@class_exists($annotation_class)) { if (!isset(self::$default_annotations)) { self::initDefaultAnnotations(); } if (isset(self::$default_annotations[$annotation_class])) { $annotation_class = self::$default_annotations[$annotation_class]; } else { $annotation_class = Annotation::class; } } return $annotation_class; }
/** * @param $list_settings Data_List_Settings * @return string */ public function getSearchSummary(Data_List_Settings $list_settings) { if ($list_settings->search) { if (Locale::current()) { $t = '|'; $i = '¦'; } else { $t = $i = ''; } $class_display = Names::classToDisplay((new Reflection_Class($list_settings->class_name))->getAnnotation('set')->value); $summary = $t . $i . ucfirst($class_display) . $i . ' filtered by' . $t; $first = true; foreach ($list_settings->search as $property_path => $value) { if ($first) { $first = false; } else { $summary .= ','; } $summary .= SP . $t . $property_path . $t . ' = ' . DQ . $value . DQ; } return $summary; } return null; }
/** * @param $property Reflection_Property * @return string[] Possibles properties names */ private function defaultMap(Reflection_Property $property) { $possibles = []; $foreign_class = $this->getForeignClass($property); foreach ($foreign_class->getProperties([T_EXTENDS, T_USE]) as $foreign_property) { $foreign_type = $foreign_property->getType(); if ($foreign_type->isClass() && $foreign_type->isMultiple() && is_a($property->getFinalClassName(), $foreign_type->getElementTypeAsString(), true) && $foreign_property->getAnnotation('link')->value == Link_Annotation::MAP && ($foreign_property->getDeclaringClassName() != $property->getDeclaringClassName() || $foreign_property->getName() != $property->getName())) { $possibles[$foreign_property->getName()] = $foreign_property; } } $possibles = Replaces_Annotations::removeReplacedProperties($possibles); if (count($possibles) != 1) { $this->value = Names::classToProperty(Names::setToClass($property->getDeclaringClass()->getAnnotation('set')->value)); } return array_keys($possibles); }
/** * @param $class_name string * @param $property_path string * @param $use_reverse_translation boolean if true, will try reverse translation of property names * @param $properties_alias string[] $property_path = string[string $property_alias] * @return string */ public static function propertyPathOf($class_name, $property_path, $use_reverse_translation = false, $properties_alias = null) { if (isset($properties_alias) && isset($properties_alias[$property_path])) { $property_path = $properties_alias[$property_path]; } elseif ($use_reverse_translation) { $property_class_name = $class_name; $property_names = []; foreach (explode(DOT, $property_path) as $property_name) { if ($asterisk = substr($property_name, -1) == '*') { $property_name = substr($property_name, 0, -1); } $property = null; $property_name = Names::displayToProperty($property_name); try { $property = new Reflection_Property($property_class_name, $property_name); } catch (ReflectionException $e) { $translated_property_name = Names::displayToProperty(Loc::rtr($property_name, $property_class_name)); try { $property = new Reflection_Property($property_class_name, $translated_property_name); $property_name = $translated_property_name; } catch (ReflectionException $e) { } } $property_names[] = $property_name . ($asterisk ? '*' : ''); if (!isset($property)) { break; } $property_class_name = $property->getType()->getElementTypeAsString(); } $property_path = join(DOT, $property_names); } return $property_path; }
/** * @return Head */ protected function buildHead() { $head = new Head(); $row = new Row(); foreach ($this->properties as $property) { if (!$property->getType()->isMultiple() || $property->getType()->getElementTypeAsString() != $property->getFinalClass()->name) { $cell = new Header_Cell(Loc::tr(Names::propertyToDisplay($property->getAnnotation('alias')->value), $this->class_name)); $row->addCell($cell); } } $head->addRow($row); return $head; }
/** * return @string */ public function getName() { return Names::displayToProperty($this->title); }
/** * Parse a special data / function and returns its return value * * @param $func_name string * @return mixed */ protected function parseFunc($func_name) { $func_name = ($p = strpos($func_name, '(')) ? Names::propertyToMethod(substr($func_name, 0, $p), 'get') . substr($func_name, $p) : Names::propertyToMethod($func_name, 'get'); return $this->htmlEntities($this->callFunc($this->functions, $func_name)); }
/** * @return string */ public function display() { return $this->display ? $this->display : Names::propertyToDisplay($this->path ? $this->path : $this->name); }
/** * Delete an object * * @param $parameters mixed[] * - first : the deleted object * - other parameters are not sent to the delete controller (only as_widget is kept) * @return mixed */ private function deleteObject($parameters) { $object = array_shift($parameters); $controller_uri = SL . Names::classToUri(get_class($object)) . SL . Dao::getObjectIdentifier($object) . SL . Feature::F_DELETE; return (new Main())->runController($controller_uri, $parameters); }
/** * Get the root URL for the application * * This includes : currently used protocol, server name and uri base * If object or class name is set, path to this object or class name is added to the URL * * @example without class name : 'https://saf.re/saf' * @example with the class name of User : '******' * @example with a User object of id = 1 : 'https://saf.re/saf/SAF/Framework/User/1' * @param $object object|string object or class name * @return string */ public static function getUrl($object = null) { return (isset($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['SERVER_NAME'] . Paths::$uri_base . (isset($object) ? SL . Names::classToUri($object) : ''); }