┌── angiv/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Пользовательские компоненты Angiv CMF
│ ├── asset/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Статические ресурсы
│ │ ├── font/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Шрифты
│ │ ├── image/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Изображения
│ │ ├── language/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Переводы
│ │ └── lib/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Пользовательские стили, скрипты
│ ├── config/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Конфигурация
│ │ ├── config.env₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Файл конфигурации Angiv CMF
│ │ └── container.php₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Файл конфигурации PHP-DI контейнера
│ ├── helper/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Пользовательские вспомогательные функции
│ ├── middleware/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Пользовательское промежуточное ПО
│ │
│ ├── plugin/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Пользовательские плагины
│ │ └── .../₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Название плагина
│ │ ├── css/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Стили
│ │ ├── image/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Изображения
│ │ ├── js/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Скрипты
│ │ ├── src/controller/₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Контроллеры
│ │ ├── view/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Представления
│ │ ├── index.php₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Файл конфигурации
│ │ ├── icon.png₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Файл иконки
│ │ └── scriptdatabase.php₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Скрипт базы данных
│ │
│ ├── storage/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Хранилище файлов
│ ├── theme/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Шаблон
│ │ ├── css/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Стили
│ │ ├── js/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Скрипты
│ │ ├── page/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Страница 401, 403, 404
│ │ └── template.php₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Страница шаблона
│ └── tmp/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Временные файлы (лог, кэш)
│ ├── cache/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Cache компиляции контейнера
│ ├── log/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Журналирование событий
│ └── session/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Пользовательские сессии
│
│
├── app/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Системные компоненты Angiv CMF - содержимое не рекомендуется изменять
│ ├── admin/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Панель управления
│ │ ├── theme/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Шаблон
│ │ │ ├── css/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Стили
│ │ │ ├── js/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Скрипты
│ │ │ └── template.php₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Страница шаблона
│ │ ├── view/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Страницы панели управления
│ │ ├── route.php₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Первичная обработка
│ │ ├── routeauth.php₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Обработка авторизации
│ │ ├── routeadmin.php₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Обработка страниц панели управления
│ │ └── routeuser.php₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Обработка страниц сайта
│ ├── asset/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Статические ресурсы
│ │ ├── font/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Шрифты
│ │ ├── image/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Изображения
│ │ └── lib/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Системные стили, скрипты
│ ├── config/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Конфигурация PHP-DI контейнера
│ ├── helper/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Вспомогательные функции
│ ├── installer/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Плагин автоматической установки Angiv CMF
│ ├── middleware/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Промежуточное программное обеспечение
│ ├── response/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Вспомогательный http-ответ
│ ├── vendor/₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Сторонние управляющие пакеты
│ └── bootstrap.php₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Файл начальной загрузки
├── public/index.php₋₋₋₋₋₋₋₋₋₋₋₋ Единая точка входа
├── .htaccess₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Правила перенаправления Apache
├── composer.json₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Описание сторонних управляющих пакетов
├── robots.txt₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Директивы поисковых роботов
├── sitemap.xml₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Карта сайта
└── favicon.ico₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋₋ Файл иконки Angiv CMF
<?php
return [
// --------------- ПАРАМЕТРЫ ПЛАГИНА ---------------
'name' => 'Two sliders', // наименование
'icon' => 'icon.png', // иконка
'version' => 0.1, // версия
//'tags' => ['nohome', 'alwaysuse', 'nodelete'], // признаки
];
<?php return [
// --------------- ПАРАМЕТРЫ ПЛАГИНА --------------- 'name' => 'Two sliders', // наименование 'icon' => 'icon.png', // иконка 'version' => 0.1, // версия //'tags' => ['nohome', 'alwaysuse', 'nodelete'], // признаки
// --------------- ПАНЕЛЬ УПРАВЛЕНИЯ (ADMIN) --------------- 'cssadmin' => [], // стили плагина 'jsadmin' => [], // скрипты плагина 'ajaxadmin' => [], // ajax-запросы плагина 'pagesadmin' => [ // страницы плагина // ----- СТРАНИЦА SLIDER ----- [ 'title' => 'Page slider', // название страницы 'url' => 'adminpageslider', // url-адрес страницы 'controller' => 'src/controller/admin/pagesliderController.php', // контроллер страницы 'page' => 'view/admin/pageslider.php', // представление страницы 'css' => [], // стили страницы 'js' => [] // скрипты страницы ], ] ];
<?php
namespace Plugin\twosliders\src\controller\admin;
use Slim\Psr7\{
Request,
Response
};
use DI\Container;
class pagesliderController
{
protected $container;
public function __construct(Container $container)
{
$this->container=$container;
}
public function __invoke(Request $request, Response $response) {
// -----данные
$phpdata=['slider1.jpg', 'slider2.jpg', 'slider3.jpg', 'slider4.jpg', 'slider5.jpg'];
// -----результат
$renderer=$this->container->get('viewadmin'); // макет страницы
return $renderer->render($response, $renderer->getAttribute('currentpage'), ['phpdata' => $phpdata]); // шаблон страницы
}
}
<div class="uk-container">
<div uk-slider>
<ul class="uk-slider-items uk-child-width-1-2 uk-child-width-1-3@s uk-child-width-1-4@m uk-light">
<?php foreach ($phpdata ?? [] as $key => $item) { ?>
<li class="uk-transition-toggle" tabindex="0">
<img src="/angiv/plugin/twosliders/image/<?= $item ?>" alt="">
<div class="uk-position-center uk-panel"><h1 class="uk-transition-slide-bottom-small"><?= __('Slide') . ' ' . ($key + 1) ?></h1></div>
</li>
<?php } ?>
</ul>
<ul class="uk-slider-nav uk-dotnav uk-flex-center uk-margin"></ul>
</div>
</div>
'css' => [
// -----системные css ("/system/" = "\app\asset\lib\")
'/system/uikit/css/uikit.min.css',
// -----пользовательские css ("/custom/" = "\angiv\asset\lib\")
'/custom/lightgallery/css/lightgallery.css',
// -----css заданного пути (если не '/system/', '/custom/' и начинается с '/')
'/test.css',
// -----css страницы (путь - "\angiv\plugin\twosliders\")
'css/user/test.css'
],
'js' => [
// -----системные js ("/system/" = "\app\asset\lib\")
'/system/jquery/jquery.min.js',
// -----пользовательские js ("/custom/" = "\angiv\asset\lib\")
'/custom/lightgallery/js/lightgallery.min.js',
// -----js заданного пути (если не '/system/', '/custom/' и начинается с '/')
'/test.js',
// -----js страницы (путь - "\angiv\plugin\twosliders\")
'js/user/test.js'
]
К примеру:
'/system/uikit/css/uikit.min.css' - преобразуется в - <link rel="stylesheet" type="text/css" href="/app/asset/lib/uikit/css/uikit.min.css">
'/custom/lightgallery/css/lightgallery.css' - преобразуется в - <link rel="stylesheet" type="text/css" href="/angiv/asset/lib/lightgallery/css/lightgallery.css">
'/test.css' - преобразуется в - <link rel="stylesheet" type="text/css" href="/test.css">
'css/user/test.css' - преобразуется в - <link rel="stylesheet" type="text/css" href="/angiv/plugin/hello/css/user/test.css">
'/system/jquery/jquery.min.js' - преобразуется в - <script type="text/javascript" src="/app/asset/lib/jquery/jquery.min.js"></script>
'/custom/lightgallery/js/lightgallery.min.js' - преобразуется в - <script type="text/javascript" src="/angiv/asset/lib/lightgallery/js/lightgallery.min.js"></script>
'/test.js' - преобразуется в - <script type="text/javascript" src="/test.js"></script>
'js/user/test.js' - преобразуется в - <script type="text/javascript" src="/angiv/plugin/twosliders/js/user/test.js"></script>
<!-- массив css -->
['href' => 'test.css'] - преобразуется в - <link rel="stylesheet" type="text/css" href="/angiv/plugin/hello/css/user/test.css">
['href' => '/system/uikit/css/uikit.min.css', 'attr' => 'async'] - преобразуется в - <link rel="stylesheet" type="text/css" href="/app/asset/lib/uikit/css/uikit.min.css" media="none" onload="if(media!='all'){media='all';this.onload=null;}"><noscript><link rel="stylesheet" type="text/css" href="/app/asset/lib/uikit/css/uikit.min.css"></noscript>
<!-- массив js -->
['src' => 'test.js'] - преобразуется в - <script type="text/javascript" src="test.js"></script>
['src' => 'test.js', 'attr' => 'defer'] - преобразуется в - <script type="text/javascript src="test.js" defer></script>
['src' => 'test.js', 'attr' => 'async'] - преобразуется в - <script type="text/javascript src="test.js" async></script>
['type' => 'module', 'src' => 'test.js'] - преобразуется в - <script type="module" src="test.js"></script>
['type' => 'module', 'src' => 'test.js', 'attr' => 'async'] - преобразуется в - <script type="module" src="test.js" async></script>
<?php
return [
// --------------- САЙТ (USER) ---------------
'cssuser' => [], // стили плагина
'jsuser' => [], // скрипты плагина
'ajaxuser' => [], // ajax-запросы плагина
'pagesuser' => [ // страницы плагина
// ----- СТРАНИЦА SLIDER -----
[
'title' => 'Page slider', // название страницы
'url' => 'userpageslider', // url-адрес страницы
'controller' => 'src/controller/user/pagesliderController.php', // контроллер страницы
'page' => 'view/user/pageslider.php', // представление страницы
'css' => [], // стили страницы
'js' => [], // скрипты страницы
'seo' => [, // поисковая оптимизация
'description' => '', // описание
'keywords' => '', // ключевые слова
'canonicalurl' => '', // канонический url
],
'ogseo' => [, // open graph поисковая оптимизация
'ogsitename' => '', // расширенное название
'ogdescription' => '', // описание
'ogtype' => '', // тип содержимого
'ogurl' => '', // канонический url
'ogimage' => '', // изображение публикации
]
],
]
];
<?php
'database' => function (Container $container) {
return (envbool('APP_DATABASE_USE') === true) ? ( // если использование базы данных
new Medoo([
'type' => 'mysql', // тип базы данных
'host' => env('APP_DATABASE_HOST', 'localhost'), // имя сервера или ip-адрес
'database' => env('APP_DATABASE_NAME', 'angiv'), // имя базы данных
'username' => env('APP_DATABASE_USER', 'username'), // имя пользователя
'password' => env('APP_DATABASE_PASSWORD', 'userpassword'), // пароль пользователя
'prefix' => env('APP_DATABASE_PREFIX', 'ang_'), // префикс таблиц
'charset' => 'utf8', // кодировка
'error' => PDO::ERRMODE_EXCEPTION, // тип обработки ошибок(https://medoo.in/api/error)
//'logging' => true // ведение журнала логирования всех sql-запросов
])
) : null;
}
<?php
return [
// --------------- ПАРАМЕТРЫ ПЛАГИНА ---------------
'name' => 'Two sliders', // наименование
'icon' => 'icon.png', // иконка
'version' => 0.1, // версия
//'tags' => ['nohome', 'alwaysuse', 'nodelete'], // признаки
'scriptdatabase' => 'scriptdatabase.php', // Скрипт базы данных
<?php
namespace Plugin\hello;
use Slim\Psr7\Response;
use App\response\customResponse;
class scriptdatabase
{
// --------------- СКРИПТ БАЗЫ ДАННЫХ ---------------
public static function executescriptdatabase(Response $response) {
$res=false; $msg='';
// --------------- СОЗДАНИЕ ТАБЛИЦЫ ---------------
if (!empty($db=$GLOBALS['app']->getContainer()->get('database'))) { // подключение к базе данных
$tablename=str_replace('"', '', $db->tableQuote('hello')); // название таблицы
//$tablename=env('APP_DATABASE_PREFIX', 'ang_') . 'hello';
if ($db->query("SHOW TABLES LIKE '{$tablename}'")->fetchColumn() === false) { // проверка существования таблицы
//$db->drop('hello');
$db->create('hello', [
// -----поля
'id' => ['integer', 'unsigned', 'auto_increment', 'not null', "comment 'id client'"],
'name' => ['varchar(255)', 'not null', 'collate utf8mb4_general_ci', "comment 'name client'"],
'age' => ['integer', 'unsigned', 'default null', "comment 'age client'"],
// -----первичный ключ
'primary key (...)',
// -----уникальные индексы
'unique (...)',
// -----индексы
'index (...)'
]);
$res=true;
} else {$msg=sprintf(__('Table "%s" already exists'), $tablename);}
} else {$msg=__('Connection to database failed');}
// -----результат
return customResponse::json($response, ['res' => $res, 'msg' => $msg]);
}
}
...
<button class="ang-button ang-margin-left10" @click.prevent="sendmessage()">{{ $t('Send') }}</button>
...
sendmessage: function() {
axios.post('/feedback/savemessagetext', {'messagetext': vm.messagetext})
.then(function(response) {
if (response.data.res === true) {
//ajax-request successfully
} else {
//ajax-request warning
}
})
.catch(function(error) {
//ajax-request error
});
},
<?php
public static function savemessagetext(Request $request, Response $response) {
$data=$request->getParsedBody();
try {
$res=false; $msg='';
if (!empty($db=$GLOBALS['app']->getContainer()->get('database'))) {
$tablename=str_replace('"', '', $db->tableQuote('feedback'));
if ($db->query("SHOW TABLES LIKE '{$tablename}'")->fetchColumn() !== false) {
$phpjwtdata=null;
if (!empty($request->getAttribute('jwtdata'))) {
$phpjwtdata=$request->getAttribute('jwtdata');
} else {
if (isset($_COOKIE['accesstoken'])) {
$phpjwtdata=JWT::decode($_COOKIE['accesstoken'], new Key(env('APP_AUTH_SECRET', ''), 'HS256'));
}
}
if (!empty($phpjwtdata)) {
if (!empty($currentlogin=$phpjwtdata->data->authlogin)) {$data['petitioner']=strtolower($currentlogin);}
}
$db->insert('feedback', $data);
if (!$db->error) {$res=true;}
} else {$msg=__('Connection to database failed');}
} else {$msg=__('Connection to database failed');}
return customResponse::json($response, ['res' => $res, 'msg' => $msg]);
} catch (\Exception $e) {
return customResponse::abort($e->getMessage(), $request);
}
}
...
<?= $this->fetch('/hello/view/user/widgetuikit.php') ?>
...
<?= $this->fetch('/feedback/view/user/widgetfeedback.php') ?>
'pagesadmin' => [
[
'title' => 'Page vue',
'url' => 'adminpagevue',
'controller' => 'src/controller/user/pageuikitController.php',
'page' => 'view/user/pageuikit.php',
//'access' => ['auth', 'hello_page_view'],
'css' => [],
'js' => []
],
class ajaxuserController
{
/**
* @route({"url": "getusertext[/{id}]", "methods": ["post"], "csrf": true, "access": ["hello_ajax_exec"]})
*/
public static function getusertext(Request $request, Response $response, $id = '') {
$params=$request->getQueryParams();
$data=$request->getParsedBody();
try {
//$container=$GLOBALS['app']->getContainer();
$res=['res' => true, 'text user' => __('Example text'), 'id' => $id, 'params' => $params, 'data' => $data];
return customResponse::json($response, $res);
} catch (\Exception $e) {
return customResponse::abort($e->getMessage(), $request);
}
}
}
<?php
'session' => function () {
$session=new SessionMiddleware([
'name' => 'sessiondata', // имя сессии
'lifetime' => 31536000, // время истечения срока действия cookie (0 - при закрытии браузера)
'path' => '/', // url из которого будут доступны cookie
//'domain' => 'angiv', // домен, которому принадлежит cookie
'httponly' => true, // запрет доступа для клиентских скриптов
'secure' => true, // отправление только через https
'cache_limiter' => 'nocache' // режим кеширования
]);
$session->start();
return $session;
},
<?php
namespace Plugin\hello\src\controller\user;
use Slim\Psr7\{
Request,
Response
};
use App\response\customResponse;
class ajaxuserController
{
/**
* @route({"url": "getusertext[/{id}]", "methods": ["post"], "csrf": true, "access": ["hello_ajax_exec"]})
*/
public static function getusertext(Request $request, Response $response, $id = '') {
$params=$request->getQueryParams();
$data=$request->getParsedBody();
try {
//$container=$GLOBALS['app']->getContainer();
$res=['res' => true, 'text user' => __('Example text'), 'id' => $id, 'params' => $params, 'data' => $data];
return customResponse::json($response, $res);
} catch (\Exception $e) {
return customResponse::abort($e->getMessage(), $request);
}
}
}
$pagereg = function ($plugin, $page, $view) use ($app, $container) {
...
// -----промежуточное ПО
$route->add($container->get('csrf')); // 3) csrf защита
...
$route->add(new rendererMiddleware($container, $view, $plugin, $page)); // 4) предварительный рендеринг шаблона
};
...
if ($method['csrf'] === true) {$route->add($container->get('csrf'));}
...
public function __invoke(Request $request, RequestHandler $handler) {
...
// -----csrf
$phpcsrf=(!empty($request) ? $request->getAttribute('csrf_name', '') . '|' . $request->getAttribute('csrf_value', '') : '|'); // получение csrf
$renderer->addAttribute('phpcsrf', '"' . (($phpcsrf == '|') ? '' : $phpcsrf) . '"');
...
}
<head>
...
<script>window.$csrf=<?= $phpcsrf ?>;</script>
<script type="text/javascript" src="/app/asset/lib/axios/axios.min.js"></script>
<script type="text/javascript" src="/app/asset/lib/axios/axios-advanced.js"></script>
...
</head>
// --------------- ПЕРЕХВАТ ЗАПРОСА ---------------
axios.interceptors.request.use(function (request) {
if (!!window.$csrf) {request['headers']['csrf']=window.$csrf;} // передача csrf
});
// --------------- ПЕРЕХВАТ ОТВЕТА ---------------
axios.interceptors.response.use(
function (response) {
...
if (!!response['headers']['csrf']) {window.$csrf=response['headers']['csrf'];} // получение (обновление) csrf
...
},
function (error) {
...
if (!!error.response.data.csrf) {window.$csrf=error.response.data.csrf;} // получение (обновление) csrf
...
}
);