phplibrary/src/Controller/Action.php

381 lines
12 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace ctiso\Controller;
use Exception,
ctiso\Path,
ctiso\Url,
ctiso\Model\Factory,
ctiso\HttpRequest,
ctiso\Functions,
ctiso\Settings,
ctiso\Registry,
ctiso\Role\User,
ctiso\View\Composite,
ctiso\Filter\ActionAccess,
ctiso\View\View,
ctiso\Controller\State;
/**
* Контроллер страниц
*/
class Action
{
const TEMPLATE_EXTENSION = ".html"; // Расширение для шаблонов
const ACTION_PREFIX = "action"; // Префикс для функций действий
// Параметры устанавливаются при создании контроллера
public $name = ''; // Имя модуля
public $front;
public $modulePath = null; // Путь к модулю
public $moduleTitle = '';
public $viewPathPrefix = ''; // Путь к шаблонам контроллера
/**
* Соединение с базой данных
*/
public $db;
// Фильтры
public $access = null; // Обьект хранит параметры доступа
public $logger = null; // Обьект для ведения лога
private $factory = null; // Ссылка на обьект создания модели
private $helpers = array(); // Помошники для действий
public $part = null; // Параметры для ссылки
public $config/*: Registry*/; // Ссылка на настройки
public $user/*: User*/; // Обьект пользователя
// Для Widgets
public $view = null;
public $childNodes = array();
public $ctrlValues = array();
public $childViews = array();
function __construct() {
$this->part = new Url();
}
public function setUp() {
}
public function loadConfig($name) {
$basePath = $this->config->get('site', 'path');
$filename = Path::join($basePath, 'modules', $name);
$settings = [];
if (file_exists($filename)) {
$settings = include($filename);
} else {
throw new Exception('Невозможно загрузить файл настроек ' . $name);
}
return $settings;
}
public function getConnection()
{
return $this->db;
}
public function installPath($name)
{
$basePath = $this->config->get('system', 'path');
return Path::join($basePath, "modules", $name);
}
public function addSuggest(View $view, $name) {
$suggest = array();
$file = Path::join($this->modulePath, 'help', $name . '.suggest');
if (file_exists($file)) {
$view->suggestions = include($file);
}
}
function findIcon($icon, $size) {
$webPath = $this->config->get('site', 'web');
return Path::join($webPath, 'icons', $size . 'x' . $size, $icon . '.png');
}
/**
* Создает представление
* @param string $name
* @param string $viewClass
* @return Composite
*/
public function getView($name, $viewClass = Composite::class)
{
$file = $name . self::TEMPLATE_EXTENSION;
$basePath = $this->config->get('system', 'path');
$webPath = $this->config->get('system', 'web');
$list = array(
Path::join($this->modulePath, 'templates', $this->viewPathPrefix) => Path::join($webPath, "modules", $this->name, 'templates', $this->viewPathPrefix),
Path::join($basePath, "templates") => Path::join($webPath, "templates")
);
// Поиск файла для шаблона
foreach($list as $ospath => $path) {
$template = Path::join($ospath, $file);
if(file_exists($template)) { break; }
}
$tpl/*: Composite*/ = new $viewClass($template);
$tpl->config = $this->config;
$stylePath = Path::join($webPath, "assets", "css");
$iconsPath = Path::join($webPath, 'icons');
$scriptPath = Path::join($webPath, 'assets');
$tpl->set('icons', $iconsPath); // Путь к файлам текущей темы
$tpl->set('assets', $stylePath);
$tpl->set('script', $scriptPath); // Путь к файлам скриптов
$tpl->set('template', $path); // Путь к файлам текущего шаблона
$tpl->setAlias(array(
'assets' => $stylePath,
'icons' => $iconsPath,
'script' => $scriptPath,
// Для media и template поиск происходит как для файлов шаблонов
'media' => $list,
'template' => $list
));
$tpl->loadImports(Path::skipExtension($template) . ".import");
$this->addSuggest($tpl, $name);
return $tpl;
}
public function getModel($name)
{
if (!$this->factory) {
$this->factory = new Factory($this->db, $this->config, $this->user);
}
return $this->factory->getModel($name);
}
/**
* Выбор действия
* Т.к действия являются методами класса то
* 1. Можно переопределить действия
* 2. Использовать наследование чтобы добавить к старому обработчику новое поведение
* @param HttpRequest $request запроса
*/
public function preProcess(HttpRequest $request)
{
$action = self::ACTION_PREFIX . ucfirst($request->getAction());
if (!method_exists($this, $action)) {
$action = "actionIndex";
}
$view = $this->forward($action, $request);
if ($view instanceof View) {
$view->active_module = get_class($this);
$view->module_action = $action;
}
return $view;
}
public function execute(HttpRequest $request)
{
$result = $this->preProcess($request);
if (!empty($result)) {
$this->view = $result;
}
$text = $this->render();
return $text;
}
public function forward($action, HttpRequest $args) {
$value = call_user_func(array($this, $action), $args);
return $value;
}
/**
* Страница по умолчанию
*/
public function actionIndex(HttpRequest $request) {
return "";
}
public function addUrlPart($key, $value) {
$this->part->addQueryParam($key, $value);
}
/**
* Генерация ссылки c учетом прав пользователя на ссылки
* @param string $name Действие
* @param array $param Дополнительные параметры
* 'mode' означает что элемент до отправки обрабатывается javascript
* @return Url|null
*/
public function nUrl($name, array $param = array())
{
$access/*: ActionAccess*/ = $this->access;
$url = new Url();
if ($access == null || $access->checkAction($name)) {
$moduleName = explode("\\", strtolower(get_class($this)));
if (count($moduleName) > 2) {
array_shift($moduleName);
if ($moduleName[0] == $moduleName[1]) {
array_shift($moduleName);
}
}
$param = array_merge(array('module' => implode("\\", $moduleName), "action" => $name), $param);
$url->setParent($this->part);
$url->setQuery($param);
}
return $url;
}
/**
* Генерация ссылки на действие контроллера
* Ajax определяется автоматически mode = ajax используется для смены layout
* @param $name
* @param array $param
* @return Url|null
*
* @example ?action=$name&mode=ajax
* {$param[i].key = $param[i].value}
*/
public function aUrl($name, array $param = array())
{
return $this->nUrl($name, array_merge(array('mode' => 'ajax'), $param));
}
/**
* Добавление помошника контроллера
*/
public function addHelper($class)
{
$this->helpers [] = $class;
}
/**
* Вызов помошников контроллера
*/
public function callHelpers(HttpRequest $request)
{
$action = self::ACTION_PREFIX . $request->getAction();
foreach ($this->helpers as $helper) {
if (method_exists($helper, $action)) {
return call_user_func(array($helper, $action), $request, $this);
} else {
return $helper->actionIndex($request, $this); // Вместо return response ???
}
}
}
/**
* Загрузка файла класса
*/
public function loadClass($path, $setup = null, $prefix = '')
{
if (file_exists($path)) {
require_once ($path);
$class = $prefix . pathinfo($path, PATHINFO_FILENAME);
return new $class($setup);
}
throw new Exception("NO CLASS $path");
}
public function loadSettings($path)
{
$result = new Settings($path);
$result->read();
return $result->export();
}
public function setView($name)
{
$this->view = $this->getView($name);
}
/**
* Установка заголовка для отображения
*/
public function setTitle($title)
{
$this->view->setTitle($title);
}
/**
* Добавление widget к отображению
*/
public function addChild($section, $node)
{
$this->childNodes[$section] = $node;
}
public function setValue($name, $value)
{
$this->ctrlValues[$name] = $value;
}
/**
* Добавление дочернего отображения к текущему отображению
*/
public function addView($section, $node)
{
$this->childViews[$section] = $node;
}
/**
* Генерация содержания
* Путаница c execute и render
*/
public function render()
{
$view = $this->view;
if ($view instanceof View) {
$this->view->assignValues($this->ctrlValues);
$node/*: Composite*/ = null;
foreach ($this->childNodes as $name => $node) {
$node->make($this);
$this->view->setView($name, $node->view);
}
foreach ($this->childViews as $name => $node) {
$this->view->setView($name, $node);
}
}
return $this->view;
}
function getPageId(HttpRequest $request) {
$pageId = time();
$request->session()->set('page', $pageId);
return $pageId;
}
function checkPageId(HttpRequest $request, $page)
{
if ($request->get('__forced__')) {
return true;
}
$_page = $request->session()->get('page');
$result = ($_page && $_page == $page);
$request->session()->clean('page');
return $result;
}
function _getActionPath() {
return new State('index');
}
// Тоже убрать в метод Controller_Model
function getActionPath(HttpRequest $request, $action = null) {
$this->_getActionPath()->getPath($this, ($action) ? $action : $request->getAction());
}
function redirect($action/*: string*/) {
header('location: ' . $action);
exit();
}
}