/** * @param $result Table */ public function afterHtmlBuilderMultipleBuild(Table $result) { if ($this->in_multiple == 'build') { $table = $result; $length = count($table->body->rows) - 1; if ($this->count->count > $length) { // vertical scrollbar $vertical_scroll_bar = new Standard_Cell(); $vertical_scroll_bar->addClass('vertical'); $vertical_scroll_bar->addClass('scrollbar'); $vertical_scroll_bar->setAttribute('rowspan', 1000000); $vertical_scroll_bar->setData('start', 0); $vertical_scroll_bar->setData('length', $length); $vertical_scroll_bar->setData('total', $this->count->count); $link = '/Html_Edit_Multiple/output/' . Namespaces::shortClassName($this->property->getDeclaringClass()) . SL . Dao::getObjectIdentifier($this->property->getObject()) . SL . $this->property->name . SL . '?move='; $up = new Anchor($link . 'up'); $up->addClass('up'); $position = new Anchor($link . 1); $position->addClass('position'); $down = new Anchor($link . 'down'); $down->addClass('down'); $vertical_scroll_bar->setContent($up . $position . $down); // add vertical scrollbar cells to multiple (collection or map) table $table->head->rows[0]->addCell(new Header_Cell(), 0); $table->body->rows[0]->addCell($vertical_scroll_bar, 0); } $this->in_multiple = ''; } }
/** * @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]; }
/** * @param $source Reflection_Source the PHP source file object * @param $compiler PHP\Compiler the main compiler * @return boolean true if compilation process did something, else false */ public function compile(Reflection_Source $source, PHP\Compiler $compiler = null) { $compiled = false; foreach ($source->getClasses() as $class) { // replace extends with the built replacement class if (!Builder::isBuilt($class->name)) { $parent_class_name = $class->getParentName(); if ($parent_class_name) { $replacement_class_name = Builder::className($parent_class_name); if ($replacement_class_name != $parent_class_name) { $class_exists = class_exists($replacement_class_name, false); if ($class_exists && is_a($replacement_class_name, $parent_class_name) || !$class_exists && Reflection_Source::of($replacement_class_name)->getClass($replacement_class_name)->isA($class->name)) { $replacement_class_name = $parent_class_name; } } if (is_array($replacement_class_name)) { trigger_error("Replacement classes should all be compiled", E_USER_ERROR); $compiler->addSource($source); } elseif ($replacement_class_name !== $parent_class_name && Builder::isBuilt($replacement_class_name)) { $extended = null; $buffer = $source->getSource(); $short_class_name = Namespaces::shortClassName($class->name); $buffer = preg_replace_callback('%(\\s+class\\s+' . $short_class_name . '\\s+extends\\s+)([\\\\\\w]+)(\\s+)%', function ($match) use(&$extended, $replacement_class_name) { $extended = $match[2]; return $match[1] . BS . $replacement_class_name . $match[3]; }, $buffer); if ($extended) { $buffer = preg_replace_callback('%(\\n\\s+\\*\\s+@link\\s+)(' . str_replace(BS, BS . BS, $extended) . ')(\\s+)%', function ($match) use($replacement_class_name) { return $match[1] . BS . $replacement_class_name . $match[3]; }, $buffer); } $source->setSource($buffer); $compiled = true; } } } } return $compiled; }
/** * 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; }
/** * @return callable */ public function getCallable() { if ($i = strpos($this->callable_string, '::')) { $class_name = substr($this->callable_string, 0, $i); switch ($class_name) { case '$this': $class_name = $this->context; break; case 'self': $class_name = get_class($this->context); break; default: $class_name = Namespaces::defaultFullClassName($class_name, get_class($this->context)); } $method_name = substr($this->callable_string, $i + 2); } else { $class_name = get_class($this->context); $method_name = $this->callable_string; if (!(new Reflection_Method($class_name, $method_name))->isStatic()) { $class_name = $this->context; } } return [$class_name, $method_name]; }
/** * Replace code before <!--BEGIN--> and after <!--END--> by the html main container's code * * @param $content string * @return string updated content */ protected function parseContainer($content) { $i = strpos($content, '<!--BEGIN-->'); if ($i !== false) { $i += 12; $j = strrpos($content, '<!--END-->', $i); $short_class = Namespaces::shortClassName(get_class(reset($this->objects))); $short_form_id = strtolower($short_class) . '_edit'; $this->form_id = $short_form_id . '_' . $this->nextFormCounter(); $action = SL . $short_class . '/write'; $content = substr($content, 0, $i) . $this->replaceSectionByForm(substr($content, $i, $j - $i), $action) . substr($content, $j); } return parent::parseContainer($content); }
/** * 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 $join Join * @param $master_path string * @param $master_property_name string * @param $foreign_path string * @return string the foreign class name * @todo use @storage to get correct master and foreign columns name */ private function addReverseJoin(Join $join, $master_path, $master_property_name, $foreign_path) { list($foreign_class_name, $foreign_property_name) = explode('->', $master_property_name); $foreign_class_name = Namespaces::defaultFullClassName($foreign_class_name, $this->classes[$master_path]); if (strpos($foreign_property_name, '=')) { list($foreign_property_name, $master_property_name) = explode('=', $foreign_property_name); $join->master_column = 'id_' . $master_property_name; } else { $join->master_column = 'id'; } $join->foreign_column = 'id_' . $foreign_property_name; $join->mode = Join::LEFT; $foreign_property = new Reflection_Property($foreign_class_name, $foreign_property_name); if ($foreign_property->getType()->isMultiple()) { $this->addLinkedJoin($join, $master_path, $foreign_path, $foreign_class_name, $foreign_property, true); } return $foreign_class_name; }
/** * @param $doc_comment string * @param $annotation_name string * @param $i integer * @param $annotation_class string * @param $reflection_object Has_Doc_Comment|Reflection * @return Annotation */ private static function parseAnnotationValue($doc_comment, $annotation_name, &$i, $annotation_class, Reflection $reflection_object) { $i += strlen($annotation_name) + 1; $next_char = $doc_comment[$i]; switch ($next_char) { case SP: case TAB: $i++; $j = strlen($doc_comment); $next_annotation = strpos($doc_comment, SP . '* @', $i); $end_doc_comment = strpos($doc_comment, SP . '*/', $i); $next_in = strpos($doc_comment, LF . self::DOC_COMMENT_IN, $i); if ($next_annotation !== false && $next_annotation < $j) { $j = $next_annotation; } if ($end_doc_comment !== false && $end_doc_comment < $j) { $j = $end_doc_comment; } if ($next_in !== false && $next_in < $j) { $j = $next_in; } if ($j === false) { trigger_error('Missing doc_comment end', E_USER_ERROR); } $value = trim(preg_replace('%\\s*\\n\\s+\\*\\s*%', '', substr($doc_comment, $i, $j - $i))); break; case CR: case LF: $value = true; break; default: $value = null; } /** @var $annotation Annotation */ $annotation = isset($value) ? new $annotation_class($value, $reflection_object, $annotation_name) : null; if (isset($annotation) && isA($annotation, Annotation_In::class)) { /** @var $annotation Annotation_In */ $j = strrpos(substr($doc_comment, 0, $i), LF . self::DOC_COMMENT_IN); if ($j === false) { $annotation->class_name = $reflection_object instanceof Reflection_Class_Component ? $reflection_object->getDeclaringClassName() : $reflection_object->getName(); } else { $j += strlen(self::DOC_COMMENT_IN) + 1; $k = strpos($doc_comment, LF, $j); $annotation->class_name = substr($doc_comment, $j, $k - $j); } } if (isset($annotation) && isA($annotation, Types_Annotation::class)) { $do = false; if (is_array($annotation->value)) { foreach ($annotation->value as $value) { if ($value && (ctype_upper($value[0]) || $value[0] == BS)) { $do = true; break; } } } else { $do = $annotation->value && ctype_upper($annotation->value[0]); } if ($do) { /** @var $annotation Types_Annotation */ $j = strrpos(substr($doc_comment, 0, $i), LF . self::DOC_COMMENT_IN); if ($j === false) { $class_name = $reflection_object instanceof Reflection_Class_Component ? $reflection_object->getDeclaringClassName() : $reflection_object->getName(); $namespace = Namespaces::of($class_name); $use = PHP\Reflection_Class::of($class_name)->getNamespaceUse(); } else { $j += strlen(self::DOC_COMMENT_IN) + 1; $k = strpos($doc_comment, LF, $j); $in_class = substr($doc_comment, $j, $k - $j); $namespace = Namespaces::of($in_class); $use = PHP\Reflection_Class::of($in_class)->getNamespaceUse(); } $annotation->applyNamespace($namespace, $use); } elseif (is_array($annotation->value)) { foreach ($annotation->value as $key => $value) { $annotation->value[$key] = Builder::className($value); } } else { if ($annotation->value[0] === BS) { $annotation->value = substr($annotation->value, 1); } $annotation->value = Builder::className($annotation->value); } } return $annotation; }
/** * @return string */ protected static function customId() { return lParse(strtolower(Namespaces::shortClassName(get_called_class())), '_settings'); }
/** * @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; }
/** * 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 $content string * @param $i integer * @param $j integer */ protected function parseUse(&$content, &$i, $j) { $class_name = substr($content, $i + 4, $j - $i - 4); $this->use[Namespaces::shortClassName($class_name)] = $class_name; $content = substr($content, 0, $i - 4) . substr($content, $j + 3); }
/** * @param $base_class string The base name for the class, ie 'SAF\Framework\User' * @param $feature_name string The name of the feature, ie 'dataList' * @param $suffix string Class suffix, ie 'Controller', 'View' * @param $extension string File extension, ie 'php', 'html' * @param $class_form boolean true to use 'Feature_Class' naming instead of 'featureClass' * @return string[] [$class, $method] */ public static function get($base_class, $feature_name, $suffix, $extension, $class_form = true) { // ie : $feature_class = 'featureName' transformed into 'Feature_Name' $feature_class = Names::methodToClass($feature_name); // $feature_what is $feature_class or $feature_name depending on $class_name $feature_what = $class_form ? $feature_class : $feature_name; $_suffix = $suffix ? '_' . $suffix : ''; $class_name = $base_class; $ext = DOT . $extension; $method = 'run'; $application_classes = Application::current()->getClassesTree(); // $classes : the controller class name and its parents // ['Vendor\Application\Module\Class_Name' => '\Module\Class_Name'] $classes = []; do { $classes[$class_name] = substr($class_name, strpos($class_name, BS, strpos($class_name, BS) + 1) + 1); if (@class_exists($class_name)) { $reflection_class = new Reflection_Class(Builder::className($class_name)); foreach ($reflection_class->getTraits() as $trait) { $classes[$trait->name] = explode(BS, $trait->name, 3)[2]; } foreach ($reflection_class->getListAnnotation('extends')->values() as $extends) { $classes[$extends] = explode(BS, $extends, 3)[2]; } } $class_name = @get_parent_class($class_name); } while ($class_name); // Looking for specific controller for each application $application_class = reset($application_classes); do { $namespace = Namespaces::of($application_class); // for the controller class and its parents foreach ($classes as $short_class_name) { $class_name = $namespace . BS . $short_class_name; $path = strtolower(str_replace(BS, SL, $class_name)); if (isset($GLOBALS['D'])) { echo '- try A1 ' . $path . SL . $feature_what . $_suffix . $ext . BR; } if (file_exists($path . SL . $feature_what . $_suffix . $ext)) { $class = $class_name . BS . $feature_what . $_suffix; break 2; } if (isset($GLOBALS['D'])) { echo '- try A2 ' . $path . SL . strtolower($feature_class) . SL . $feature_what . $_suffix . $ext . BR; } if (file_exists($path . SL . strtolower($feature_class) . SL . $feature_what . $_suffix . $ext)) { $class = $class_name . BS . $feature_class . BS . $feature_what . $_suffix; break 2; } if (isset($GLOBALS['D']) && $suffix) { echo '- try A3 ' . $path . SL . strtolower($feature_class) . SL . $suffix . $ext . BR; } if ($suffix && file_exists($path . SL . strtolower($feature_class) . SL . $suffix . $ext)) { $class = $class_name . BS . $feature_class . BS . $suffix; break 2; } if (isset($GLOBALS['D'])) { echo '- try A4 ' . Names::classToPath($class_name) . '_' . $feature_what . $_suffix . $ext . BR; } if (file_exists(Names::classToPath($class_name) . '_' . $feature_what . $_suffix . $ext)) { $class = $class_name . '_' . $feature_what . $_suffix; break 2; } if (isset($GLOBALS['D']) && $suffix) { echo '- try A5 ' . $path . SL . $suffix . $ext . BR; } if ($suffix && file_exists($path . SL . $suffix . $ext) && method_exists($class_name . BS . $suffix, 'run' . ucfirst($feature_name))) { $class = $class_name . BS . $suffix; $method = 'run' . ucfirst($feature_name); break 2; } } // next application is the parent one $application_class = next($application_classes); } while ($application_class); // Looking for default controller for each application if (empty($class)) { reset($application_classes); do { // looking for default controller $path = strtolower(str_replace(BS, SL, $namespace)); if (isset($GLOBALS['D']) && $suffix) { echo '- try B1 ' . $path . SL . strtolower($feature_class) . SL . $suffix . $ext . BR; } if ($suffix && file_exists($path . SL . strtolower($feature_class) . SL . $suffix . $ext)) { $class = $namespace . BS . $feature_class . BS . $suffix; break; } if (isset($GLOBALS['D'])) { echo '- try B2 ' . $path . SL . strtolower($feature_class) . SL . $feature_what . $_suffix . $ext . BR; } if (file_exists($path . SL . strtolower($feature_class) . SL . $feature_what . $_suffix . $ext)) { $class = $namespace . BS . $feature_class . BS . $feature_what . $_suffix; break; } if (isset($GLOBALS['D']) && $suffix) { echo '- try B3 ' . $path . SL . 'widget' . SL . strtolower($feature_class) . SL . $suffix . $ext . BR; } if ($suffix && file_exists($path . SL . 'widget' . SL . strtolower($feature_class) . SL . $suffix . $ext)) { $class = $namespace . BS . 'Widget' . BS . $feature_class . BS . $suffix; break; } if (isset($GLOBALS['D'])) { echo '- try B4 ' . $path . SL . 'widget' . SL . strtolower($feature_class) . SL . $feature_what . $_suffix . $ext . BR; } if (file_exists($path . SL . 'widget' . SL . strtolower($feature_class) . SL . $feature_what . $_suffix . $ext)) { $class = $namespace . BS . 'Widget' . BS . $feature_class . BS . $feature_what . $_suffix; break; } if (isset($GLOBALS['D']) && $suffix) { echo '- try B5 ' . $path . SL . 'webservice' . SL . strtolower($feature_class) . SL . $suffix . $ext . BR; } if ($suffix && file_exists($path . SL . 'webservice' . SL . strtolower($feature_class) . SL . $suffix . $ext)) { $class = $namespace . BS . 'Webservice' . BS . $feature_class . BS . $suffix; break; } if (isset($GLOBALS['D'])) { echo '- try B6 ' . $path . SL . 'webservice' . SL . strtolower($feature_class) . SL . $feature_what . $_suffix . $ext . BR; } if (file_exists($path . SL . 'webservice' . SL . strtolower($feature_class) . SL . $feature_what . $_suffix . $ext)) { $class = $namespace . BS . 'Webservice' . BS . $feature_class . BS . $feature_what . $_suffix; break; } // next application is the parent one } while (next($application_classes)); // Looking for direct feature call, without using any controller static $last_controller_class = ''; static $last_controller_method = ''; if (empty($class) && (strpos($suffix, 'View') === false || $last_controller_class !== $base_class && $last_controller_method !== $feature_name)) { if (strpos($suffix, 'Controller') !== false) { $last_controller_class = $base_class; $last_controller_method = $feature_name; } if (@method_exists($base_class, $feature_name)) { $class = $base_class; $method = $feature_name; } } // Looking for default controller for each application if (empty($class) && $suffix) { reset($application_classes); // $suffix == 'Html_View' => $sub = 'View/Html', $suffix = 'View' if (strpos($suffix, '_')) { $elements = explode('_', $suffix); $sub = join(SL, array_reverse($elements)); $suffix = end($elements); } else { $sub = $suffix; } do { if (isset($GLOBALS['D'])) { echo '- try C2 ' . $path . SL . strtolower($sub) . '/Default_' . $suffix . $ext . BR; } if (file_exists($path . SL . strtolower($sub) . '/Default_' . $suffix . $ext)) { $class = $namespace . BS . str_replace(SL, BS, $sub) . BS . 'Default_' . $suffix; break; } } while (next($application_classes)); } } $result = [isset($class) ? $class : null, $method]; if (isset($GLOBALS['D'])) { echo '- FOUND ' . join('::', $result) . BR; } return $result; }
/** * @param $link * @param $class_name * @return Table[] */ private function buildLinkTables($link, $class_name) { $link_class_name = Namespaces::defaultFullClassName($link, $class_name); $tables = (new Table_Builder_Class())->build($link_class_name); $this->excluded_properties = array_keys((new Reflection_Class($link_class_name))->getProperties([T_EXTENDS, T_USE])); return $tables; }
/** * @return string */ public function getSetClassName() { $expr = '%' . '\\n\\s+\\*\\s+' . '@set' . '\\s+([\\\\\\w]+)' . '%'; preg_match($expr, $this->getDocComment(), $match); return $match ? Namespaces::defaultFullClassName($match[1], $this->name) : Set::defaultSetClassNameOf($this->name); }
/** * Changes 'A\Namespace\Class_Names' into 'A\Namespace\Class_Name' * * @param $class_name string * @param $check_class boolean false if you don't want to check for existing classes * @return string */ public static function setToClass($class_name, $check_class = true) { $set_class_name = $class_name; $class_name = Namespaces::shortClassName($class_name); $right = ''; do { $class_name = self::setToSingle($class_name); $full_class_name = Namespaces::defaultFullClassName($class_name . $right, $set_class_name); if (@class_exists($full_class_name) || trait_exists($full_class_name, false)) { return $full_class_name; } $i = strrpos($class_name, '_'); if (strrpos($class_name, BS) > $i) { $i = false; } if ($i === false) { if ((@class_exists($set_class_name) || trait_exists($set_class_name, false)) && (new Reflection_Class($set_class_name))->getAnnotation('set')->value == $set_class_name) { return $set_class_name; } elseif ($check_class && error_reporting()) { trigger_error('No class found for set ' . $set_class_name, E_USER_ERROR); } else { $right = substr($class_name, $i) . $right; $class_name = substr($class_name, 0, $i); } } else { $right = substr($class_name, $i) . $right; $class_name = substr($class_name, 0, $i); } } while (!empty($class_name)); $class_name .= $right; if (class_exists($class_name, false) || trait_exists($class_name, false)) { return $class_name; } elseif (strrpos($set_class_name, '_') > strrpos($set_class_name, BS)) { $namespace = Namespaces::of($set_class_name); $class_name = substr($set_class_name, strpos($set_class_name, '_', strlen($namespace)) + 1); return self::setToClass($namespace . BS . $class_name, $check_class); } else { return $set_class_name; } }
/** * Gets built name space for a class name * * @param $class_name string ie 'SAF\Framework\Module\Class_Name' * @return string ie 'Vendor\Application\Built\SAF\Framework\Module\Class_Name' */ public static function builtClassName($class_name) { $namespace = array_slice(explode(BS, Namespaces::of($class_name)), 1); $left = Application::current()->getNamespace(); $namespace = $left . BS . 'Built' . BS . join(BS, $namespace); $built_class = $namespace . BS . Namespaces::shortClassName($class_name); return $built_class; }
/** * @param $class_name string * @return string */ private function addClassPath($class_name) { $result = ''; foreach ($this->filesFor(Namespaces::shortClassName($class_name)) as $file_name) { $in_class_name = $this->fileToClassName($file_name); if ($in_class_name) { $this->changes = true; $this->class_paths[$in_class_name] = $file_name; if ($in_class_name == $class_name) { $result = $file_name; break; } } } return $result; }