self::replaceContent($x); return preg_replace_callback('/<(\w+)(\s+[a-zA-Z\-]+=\"[^\"]*\")*\s+tal:replace="structure\s+component:([^\"]*)"[^>]*>/u', $callback, $text); } /** * Выполняет запрос компонента и возвращает результат * Результат может быть строкой или View для обычных компонентов, или массивом для использования в сервисах * * @param HttpRequest $request * @param bool $has_id * @return mixed */ function execute(HttpRequest $request, $has_id = true) { $crequest = new ComponentRequest($this->component_id, $request); $_action = $request->get('action', 'index'); if (is_array($_action)) { $action = 'action' . ucfirst(Arr::get($_action, $this->component_id, 'index')); } else { $action = 'action' . ucfirst($_action); } $this->before(); $actionMethod = [$this, $action]; if (is_callable($actionMethod)) { return call_user_func($actionMethod, $crequest); } return $this->actionIndex($crequest); } /** * Получить имя шаблона * @param Registry $_registry * @return string */ public function getTemplateName($_registry) { return (isset($_COOKIE['with_template']) && preg_match('/^[\w\d-]{3,20}$/', $_COOKIE['with_template'])) ? $_COOKIE['with_template'] : ($_registry ? $_registry->get('site', 'template') : 'modern'); } /** * Получить шаблон * @param string $name * @return Template */ public function getView($name) { if ($this->output === 'json') { return new Json($name); } /** @var Registry $config */ $config = $this->config; $default = $config->get('site', 'template'); $template = ($this->template) ? $this->template : $this->getTemplateName($config); $selected = null; $tpl = null; foreach ($this->viewPath as $index => $viewPath) { // Загружать шаблон по умолчанию если не найден текущий $dir = Path::join($this->viewPath[$index], 'templates', $template); if(is_dir($dir)) { $tpl = new TalView(Path::join($this->viewPath[$index], 'templates', $template, $name)); $selected = $index; break; } } if ($selected === null) { // Последний вариант viewPath, путь к папке компонента $selected = count($this->viewPath) - 1; $tpl = new TalView(Path::join($this->viewPath[$selected], 'templates', 'modern', $name)); $template = 'modern'; } // $tpl->addPreFilter(new \PHPTAL_PreFilter_Normalize()); $tpl->set('common', Path::join($this->config->get('system', 'web'), '../', 'common')); $tpl->set('script', Path::join($this->config->get('system', 'web'), 'js')); $tpl->set('media', Path::join($this->config->get('system', 'templates.web'), $template)); if ($default) { $tpl->set('site_template', Path::join($this->config->get('site', 'templates.web'), $default)); } $tpl->set('base', $this->config->get('site', 'web')); $tpl->set('component_base', $this->webPath[$selected]); $tpl->set('component', Path::join($this->webPath[$selected], 'templates', $template)); $tpl->set('component_id', $this->component_id); return $tpl; } /** * Возвращает путь к шаблону по умолчанию * @return string */ function _getDefaultPath() { return $this->viewPath[count($this->viewPath) - 1]; } /** * Возвращает путь к шаблону * @param string $name * @return string */ public function getTemplatePath($name) { $registry = $this->config; // Брать настройки из куков если есть $template = ($this->template) ? $this->template : $this->getTemplateName($registry); foreach ($this->viewPath as $index => $_) { if(is_dir(Path::join($this->viewPath[$index], 'templates', $template))) { return Path::join($this->viewPath[$index], 'templates', $template, $name); } } return Path::join($this->viewPath[count($this->viewPath) - 1], 'templates', 'modern', $name); } /** * Возвращает путь к шаблонам * @return string */ public function getTemplateWebPath() { return Path::join($this->webPath[count($this->webPath) - 1], 'templates', 'modern'); } /** * Создает модель * * @template T * @param class-string $modelName * @return T */ public function getModel($modelName) { $model = new $modelName(); $model->config = $this->config; $model->db = $this->db; return $model; } /** * @param string $key * @param string $val * @param PDOStatement $res * @return array{value: string, name: string}[] */ public function options(string $key, string $val, $res) { $result = []; while($res->next()) { $result[] = ['value' => $res->getString($key), 'name' => $res->getString($val)]; } return $result; } /** * @param array $list * @param bool $selected * @return array{value: string, name: string, selected: bool}[] */ public function optionsPair(array $list, $selected = false) { $result = []; foreach ($list as $key => $value) { $result [] = ['value' => $key, 'name' => $value, 'selected' => $key == $selected]; } return $result; } /** * Найти файл по пути * @param string[] $pathList * @param string $name * @return string|null */ function findFile(array $pathList, string $name) { foreach($pathList as $item) { $filename = Path::join($item, $name); if (file_exists($filename)) { return $filename; } } return null; } /** * Получить информацию о параметрах * @return array */ function getInfo() { $filename = Path::join($this->viewPath[count($this->viewPath) - 1], 'install.json'); if (file_exists($filename)) { $settings = json_decode(File::getContents($filename), true); if ($settings) { return $settings; } } return ['parameter' => []]; } /** * Генерация интерфейса для выбора галлереи фотографии * @param View $view * @param ?\ctiso\Form\OptionsFactory $options */ public function setParameters(View $view, $options = null): void { $form = new Form(); $settings = $this->getInfo(); $form->addFieldList($settings['parameter'], $options); $view->set('form', $form); $view->set('component', $settings['component']); $view->set('component_title', $settings['title']); } /** * @param \ctiso\Form\OptionsFactory $options * @return array */ public function getFields($options = null) { $form = new Form(); $settings = $this->getInfo(); $form->addFieldList($settings['parameter'], $options); return $form->field; } /** * Обьеденить с ComponentFactory * @param string $expression * @param SiteInterface $site * @return Component */ static function loadComponent(string $expression, $site) { $expression = htmlspecialchars_decode($expression); $offset = strpos($expression, '?'); $url = parse_url($expression); $arguments = []; $path = $expression; if (is_int($offset)) { $path = substr($expression, 0, $offset); $query = substr($expression, $offset + 1); parse_str($query, $arguments); } $name = $path; $config = $site->getConfig(); // FIXME: Если имя для компонента не задано то возвращаем пустой компонент // Нужно дополнительно проверить и файл или в autoloader просто не найдет файл копонента if (!$name) { return new Component(); } $filename = ucfirst($name); $path = Path::join ($config->get('site', 'components'), $name, $filename . '.php'); $className = implode("\\", ['Components', ucfirst($name), $filename]); $component = null; if (file_exists($path)) { /** @var Component $component */ $component = new $className(); $component->viewPath = [$config->get('site', 'components') . '/' . $name . '/']; $component->webPath = [$config->get('site', 'components.web') . '/' . $name]; $component->COMPONENTS_WEB = $config->get('site', 'web') . '/components/'; } else { /** @var Component $component */ $component = new $className(); $template = $component->getTemplateName($site->getConfig()); $component->viewPath = [ // Сначало ищем локально $config->get('site', 'templates') . '/'. $template . '/_components/' . $name . '/', $config->get('site', 'components') . '/' . $name . '/', // Потом в общем хранилище $config->get('system', 'templates'). '/' . $template . '/_components/' . $name . '/', $config->get('system', 'components') . '/' . $name . '/', ]; if (defined('COMPONENTS_WEB')) { $component->webPath = [ // Сначало локально $config->get('site', 'templates.web') . '/' . $template . '/_components/' . $name, $config->get('site', 'components.web') . '/' . $name, // Потом в общем хранилище $config->get('system', 'templates.web') . '/' . $template . '/_components/' . $name, $config->get('system', 'components.web') . '/' . $name, ]; $component->COMPONENTS_WEB = $config->get('system', 'components.web'); } else { $component->webPath = ['', $config->get('site', 'components.web') . '/' . $name, '', '']; } } // Вынести в отдельную функцию $db = $site->getDatabase(); $component->db = $db; $component->config = $site->getConfig(); $component->site = $site; $stmt = $db->prepareStatement("SELECT * FROM component WHERE code = ?"); $stmt->setString(1, $expression); $cid = $stmt->executeQuery(); if ($cid->next()) { $component->component_id = $cid->getInt('id_component'); } else { $last = $db->getIdGenerator(); $result = null; if ($last->isBeforeInsert()) { $result = $last->getId('component_id_component_seq'); $stmt = $db->prepareStatement("INSERT INTO component (id_component, code) VALUES ($result, ?)"); $stmt->setString(1, $expression); $stmt->executeQuery(); } if ($last->isAfterInsert()) { $stmt = $db->prepareStatement("INSERT INTO component (code) VALUES (?)"); $stmt->setString(1, $expression); $stmt->executeQuery(); $result = $last->getId('component_id_component_seq'); } $component->component_id = $result; } $params = new Collection(); $params->import(array_merge($_GET, $arguments)); $component->parameter = $params; $component->template = $params->get('template', false); $editor = $component->getEditUrl(); if ($editor) { $site->addComponentConfig($editor); } return $component; } /** * @return ?array{name: string, url: string} */ function getEditUrl() { return null; } /** * @param ComponentRequest $request * @return array */ function raw_query($request) { $arr = $request->r->export('get'); $param = []; $parameter = $this->parameter; foreach($parameter->export() as $key => $value) { $param[$key] = $value; } $data = []; foreach($arr as $key => $value) { if (is_array($value)) { $data[$key] = Arr::get($value, $this->component_id); } else { $data[$key] = $value; } } $data['param'] = $param; return $data; } /** * @param ComponentRequest $request * @param array $list * @return string */ function query($request, $list) { $arr = $request->r->export('get'); foreach($list as $key => $val) { $arr[$key] [$this->component_id] = $val; } unset($arr['active_page']); return '?' . http_build_query($arr); } /** * @param string $name * @param string $path * @param array $shim */ function addRequireJsPath($name, $path, $shim = null): void { $this->site->addRequireJsPath($name, $path, $shim); } /** * @param ComponentRequest $request * @return mixed */ function actionIndex($request) { return ""; } /** * @param HttpRequest $request * @return array */ function getDefaultPageEnvironment($request) { return []; } }