428 lines
13 KiB
PHP
428 lines
13 KiB
PHP
<?php
|
||
|
||
namespace ctiso\Controller;
|
||
|
||
use ctiso\HttpRequest;
|
||
use ctiso\ComponentRequest;
|
||
use ctiso\Arr;
|
||
use ctiso\Path;
|
||
use ctiso\File;
|
||
use ctiso\Form\Form;
|
||
use ctiso\View\Composite;
|
||
use ctiso\Database;
|
||
use ctiso\Collection;
|
||
use ctiso\Registry;
|
||
use ctiso\Controller\SiteInterface;
|
||
use PHPTAL;
|
||
use PHPTAL_PreFilter_Normalize;
|
||
|
||
class FakeTemplate {
|
||
public $_data = [];
|
||
public $_name = '';
|
||
|
||
function __construct($name) {
|
||
$this->_name = $name;
|
||
}
|
||
|
||
function __set($key, $value) {
|
||
$this->_data[$key] = $value;
|
||
}
|
||
|
||
function execute() {
|
||
return json_encode($this->_data);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Класс компонента
|
||
*/
|
||
class Component
|
||
{
|
||
public $viewPath = [];
|
||
public $webPath = [];
|
||
|
||
public $template = null;
|
||
public string $templatePath;
|
||
|
||
public $component_id;
|
||
public $component_title;
|
||
|
||
public $COMPONENTS_WEB;
|
||
|
||
public Registry $config;
|
||
public Database $db;
|
||
public Collection $parameter;
|
||
|
||
public $output = 'html';
|
||
|
||
public $module;
|
||
public $item_module;
|
||
|
||
/**
|
||
* @var SiteInterface $site
|
||
*/
|
||
public $site;
|
||
|
||
function before() {
|
||
}
|
||
|
||
static function replaceContent($match) {
|
||
return \ctiso\Tales::phptal_component(htmlspecialchars_decode($match[3]));
|
||
}
|
||
|
||
static function applyComponents($text) {
|
||
return preg_replace_callback('/<(\w+)(\s+[a-zA-Z\-]+=\"[^\"]*\")*\s+tal:replace="structure\s+component:([^\"]*)"[^>]*>/u', 'ctiso\\Controller\\Component::replaceContent', $text);
|
||
}
|
||
|
||
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();
|
||
if (method_exists($this, $action)) {
|
||
return call_user_func([$this, $action], $crequest);
|
||
} else {
|
||
return $this->actionIndex($crequest);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Получить имя шаблона
|
||
* @param Registry $_registry
|
||
*/
|
||
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');
|
||
}
|
||
|
||
public function getView($name)
|
||
{
|
||
if ($this->output === 'json') {
|
||
return new FakeTemplate($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 PHPTAL(Path::join($this->viewPath[$index], 'templates', $template, $name));
|
||
$tpl->setPhpCodeDestination(PHPTAL_PHP_CODE_DESTINATION);
|
||
$selected = $index;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if ($selected === null) {
|
||
// Последний вариант viewPath, путь к папке компонента
|
||
$selected = count($this->viewPath) - 1;
|
||
$tpl = new PHPTAL(Path::join($this->viewPath[$selected], 'templates', 'modern', $name));
|
||
$tpl->setPhpCodeDestination(PHPTAL_PHP_CODE_DESTINATION);
|
||
$template = 'modern';
|
||
}
|
||
|
||
$tpl->stripComments(true);
|
||
$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;
|
||
}
|
||
|
||
function _getDefaultPath() {
|
||
return $this->viewPath[count($this->viewPath) - 1];
|
||
}
|
||
|
||
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);
|
||
}
|
||
|
||
public function getTemplateWebPath()
|
||
{
|
||
return Path::join($this->webPath[count($this->webPath) - 1], 'templates', 'modern');
|
||
}
|
||
|
||
/**
|
||
* Создает модель
|
||
* @param string $name
|
||
* @return mixed
|
||
*/
|
||
public function getModel($name)
|
||
{
|
||
$modelName = "App\\Mapper\\" . $name;
|
||
$model = new $modelName();
|
||
$model->config = $this->config;
|
||
$model->db = $this->db;
|
||
return $model;
|
||
}
|
||
|
||
/**
|
||
* @param string $key
|
||
* @param string $val
|
||
* @param $res
|
||
*/
|
||
public function options(string $key, string $val, $res) {
|
||
$result = [];
|
||
while($res->next()) {
|
||
$result[] = ['value' => $res->getString($key), 'name' => $res->getString($val)];
|
||
}
|
||
return $result;
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
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 Composite $view
|
||
* @param \ctiso\Form\OptionsFactory $options
|
||
*/
|
||
public function setParameters(Composite $view, $options = null)
|
||
{
|
||
$form = new Form();
|
||
|
||
$settings = $this->getInfo();
|
||
$form->addFieldList($settings['parameter'], $options);
|
||
|
||
$view->form = $form;
|
||
$view->component = $settings['component'];
|
||
$view->component_title = $settings['title'];
|
||
}
|
||
|
||
public function getFields($options = null) {
|
||
$form = new Form();
|
||
$form->addFieldList($this->getInfo()['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();
|
||
|
||
$filename = ucfirst($name);
|
||
$path = Path::join ($config->get('site', 'components'), $name, $filename . '.php');
|
||
$className = implode("\\", ['Components', ucfirst($name), $filename]);
|
||
|
||
/**
|
||
* @var ?Component $component
|
||
*/
|
||
$component = null;
|
||
|
||
if (file_exists($path)) {
|
||
$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 {
|
||
$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;
|
||
}
|
||
|
||
function getEditUrl() {
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* @param ComponentRequest $request
|
||
*/
|
||
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
|
||
*/
|
||
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);
|
||
}
|
||
|
||
function addRequireJsPath($name, $path, $shim = null) {
|
||
$this->site->addRequireJsPath($name, $path, $shim);
|
||
}
|
||
|
||
/**
|
||
* @param ComponentRequest $request
|
||
*/
|
||
function actionIndex($request) {
|
||
}
|
||
}
|