Compare commits

..

1 commit

34 changed files with 211 additions and 287 deletions

View file

@ -58,23 +58,12 @@ class Collection implements \ArrayAccess
/** /**
* @param string $key * @param string $key
* @param int $default * @param int $default
* @return int * @return int
*/ */
public function getInt(string $key, int $default = 0): int public function getInt($key, $default = 0)
{ {
$value = $this->get($key); return (int)$this->get($key, $default);
// Фильтруем как целое число
if (is_numeric($value)) {
// Приводим к int, но сначала проверим, что не float с дробной частью
$floatVal = (float)$value;
if (is_finite($floatVal) && floor($floatVal) === $floatVal) {
return (int)$floatVal;
}
}
return $default;
} }
/** /**
@ -84,59 +73,15 @@ class Collection implements \ArrayAccess
*/ */
public function getString(string $key, string $default = ''): string public function getString(string $key, string $default = ''): string
{ {
$value = $this->get($key); return (string)$this->get($key, $default);
if (is_string($value)) {
return $value;
}
if (is_numeric($value)) {
return (string)$value;
}
return $default;
} }
/**
* Получает булево значение
* Поддерживает: 1, '1', 'true', 'on', 'yes' true
* Иначе false
*/
public function getBool(string $key, bool $default = false): bool
{
$value = $this->get($key);
if (is_bool($value)) {
return $value;
}
if (is_string($value)) {
$value = strtolower(trim($value));
return in_array($value, ['1', 'true', 'on', 'yes'], true);
}
if (is_numeric($value)) {
return (bool)$value;
}
return $default;
}
function getArray(string $key, array $default = []): array {
$result = $this->get($key);
if (is_array($result)) {
return $result;
}
return $default;
}
/** /**
* @param string $key * @param string $key
* @param int $default * @param int $default
* @return int * @return int
*/ */
public function getNat(string $key, int $default = 1): int public function getNat($key, $default = 1)
{ {
$result = (int)$this->get($key, $default); $result = (int)$this->get($key, $default);
return (($result > 0) ? $result : $default); return (($result > 0) ? $result : $default);

View file

@ -47,12 +47,12 @@ class HttpResponse
if (isset($this->param['Transfer-Encoding']) && $this->param['Transfer-Encoding'] == 'chunked') { if (isset($this->param['Transfer-Encoding']) && $this->param['Transfer-Encoding'] == 'chunked') {
//$this->data = substr($this->response, $this->offset); //$this->data = substr($this->response, $this->offset);
$index = (int)hexdec($this->getLine()); $index = hexdec($this->getLine());
$chunk = []; $chunk = [];
while ($index > 0) { while ($index > 0) {
$chunk [] = substr($this->response, $this->offset, $index); $chunk [] = substr($this->response, $this->offset, $index);
$this->offset += $index; $this->offset += $index;
$index = (int)hexdec($this->getLine()); $index = hexdec($this->getLine());
} }
$this->data = implode("", $chunk); $this->data = implode("", $chunk);

View file

@ -111,7 +111,7 @@ class Action implements ActionInterface
* @param int $size * @param int $size
* @return string Путь к иконке * @return string Путь к иконке
*/ */
function findIcon($icon, $size) { function findIcon($icon, $size): string {
$webPath = $this->config->get('site', 'web'); $webPath = $this->config->get('site', 'web');
return Path::join($webPath, 'icons', $size . 'x' . $size, $icon . '.png'); return Path::join($webPath, 'icons', $size . 'x' . $size, $icon . '.png');
} }
@ -119,8 +119,8 @@ class Action implements ActionInterface
/** /**
* Создает представление * Создает представление
* @param string $name * @param string $name
* @param class-string $viewClass * @param class-string<Composite> $viewClass
* @return Composite * @return View
*/ */
public function getView($name, $viewClass = Composite::class) public function getView($name, $viewClass = Composite::class)
{ {
@ -143,7 +143,7 @@ class Action implements ActionInterface
/** @var \ctiso\View\Composite */ /** @var \ctiso\View\Composite */
$tpl = new $viewClass($template); $tpl = new $viewClass($template);
$tpl->config = $this->config; $tpl->set('config', $this->config);
$stylePath = Path::join($webPath, "assets", "css"); $stylePath = Path::join($webPath, "assets", "css");
$iconsPath = Path::join($webPath, 'icons'); $iconsPath = Path::join($webPath, 'icons');
@ -231,7 +231,7 @@ class Action implements ActionInterface
/** /**
* Страница по умолчанию * Страница по умолчанию
* @param HttpRequest $request * @param HttpRequest $request
* @return string|false * @return View|string
*/ */
public function actionIndex(HttpRequest $request) { public function actionIndex(HttpRequest $request) {
return ""; return "";

View file

@ -2,6 +2,7 @@
namespace ctiso\Controller; namespace ctiso\Controller;
use ctiso\View\Template;
use ctiso\Database; use ctiso\Database;
use ctiso\HttpRequest; use ctiso\HttpRequest;
@ -10,14 +11,14 @@ interface ActionInterface {
* Действие может вернуть Шаблон или строку * Действие может вернуть Шаблон или строку
* *
* @param HttpRequest $request * @param HttpRequest $request
* @return \ctiso\View\View|string|false * @return Template|string|false
*/ */
function execute(HttpRequest $request); function execute(HttpRequest $request);
function getConnection(): Database; function getConnection(): Database;
/** /**
* @param string $name * @param string $name
* @param class-string<\ctiso\View\View> $class * @param class-string<Template> $class
* @return \ctiso\View\View * @return Template
*/ */
function getView($name, $class); function getView($name, $class);
/** /**

View file

@ -8,15 +8,17 @@ use ctiso\Arr;
use ctiso\Path; use ctiso\Path;
use ctiso\File; use ctiso\File;
use ctiso\Form\Form; use ctiso\Form\Form;
use ctiso\View\Composite; use ctiso\View\View;
use ctiso\Database; use ctiso\Database;
use ctiso\Collection; use ctiso\Collection;
use ctiso\Registry; use ctiso\Registry;
use ctiso\Controller\SiteInterface; use ctiso\Controller\SiteInterface;
use ctiso\Database\PDOStatement; use ctiso\Database\PDOStatement;
use ctiso\View\Json;
use PHPTAL; use PHPTAL;
use PHPTAL_PreFilter_Normalize; use PHPTAL_PreFilter_Normalize;
use ctiso\View\JsonView; use ctiso\View\Template;
use ctiso\View\TalView;
/** /**
* Класс компонента * Класс компонента
@ -117,12 +119,12 @@ class Component
/** /**
* Получить шаблон * Получить шаблон
* @param string $name * @param string $name
* @return PHPTAL|JsonView * @return Template
*/ */
public function getView($name) public function getView($name)
{ {
if ($this->output === 'json') { if ($this->output === 'json') {
return new JsonView($name); return new Json($name);
} }
/** @var Registry $config */ /** @var Registry $config */
@ -135,9 +137,8 @@ class Component
foreach ($this->viewPath as $index => $viewPath) { foreach ($this->viewPath as $index => $viewPath) {
// Загружать шаблон по умолчанию если не найден текущий // Загружать шаблон по умолчанию если не найден текущий
$dir = Path::join($this->viewPath[$index], 'templates', $template); $dir = Path::join($this->viewPath[$index], 'templates', $template);
if (is_dir($dir)) { if(is_dir($dir)) {
$tpl = new PHPTAL(Path::join($this->viewPath[$index], 'templates', $template, $name)); $tpl = new TalView(Path::join($this->viewPath[$index], 'templates', $template, $name));
$tpl->setPhpCodeDestination(PHPTAL_PHP_CODE_DESTINATION);
$selected = $index; $selected = $index;
break; break;
} }
@ -146,13 +147,11 @@ class Component
if ($selected === null) { if ($selected === null) {
// Последний вариант viewPath, путь к папке компонента // Последний вариант viewPath, путь к папке компонента
$selected = count($this->viewPath) - 1; $selected = count($this->viewPath) - 1;
$tpl = new PHPTAL(Path::join($this->viewPath[$selected], 'templates', 'modern', $name)); $tpl = new TalView(Path::join($this->viewPath[$selected], 'templates', 'modern', $name));
$tpl->setPhpCodeDestination(PHPTAL_PHP_CODE_DESTINATION);
$template = 'modern'; $template = 'modern';
} }
$tpl->stripComments(true); // $tpl->addPreFilter(new \PHPTAL_PreFilter_Normalize());
$tpl->addPreFilter(new \PHPTAL_PreFilter_Normalize());
$tpl->set('common', Path::join($this->config->get('system', 'web'), '../', 'common')); $tpl->set('common', Path::join($this->config->get('system', 'web'), '../', 'common'));
$tpl->set('script', Path::join($this->config->get('system', 'web'), 'js')); $tpl->set('script', Path::join($this->config->get('system', 'web'), 'js'));
@ -280,19 +279,19 @@ class Component
/** /**
* Генерация интерфейса для выбора галлереи фотографии * Генерация интерфейса для выбора галлереи фотографии
* @param Composite $view * @param View $view
* @param ?\ctiso\Form\OptionsFactory $options * @param ?\ctiso\Form\OptionsFactory $options
*/ */
public function setParameters(Composite $view, $options = null): void public function setParameters(View $view, $options = null): void
{ {
$form = new Form(); $form = new Form();
$settings = $this->getInfo(); $settings = $this->getInfo();
$form->addFieldList($settings['parameter'], $options); $form->addFieldList($settings['parameter'], $options);
$view->form = $form; $view->set('form', $form);
$view->component = $settings['component']; $view->set('component', $settings['component']);
$view->component_title = $settings['title']; $view->set('component_title', $settings['title']);
} }
/** /**

View file

@ -111,7 +111,7 @@ class Front extends Action
public function execute(HttpRequest $request) public function execute(HttpRequest $request)
{ {
$name = $request->getString('module', $this->default); $name = $request->get('module', $this->default);
try { try {
return $this->loadModule($name, $request); return $this->loadModule($name, $request);
} catch (UserMessageException $ex) { //Исключение с понятным пользователю сообщением } catch (UserMessageException $ex) { //Исключение с понятным пользователю сообщением

View file

@ -55,7 +55,6 @@ class Service
*/ */
public function getModel($modelName) public function getModel($modelName)
{ {
/** @var BaseMapper */
$model = new $modelName(); $model = new $modelName();
$model->db = $this->db; $model->db = $this->db;
return $model; return $model;

View file

@ -23,11 +23,13 @@ namespace ctiso {
* Класс оболочка для PDO для замены Creole * Класс оболочка для PDO для замены Creole
* @phpstan-type DSN = array{phptype: string, hostspec: string, database: string, username: string, password: string} * @phpstan-type DSN = array{phptype: string, hostspec: string, database: string, username: string, password: string}
*/ */
class Database extends PDO class Database
{ {
/** @var DSN */ /** @var DSN */
public $dsn; public $dsn;
/** @var PDO */
public $db;
/** /**
* Создает соединение с базой данных * Создает соединение с базой данных
@ -37,10 +39,10 @@ namespace ctiso {
*/ */
public function __construct($dsn, $username = null, $password = null) public function __construct($dsn, $username = null, $password = null)
{ {
parent::__construct($dsn, $username, $password); $this->db = new PDO($dsn, $username, $password);
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); $this->db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS, [PDOStatement::class, []]); $this->db->setAttribute(PDO::ATTR_STATEMENT_CLASS, [PDOStatement::class, []]);
} }
/** /**
@ -49,13 +51,38 @@ namespace ctiso {
function prepare(string $sql, array $options = []): PDOStatement function prepare(string $sql, array $options = []): PDOStatement
{ {
/** @var PDOStatement */ /** @var PDOStatement */
$result = parent::prepare($sql, $options); $result = $this->db->prepare($sql, $options);
return $result; return $result;
} }
function query($query, $fetchMode = PDO::FETCH_INTO, mixed $_arg1 = null, mixed $_arg2 = null): PDOStatement { function lastInsertId(?string $name = null): string|false {
return $this->db->lastInsertId($name);
}
function beginTransaction(): bool {
return $this->db->beginTransaction();
}
function commit(): bool {
return $this->db->commit();
}
function rollBack(): bool {
return $this->db->rollBack();
}
function quote(string $string, int $type = PDO::PARAM_STR): bool|string {
return $this->db->quote($string, $type);
}
/**
* query возвращает только PDOStatement т.к установлен PDO::ERRMODE_EXCEPTION
* @param string $query
* @return PDOStatement
*/
function query($query): PDOStatement {
/** @var PDOStatement */ /** @var PDOStatement */
$result = parent::query($query, $fetchMode); $result = $this->db->query($query);
return $result; return $result;
} }
@ -76,6 +103,10 @@ namespace ctiso {
{ {
return ($this->dsn["phptype"] == "pgsql"); return ($this->dsn["phptype"] == "pgsql");
} }
function sqliteCreateFunction(string $function_name, ?callable $callback = null, int $num_args = -1): void {
$this->db->sqliteCreateFunction($function_name, $callback, $num_args);
}
/** /**
* Создает соединение с базой данных * Создает соединение с базой данных
* @param array $dsn - DSN * @param array $dsn - DSN
@ -101,7 +132,7 @@ namespace ctiso {
$connection->sqliteCreateFunction('LOWER', 'sqliteLower', 1); $connection->sqliteCreateFunction('LOWER', 'sqliteLower', 1);
} elseif ($dsn['phptype'] == 'sqlite') { } elseif ($dsn['phptype'] == 'sqlite') {
$connection = new self("{$dsn['phptype']}:{$dsn['database']}"); $connection = new self("{$dsn['phptype']}:{$dsn['database']}");
$connection->setAttribute(PDO::ATTR_TIMEOUT, 5); $connection->db->setAttribute(PDO::ATTR_TIMEOUT, 5);
$mode = defined('SQLITE_JOURNAL_MODE') ? \SQLITE_JOURNAL_MODE : 'WAL'; $mode = defined('SQLITE_JOURNAL_MODE') ? \SQLITE_JOURNAL_MODE : 'WAL';
$connection->query("PRAGMA journal_mode=$mode"); $connection->query("PRAGMA journal_mode=$mode");
$connection->sqliteCreateFunction('LOWER', 'sqliteLower', 1); $connection->sqliteCreateFunction('LOWER', 'sqliteLower', 1);

View file

@ -16,7 +16,7 @@ use Exception;
* @phpstan-type CreateAction array{ * @phpstan-type CreateAction array{
* type:"createTable", * type:"createTable",
* table_name:string, * table_name:string,
* constraints?:array{fields: array<string>, type: string}|string, * constraints:?array<mixed>,
* fields:array<mixed>, * fields:array<mixed>,
* } * }
* *
@ -277,7 +277,7 @@ class Manager
* Добавляет столбец в таблицу * Добавляет столбец в таблицу
* @param string $table_name * @param string $table_name
* @param string $column_name * @param string $column_name
* @param ColumnProps $field * @param array $field
*/ */
public function addColumn($table_name, $column_name, $field): void public function addColumn($table_name, $column_name, $field): void
{ {

View file

@ -8,6 +8,7 @@ namespace ctiso\Filter;
use ctiso\Database; use ctiso\Database;
use ctiso\HttpRequest; use ctiso\HttpRequest;
use ctiso\Controller\ActionInterface; use ctiso\Controller\ActionInterface;
use ctiso\View\Template;
class Filter implements ActionInterface class Filter implements ActionInterface
{ {
@ -29,8 +30,8 @@ class Filter implements ActionInterface
/** /**
* @param string $name * @param string $name
* @param class-string<\ctiso\View\View> $class * @param class-string<Template> $class
* @return \ctiso\View\View * @return Template
*/ */
public function getView($name, $class = \ctiso\View\Top::class) public function getView($name, $class = \ctiso\View\Top::class)
{ {

View file

@ -41,7 +41,7 @@ class Login extends Filter
/** /**
* Проверка авторизации * Проверка авторизации
* @param HttpRequest $request * @param HttpRequest $request
* @return bool Авторизовани пользователь или нет * @return Boolean Авторизовани пользователь или нет
*/ */
public function isLoggin(HttpRequest $request) public function isLoggin(HttpRequest $request)
{ {
@ -50,8 +50,8 @@ class Login extends Filter
switch ($request->getAction()) { switch ($request->getAction()) {
// Авторизация по постоянному паролю // Авторизация по постоянному паролю
case 'login': case 'login':
$login = $request->getString('login', '') ; $login = $request->get('login', '') ;
$password = $request->getString('password'); $password = $request->get('password');
$result = $this->role->getUserByLogin($login); // Поиск по логину $result = $this->role->getUserByLogin($login); // Поиск по логину
if ($result) { if ($result) {
@ -81,7 +81,7 @@ class Login extends Filter
$request->set('timeout_error', true); $request->set('timeout_error', true);
break; break;
} else { } else {
$this->role->resetTries($request->getString('login')); $this->role->resetTries($request->get('login'));
} }
} }
// Извлечнеие пользователя из родительской CMS, для проверки пароля // Извлечнеие пользователя из родительской CMS, для проверки пароля
@ -154,7 +154,7 @@ class Login extends Filter
public function execute(HttpRequest $request): mixed public function execute(HttpRequest $request): mixed
{ {
$logged = $this->isLoggin($request); $logged = $this->isLoggin($request);
if ($request->getString('action') == 'user_access') { if ($request->get('action') == 'user_access') {
if ($logged) { if ($logged) {
$result = []; $result = [];
$result['fullname'] = $this->user->getString('patronymic') . " " . $this->user->getString('firstname'); $result['fullname'] = $this->user->getString('patronymic') . " " . $this->user->getString('firstname');
@ -166,7 +166,7 @@ class Login extends Filter
} }
} }
if ($request->getString('action') == 'relogin') { if ($request->get('action') == 'relogin') {
if ($logged) { if ($logged) {
return json_encode(['result' => 'ok', 'message' => "Авторизация успешна"]); return json_encode(['result' => 'ok', 'message' => "Авторизация успешна"]);
} else { } else {
@ -177,7 +177,7 @@ class Login extends Filter
if (!$logged) { if (!$logged) {
// Параметры при неправильной авторизации // Параметры при неправильной авторизации
// Действия по умолчанию !! Возможно переход на форму регистрации // Действия по умолчанию !! Возможно переход на форму регистрации
if ($request->getString('mode') == 'ajax') { if ($request->get('mode') == 'ajax') {
if (!$this->requestIsWhite($request)) { if (!$this->requestIsWhite($request)) {
return json_encode(['result' => 'fail', 'message' =>"NOT_AUTHORIZED"]); return json_encode(['result' => 'fail', 'message' =>"NOT_AUTHORIZED"]);
} }
@ -187,11 +187,8 @@ class Login extends Filter
} }
} else if (isset($_SERVER['HTTP_REFERER'])) { } else if (isset($_SERVER['HTTP_REFERER'])) {
$arr = []; $arr = [];
parse_str(parse_url($_SERVER['HTTP_REFERER'] ?? '', PHP_URL_QUERY) ?: '', $arr); parse_str(parse_url($_SERVER['HTTP_REFERER'] ?? '', PHP_URL_QUERY) ?? '', $arr);
if (isset($arr['back_page']) if (isset($arr['back_page']) && $request->get('mode') != 'ajax') {
&& is_string($arr['back_page'])
&& $request->getString('mode') != 'ajax')
{
$request->redirect($arr['back_page']); $request->redirect($arr['back_page']);
} }
} }

View file

@ -4,7 +4,7 @@ namespace ctiso\Form;
use ctiso\Form\Field; use ctiso\Form\Field;
/** /**
* @phpstan-type Option = array{value: string, name: string, selected?: bool, class?: string|false} * @phpstan-type Option = array{value: string, name: string, selected: bool, class?: string|false}
*/ */
class Select extends Field class Select extends Field
{ {

View file

@ -268,7 +268,7 @@ class Functions {
/** /**
* @param string $key * @param string $key
* @param array<object>|\ArrayIterator<int, object> $array * @param list<object>|\ArrayIterator<int, object> $array
* @return array<mixed> * @return array<mixed>
*/ */
static function key_values_object($key, $array) { static function key_values_object($key, $array) {
@ -283,7 +283,7 @@ class Functions {
/** /**
* @param string $key * @param string $key
* @param string $value * @param string $value
* @param array<array<string, mixed>>|\ArrayIterator<int, array> $array * @param list<array<string, mixed>>|\ArrayIterator<int, array> $array
* @return array<string, mixed> * @return array<string, mixed>
*/ */
static function assoc_key_values($key, $value, $array) { static function assoc_key_values($key, $value, $array) {
@ -296,7 +296,7 @@ class Functions {
/** /**
* @param string $key * @param string $key
* @param array<array<string, mixed>>|\ArrayIterator<int, array> $array * @param list<array<string, mixed>>|\ArrayIterator<int, array> $array
* @return array<string, mixed> * @return array<string, mixed>
*/ */
static function assoc_key($key, $array) { static function assoc_key($key, $array) {

View file

@ -5,7 +5,8 @@
*/ */
namespace ctiso; namespace ctiso;
use Exception;
use ArrayAccess;
use ctiso\Collection; use ctiso\Collection;
use ctiso\Session; use ctiso\Session;
@ -54,7 +55,7 @@ class HttpRequest extends Collection
/** /**
* @param string $key * @param string $key
* @param mixed $default * @param mixed $default
* @return null|string|array * @return mixed
*/ */
function get($key, $default = null) function get($key, $default = null)
{ {
@ -66,26 +67,6 @@ class HttpRequest extends Collection
return parent::get('data')->getString($key, $default); return parent::get('data')->getString($key, $default);
} }
function getInt(string $key, int $default = 0): int
{
return parent::get('data')->getInt($key, $default);
}
function getNat(string $key, int $default = 1): int
{
return parent::get('data')->getNat($key, $default);
}
function getBool(string $key, bool $default = false): bool
{
return parent::get('data')->getBool($key, $default);
}
function getArray(string $key, array $default = []): array
{
return parent::get('data')->getArray($key, $default);
}
function session(?Session $value = null): ?Session function session(?Session $value = null): ?Session
{ {
if ($value) { if ($value) {

View file

@ -2,9 +2,6 @@
namespace ctiso\Model; namespace ctiso\Model;
/**
* @property \ctiso\Database $db
*/
abstract class BaseMapper { abstract class BaseMapper {
function getAllAsOptions(): array { function getAllAsOptions(): array {
return []; return [];

View file

@ -21,7 +21,7 @@ class Path
*/ */
public function __construct($path = '') public function __construct($path = '')
{ {
$this->url = parse_url($path) ?: []; $this->url = parse_url($path);
if (isset($this->url['path'])) { if (isset($this->url['path'])) {
$path = $this->url['path']; $path = $this->url['path'];
@ -60,7 +60,7 @@ class Path
*/ */
public static function basename($path) public static function basename($path)
{ {
$list = preg_split('#\\\\|/#s', $path) ?: ['']; $list = preg_split('#\\\\|/#s', $path);
return end($list); return end($list);
} }
@ -96,7 +96,7 @@ class Path
static function skipExtension(string $fileName): string static function skipExtension(string $fileName): string
{ {
$path = pathinfo($fileName); $path = pathinfo($fileName);
if (!isset($path['dirname']) || $path['dirname'] === ".") { if ($path['dirname'] === ".") {
return $path['filename']; return $path['filename'];
} else { } else {
return self::join($path['dirname'], $path['filename']); return self::join($path['dirname'], $path['filename']);
@ -120,12 +120,12 @@ class Path
* Преобразует строку пути в массив * Преобразует строку пути в массив
* *
* @param string $path Путь * @param string $path Путь
* @return list<string> * @return list<string>|false
*/ */
public static function listFromString(string $path): array public static function listFromString(string $path): array|false
{ {
$list = preg_split('#\\\\|/#s', $path); $list = preg_split('#\\\\|/#s', $path);
return $list ?: []; return $list;
} }
/** /**
@ -174,17 +174,17 @@ class Path
*/ */
public static function makeUrl($path): string public static function makeUrl($path): string
{ {
$slash = (isset($path['host']) && isset($path['path']) && (strlen($path['path']) > 0) && ($path['path'][0] != '/')) ? '/' : ''; $slash = (isset($path['host']) && (strlen($path['path']) > 0) && ($path['path'][0] != '/')) ? '/' : '';
$scheme = isset($path['scheme']) ? $path['scheme'] . ':/' : '';
$user = isset($path['user']) ? $path['user'] . (isset($path['pass']) ? ':' . $path['pass'] : '') . '@' : '';
$port = isset($path['port']) ? ':' . $path['port'] : ''; return (isset($path['scheme']) ? $path['scheme'] . ':/' : '')
$host = isset($path['host']) ? ('/' . $user . $path['host'] . $port) : ''; . (isset($path['host']) ? ('/'
. (isset($path['user']) ? $path['user'] . (isset($path['pass']) ? ':' . $path['pass'] : '') . '@' : '')
$query = isset($path['query']) ? '?' . $path['query'] : ''; . $path['host']
$fragment = isset($path['fragment']) ? '#' . $path['fragment'] : ''; . (isset($path['port']) ? ':' . $path['port'] : '')) : '')
. $slash
return $scheme . $host . $slash . ($path['path'] ?? '') . $query . $fragment; . ($path['path'] ?? '')
. (isset($path['query']) ? '?' . $path['query'] : '')
. (isset($path['fragment']) ? '#' . $path['fragment'] : '');
} }
/** /**

View file

@ -74,9 +74,7 @@ class User implements UserInterface
if ($result) { if ($result) {
$time = time(); $time = time();
$id = $this->id; $id = $this->id;
$this->db->executeQuery( $this->db->executeQuery("UPDATE users SET lasttime = $time WHERE id_user = $id"); // Время входа
"UPDATE users SET lasttime = :time WHERE id_user = :id",
['time' => $time, 'id' => $id]); // Время входа
} }
return $result; return $result;
} }

View file

@ -16,7 +16,10 @@ class Session
{ {
if (is_array($key)) { if (is_array($key)) {
$className = get_class($key[0]); $className = get_class($key[0]);
$_SESSION[strtolower($className ?: '')][$key[1]] = $value; /*if ($className === false) {
throw new \RuntimeException("Invalid class name " . $className);
}*/
$_SESSION[strtolower($className)][$key[1]] = $value;
} else { } else {
$_SESSION[$key] = $value; $_SESSION[$key] = $value;
} }

View file

@ -10,7 +10,6 @@
namespace ctiso; namespace ctiso;
use ctiso\Tools\SQLStatementExtractor; use ctiso\Tools\SQLStatementExtractor;
use ctiso\Path; use ctiso\Path;
use ctiso\File;
use SimpleXMLElement; use SimpleXMLElement;
class FakeZipArchive { class FakeZipArchive {
@ -27,7 +26,7 @@ class FakeZipArchive {
* @return string * @return string
*/ */
function getFromName($file) { function getFromName($file) {
return File::getContents(Path::join($this->base, $file)); return file_get_contents(Path::join($this->base, $file));
} }
} }

View file

@ -96,11 +96,11 @@ class StringUtil
/** /**
* Разбивает строку на массив символов * Разбивает строку на массив символов
* @param string $str * @param string $str
* @return array * @return array|false
*/ */
static function mb_str_split(string $str): array static function mb_str_split(string $str): array|false
{ {
return preg_split('~~u', $str, -1, PREG_SPLIT_NO_EMPTY) ?: []; return preg_split('~~u', $str, -1, PREG_SPLIT_NO_EMPTY);
} }
/** /**

View file

@ -196,16 +196,12 @@ class TemplateImage
return $text; return $text;
} }
/** function setSize(int $new_width, int $new_height): void
* @param int<1,max> $new_width
* @param ?int<1,max> $new_height
*/
function setSize(int $new_width, ?int $new_height = null): void
{ {
$width = imagesx($this->image); $width = imagesx($this->image);
$height = imagesy($this->image); $height = imagesy($this->image);
if ($new_height == null) { if ($new_height == null) {
$new_height = max(1, (int)ceil($height * $new_width / $width)); $new_height = ceil($height * $new_width / $width);
} }
// Resample // Resample

View file

@ -1,14 +1,13 @@
<?php <?php
namespace ctiso\Validator\Rule; namespace ctiso\Validator\Rule;
use ctiso\Collection; use ctiso\Collection;
abstract class AbstractRule abstract class AbstractRule
{ {
public string $field; public string $field;
protected ?string $errorMsg; protected ?string $errorMsg;
/** @var RuleContext */ /** @var object */
protected $ctx; protected $ctx;
public function __construct(string $field, ?string $errorMsg = null) public function __construct(string $field, ?string $errorMsg = null)
@ -49,7 +48,7 @@ abstract class AbstractRule
} }
/** /**
* @param RuleContext $ctx * @param object $ctx
*/ */
public function setContext($ctx): void public function setContext($ctx): void
{ {

View file

@ -4,9 +4,8 @@
* Проверка на число * Проверка на число
*/ */
namespace ctiso\Validator\Rule; namespace ctiso\Validator\Rule;
use ctiso\Validator\Rule\AbstractRule,
use ctiso\Validator\Rule\AbstractRule; ctiso\Collection;
use ctiso\Collection;
class Alpha extends AbstractRule class Alpha extends AbstractRule
{ {

View file

@ -1,10 +0,0 @@
<?php
namespace ctiso\Validator\Rule;
use ctiso\Collection;
use ctiso\HttpRequest;
interface RuleContext {
function getMessage(): string;
function isUnique(string $field, mixed $status, Collection $collection): bool;
}

View file

@ -3,9 +3,8 @@
/** /**
*/ */
namespace ctiso\Validator\Rule; namespace ctiso\Validator\Rule;
use ctiso\Validator\Rule\AbstractRule,
use ctiso\Validator\Rule\AbstractRule; ctiso\Collection;
use ctiso\Collection;
class Unique extends AbstractRule class Unique extends AbstractRule
{ {
@ -16,7 +15,7 @@ class Unique extends AbstractRule
public function isValid(Collection $container, $status = null): bool public function isValid(Collection $container, $status = null): bool
{ {
return $this->ctx->isUnique($container->getString($this->field), $status, $container); return $this->ctx->isUnique($container->get($this->field), $status, $container);
} }
} }

View file

@ -4,16 +4,15 @@
* Проверка коллекции * Проверка коллекции
*/ */
namespace ctiso\Validator; namespace ctiso\Validator;
use Exception; use Exception,
use ctiso\Validator\Rule\AbstractRule; ctiso\Validator\Rule\AbstractRule,
use ctiso\Validator\Rule\RuleContext; ctiso\Collection;
use ctiso\Collection;
/** /**
* @phpstan-type Rule array{ * @phpstan-type Rule array{
* validate?:string, // Описание правила см. формат правила ниже * validate:string, // Описание правила см. формат правила ниже
* name:string, // Имя переменой для проверки * name:string, // Имя переменой для проверки
* context?:RuleContext * context?:object
* } * }
*/ */
class Validator class Validator

View file

@ -24,18 +24,10 @@ class Composite extends View
} }
function set(string $key, mixed $val): void { function set(string $key, mixed $val): void {
if ($key == 'title') {
$this->setTitle($val);
}
$this->tal->set($key, $val); $this->tal->set($key, $val);
} }
function __set(string $key, mixed $val): void { function execute(): string {
$this->tal->set($key, $val);
}
function execute(): string
{
$this->processChild(); $this->processChild();
return $this->tal->execute(); return $this->tal->execute();
} }

33
src/View/Json.php Normal file
View file

@ -0,0 +1,33 @@
<?php
namespace ctiso\View;
class Json implements Template {
/** @var array */
private $_data = [];
/** @var string */
private $_file;
/**
* @param string $_file
*/
function __construct($_file) {
$this->_file = $_file;
}
function getFile(): string {
return $this->_file;
}
/**
* @param string $key
* @param mixed $value
*/
function set($key, $value): void {
$this->_data[$key] = $value;
}
function execute(): string {
return json_encode($this->_data) ?: '';
}
}

View file

@ -1,40 +0,0 @@
<?php
namespace ctiso\View;
class JsonView extends \stdClass {
/** @var array */
public $_data = [];
/** @var string */
public $_name = '';
/**
* @param string $name
*/
function __construct($name) {
$this->_name = $name;
}
/**
* @param string $key
* @param mixed $value
*/
function set($key, $value): void {
$this->_data[$key] = $value;
}
/**
* @param string $key
* @param mixed $value
*/
function __set($key, $value): void {
$this->_data[$key] = $value;
}
/**
* @return string
*/
function execute() {
return json_encode($this->_data) ?: '';
}
}

View file

@ -5,7 +5,7 @@ namespace ctiso\View;
/** /**
* Шаблон для PHP * Шаблон для PHP
*/ */
class Plain extends \stdClass class Plain implements Template
{ {
/** @var string */ /** @var string */
protected $document; protected $document;
@ -40,23 +40,13 @@ class Plain extends \stdClass
$this->values = array_merge($this->values, $list); $this->values = array_merge($this->values, $list);
} }
/**
* @param string $key ключ
* @param mixed $value значение
*/
public function __set($key, $value): void
{
$this->set($key, $value);
}
/** /**
* Выполнение шаблона * Выполнение шаблона
* @return string
*/ */
public function execute() public function execute(): string
{ {
$result = $this->values; $result = $this->values;
return self::getTemplateContent ($this->document, $result); return self::getTemplateContent($this->document, $result);
} }
/** /**

27
src/View/TalView.php Normal file
View file

@ -0,0 +1,27 @@
<?php
namespace ctiso\View;
use PHPTAL;
class TalView implements Template {
private PHPTAL $tal;
function __construct(string $file)
{
$this->tal = new PHPTAL($file);
$this->tal->setPhpCodeDestination(PHPTAL_PHP_CODE_DESTINATION);
$this->tal->setEncoding(PHPTAL_DEFAULT_ENCODING);
$this->tal->setTemplateRepository(PHPTAL_TEMPLATE_REPOSITORY);
$this->tal->setOutputMode(PHPTAL::HTML5);
$this->tal->stripComments(true);
}
function set(string $key, mixed $val): void {
$this->tal->set($key, $val);
}
function execute(): string {
return $this->tal->execute();
}
}

10
src/View/Template.php Normal file
View file

@ -0,0 +1,10 @@
<?php
namespace ctiso\View;
interface Template {
/** Установка значений шаблона */
function set(string $key, mixed $value): void;
/** Преобразование шаблона в строку */
function execute(): string;
}

View file

@ -6,15 +6,10 @@ use ctiso\View\Composite;
class Top extends Composite class Top extends Composite
{ {
/** /** @var int Счетчик для идентификторов */
* Общая строка заголовка private $mid = 0;
* @var int
*/
public $mid = 0;
/** @var array */ /** @var array */
public $require = []; public $require = [];
/** @var array */
public $deps = [];
/** @var \ctiso\Registry */ /** @var \ctiso\Registry */
public $config; public $config;
@ -57,7 +52,6 @@ class Top extends Composite
$this->set('stylesheet', array_unique($this->getStyleSheet())); $this->set('stylesheet', array_unique($this->getStyleSheet()));
$this->require = ['admin' => 'ma']; $this->require = ['admin' => 'ma'];
$this->deps = [];
$startup = []; $startup = [];
foreach ($this->_section as $s) { foreach ($this->_section as $s) {
@ -83,23 +77,9 @@ class Top extends Composite
foreach ($s->_values as $key => $v) { foreach ($s->_values as $key => $v) {
$script .= $value . "." . $key . " = " . json_encode($v /*, JSON_PRETTY_PRINT*/) . ";\n"; $script .= $value . "." . $key . " = " . json_encode($v /*, JSON_PRETTY_PRINT*/) . ";\n";
} }
$init = [];
/** @var View $item */
foreach ($s->_section as $key => $item) {
if ($item->codeGenerator !== null) {
// функцию которая вычисляет а не результат
$part = call_user_func($item->codeGenerator, $this, $key, $value);
$init[] = $part;
}
}
$script .= $value . ".execute('" . $s->module_action . "', " . json_encode($init) . ");\n";
$startup[] = $script; $startup[] = $script;
} }
$this->set('startup', implode("", $startup) . $this->getScriptStartup()); $this->set('startup', implode("", $startup) . $this->getScriptStartup());
$this->set('require', implode(",", array_map(function ($x) { $this->set('require', implode(",", array_map(function ($x) {
return "'$x'"; }, array_keys($this->require)))); return "'$x'"; }, array_keys($this->require))));

View file

@ -3,7 +3,7 @@
namespace ctiso\View; namespace ctiso\View;
use Exception; use Exception;
class View extends \stdClass class View implements Template
{ {
/** @var array<View|string> Вложенные шаблоны */ /** @var array<View|string> Вложенные шаблоны */
protected array $_section = []; protected array $_section = [];
@ -32,7 +32,7 @@ class View extends \stdClass
/** @var array<string, string|array<string, string>> */ /** @var array<string, string|array<string, string>> */
public array $alias = []; public array $alias = [];
// public $codeGenerator = null;
/** @var View|null */ /** @var View|null */
public $parent_view = null; public $parent_view = null;
@ -130,8 +130,7 @@ class View extends \stdClass
} }
*/ */
public function set(string $key, mixed $value): void
/*abstract*/ public function set(string $key, mixed $value): void
{ {
} }