Иногда требуется информация от админа. То есть не просто юзера, а юзера именно из админки. Для это используется класс BackendAuth.
use Backend\Facades\BackendAuth;
BackendAuth::check() // true false проверка на юзера
BackendAuth::user() // вся информация о юзере
BackendAuth::user()->id // конкретное поле
Соответсвенно можете вытянуть любую нужную информацию
Например есть тестовый проект. В нем «магазин с товарами».
Я буду описывать кейс, когда уже есть лист продуктов. И только потом решили добавить сортировку. Это отличается тем, что у моих продуктов отсутствует ReorderController. При создании новой сущности, указываете, чтобы он был доступен.
При указании данного параметра создадутся вьюшка и некоторые настройки контроллера. У меня этого нет, поэтому буду делать вручную, заодно детальней.
Сначала указываю настройки reorder в контроллере, подключаю Behaivor и файл yaml.
<?php namespace Alex\Store\Controllers;use Backend\Classes\Controller;
use BackendMenu;class Prod extends Controller
{
public $implement = [
'Backend\Behaviors\ListController',
'Backend\Behaviors\FormController',
'Backend\Behaviors\ReorderController', // добавил
];
public $listConfig = 'config_list.yaml';
public $formConfig = 'config_form.yaml';
public $reorderConfig = 'config_reorder.yaml'; // добавил public function __construct()
{
parent::__construct();
BackendMenu::setContext('Alex.Store', 'main-menu-item');
}
}
Далее вставляю config_reorder.yaml в папке /controllers/prod. Соотв указываю заголовок, модель. NameForm скажу чуть позже для чего.
title: 'Сортировка продуктов'
modelClass: Alex\Store\Models\Prod
nameFrom: title
toolbar:
buttons: reorder_toolbar
Добавляем собственно вьюшку reorder.htm в туже папку с нашим контроллером /controllers/prod, так как сортировка происходит на отдельной странице.
Собственно этой всей настройки можно было избежать и октобер бы сам сгенерировал как надо, при указании галочки ReorderBehavior, о чем говорил в самом начале.
Кнопка появилась, но при переходе с нее возникает ошибка, говорящая о том, что мы еще не добавили в модель Трейт сортировки.
Добавляем в нашу модель.
use \October\Rain\Database\Traits\Sortable; // Для Sortable
И далее, чтобы этот трейт корректно отрабатывал нашей моделе и соотв таблице нужно поле sort_order. Добавляем его. Тип число, nullable true.
Отлично. Заходим в сортировку. И лично у меня это выглядит так. Есть итемы, но они пустые. Это собственно поле nameForm, которое указывается в config_reorder.yaml. У меня было написано title, хотя исходя из моей таблицы нужно указать name.
Указал name. Результат
!Есть один нюанс. Он касается поля sort_order. В идеале это все делать на новой сущности. Но если мы редактируем существующую, то у поля sort_order будет стоять 0 или Null в таблице. Как было подмечено в статье https://octoclub.ru/d/21-sortable-simple-tree-nested-tree надо в ручном режиме проставить валидные значения для текущих итемов.
В моем случае все не сложно и выглядит так.
Отлично. Все почти готово. Для примера я хочу выделить классный Сыр и поставить его первым. При стандартном получении из модели, сортировка происходит автоматически.
// это из компонента Prod
public function init()
{
$this->items = ProdModel::get();
}
Результат
Если же вы получаете итемы другими способами, то может указать дополнительно orderBy по полю sort_order.
В первой части обсудили постановку задачи. Я привел источники, на которые можно опираться, обсудили что нам потребуется и так же сделали простой перевод статических частей сайта. Теперь перейдем к более нетривиальной задаче.
Перевод кастомных компонентов и данных из моделей
Давайте установим Билдер, чтобы сделать небольшой плагин. https://octobercms.com/plugin/rainlab-builder
В нашей демо версии создадим мини каталог-магазин.
Не будем заморачиваться, добавим простые поля товара. Нам этого хватит.
Отлично. Уж извините 🙂 ничего быстрее не придумал, но буду продавать картошку и помидоры и еще что-нибудь. НО! интернационально на всех языках. Поэтому это круто. Сделал пару товаров.
Добавлю компонентик с помощью которого выведу информацию на фронтенд. Код:
<?php
namespace Alex\Store\Components;
use Cms\Classes\ComponentBase;
use Alex\Store\Models\Prod as ProdModel;
class Prod extends ComponentBase
{
public $items;
public function init()
{
}
public function onRun()
{
}
public function componentDetails()
{
return [
'name' => 'Products',
'description' => 'Some Products'
];
}
public function defineProperties()
{
return [
];
}
}
Регистрируем компонент и выводим.
Plugin.php
<?php namespace Alex\Store;
use System\Classes\PluginBase;
class Plugin extends PluginBase
{
public function registerComponents()
{
return [
'Alex\Store\Components\Prod' => 'prods'
];
}
public function registerSettings()
{
}
}
И пока что как мы видим появилась страничка. Продукты еще не вывелись. Давайте их перекинем с бэка.
public function onRun()
{
$this->items = ProdModel::get();
}
Как то так.
Все хорошо. Только продукты я вывел на русском. Хотя мы договорились, что дефолтный язык будет английским. Это я поправлю. Теперь надо подумать как локализовать данные из компонента. Точнее как локализовать модель. Изначально я делал не столь гибко, тк не до конца разобрался. Я пошел по пути дополнения полей в модель. Это раздуло таблицу и к тому же вышло не гибко. У меня был случай на 2 языка. А что если их будет 2-5 десять?
Поэтому у RainlabTranslate реализован более гибкий подход. Мы будем использовать трейт для имплементации функционала перевода.
class Prod extends Model
{
use \October\Rain\Database\Traits\Validation;
public $implement = ['RainLab.Translate.Behaviors.TranslatableModel'];
public $translatable = ['name','descr'];
Добавили трейт и указали поля для перевода. В итоге получили дефолтный функционал.
И при этом наша таблица осталась с теми же полями, но добавилась отдельная таблица Rainlab с атрибутами.
Отлично. Теперь под дефолтной локалью, кою я поменял на En выводятся товары на английском, под ru соответственно на русском.
Стоит добавить локализацию для валюты и цены. Тогда будет совсем ок.
Что ж таким образом можно переводить контент из моделей для любых кастомных плагинов. Узкие места и нюансы, я возможно допишу позже.
В данной статье я опишу мой подход к локализации сайта, который я довольно успешно применил. Я просмотрел практически всю информацию на данную тему и преобразовал ее под свои нужды. Мой подход далеко не идеальный, поэтому делитесь замечаниями и вариантами доработок, возможно мы улучшим статью.
Данный гайд основывается на версии 1, но думаю и для второй будет актуален.
В списке выше есть источник тут и тут, который прекрасно описывает как локализовать сайт, если используются стандартные плагины RainlabBlog и RainlabStaticPages. Я же буду говорить о примере, когда данные плагины практически не используются и сайт делается на своих компонентах, что я наблюдаю гораздо чаще.
Постановка задачи
локализация статического контента
локализация динамического контента в плагинах и компонентах
В моем случае я использовал смежный функционал двух плагинов: RainlabTranslate и ContentEditor. Далее я объясню как их использовать и для чего каждый.
Локализация статики
Я буду показывать на demo теме октября. Ее переводом мы и займемся.
Локализации статики — это самое простое. Для этого я использовал ContentEditor. Во первых это удобно для клиента, а во вторых он замечательно расширяется RainlabTranslate.
После установки переходим в настройку Транслейта и устанавливаем языки. Их название и локали.
Я добавил русский и сделал его по умолчанию.
Отлично. Теперь у нас доступен режим подраздела для наших локалей. Можем перейти и попробовать: http://localhost:8888/ru и http://localhost:8888/en. Пока что никаких изменений.
Теперь задаем контент эдитор. Суть плагина в том, что мы оборачиваем контент в паршил, которые хранятся в директории контента themes/demo/content. Расширение транслейта происходит за счет того, что у нас создаются поддиректории для каждого языка автоматом.
Для контент эдитора я использую твиг тег такого вида:
Отлично у нас появилась кнопка редактирования и область контента стала подсвеченной.
Теперь можем отредактировать контент под разными локалями http://localhost:8888/ru и http://localhost:8888/en. Кстати я передумал 🙂 основной язык все таки будет английский а переводить будем на русский. Поэтому на локаль en оставляем без изменений, а на локали ru переводим. Как то так.
Таким же способом можно перевести и другие блоки достаточно внезависимости от сложности верстки. Тоже самое касается других страниц. При этом если мы посмотрим на директорию контент, то увидим rulang папку. Так же будет и с остальными языками.
Плюсы: — удобно для пользователя — игнорируется сложность верстки — редактирование любых страниц без использования StaticPages плагина — сколько угодно языков
Минусы — шаблон дробится на вставки из контент эдитора, что усложняет поиск элементов.
Есть список, в моем случае например товаров. Необходимо добавить какое-либо действие для обработки списка. Мне было необхдимо сделать функционал клонирования товара.
Мы идем в директорию с плагином и собственно с контроллером, который модифицируем. У меня для примера /alex/catalog/controllers/Products.php Так же нам понадобиться шаблон тулбара.
Тут уже кнопка у меня добавлена. Изначально шаблон был без нее. Шаблон находим /alex/catalog/controllers/products/_list_toolbar.htm
Как видно в шаблоны указаны все кнопки в том числе и новую мной созданную «Скопировать». На нее ставим data-request=«Ваш обработчик» и фунцкию onclick, я взял с копки удаления. Суть js забирать id-ники чекнутых итемов и передавать их на экшн.
Идем далее. Возвращаемся к контроллеру и прописываем обработчик.
/**
* @return
* Копирование товара
*/
public function onCopy() {
// Проверка на чекнутые товары
if (($checkedIds = post('checked')) && is_array($checkedIds) && count($checkedIds)) {
// Первый чекнутый // Делаем действия либо с одним
// $copy_id = post("checked")[0];
// Либо делаем действие со списком ID
foreach ($checkedIds as $checkedId) {
// Делаем дела ...........
}
Flash::success('Товар скопирован');
}
return $this->listRefresh();
}
Я обрабатывал только первый чекнутый. То есть у меня он в принципе должен быть выбрать один. Вы можете обработать несколько. На выходе я вывожу Флэш сообщение и перезагружаю список. Собственно все.
Когда я делал поля как обычно используя Page Builder, я наткнулся на ошибку: Model Alexdzen\Content\Models\Brands’ does not contain a definition for ‘image’.
Спросил в чате, оказалось, что добавления поля картинки не столь очевидно как хотелось бы.
Наше значение не указывается в таблице как поле.
Допустим моя задача сделать галлерею. Таблица состоит из Id и Image. Image — не указываем в таблице. Мы идем в нашу модель, в моем случае это Brands.php и прописываем поле image через attachOne (или attachMany).
<?php namespace Alexdzen\Content\Models;
use Model;
/**
* Model
*/
class Brands extends Model
{
use \October\Rain\Database\Traits\Validation;
/*
* Disable timestamps by default.
* Remove this line if timestamps are defined in the database table.
*/
public $timestamps = false;
/**
* @var string The database table used by the model.
*/
public $table = 'alexdzen_content_brands';
/**
* @var array Validation rules
*/
public $rules = [
'image' => 'required',
];
public $attributeNames = [
'image' => 'Картинка',
];
public $attachOne = [
'image' => 'System\Models\File'
];
}
Соответсвенно в form.yml указываем наше поле из модели.
Ну и чтобы картинка отображался в на странице Контроллера прописываем image. Значение поля я ставлю partial и путь указываю $/alexdzen/content/partials/_image3.htm.
Допустим у вас появилась задача похожую на мою. Мне было необходимо подделать метод onActivate. Соответсвенно, если мы сделаем это напрямую в плагине в классе Account, то через последующее обновление наши изменения сотрутся.
Поэтому мы идем следующем путем.
У нас есть компонент login.htm. Изначально он использует компонент Account.php Rainlab.
Допустим у вас Плагин Myplugin. В нем мы создадим свой Аккаунт компонент и отнаследуем от Rainlab.
<?php namespace Alexti\Myplugin\Components;
class Account2 extends \RainLab\User\Components\Account
{
public function componentDetails()
{
return [
'name' => 'Account2',
'description' => 'Account2'
];
}
/**
* Activate the user
* @param string $code Activation code
*/
public function onActivate($code = null)
{
// do something
}
}
Соответсвенно наш компонент надо зарегистрировать в Plugin.php
public function registerComponents()
{
return [
'Alexti\Myplugin\Components\Account2' => 'Account2',
]
}
Все готово. Теперь Account будет отрабатывать как обычно, но методы которые мы заоверайдили будут отрабатывать в нашем компоненте. И соответсвенно по всех шаблонах необходимо подключить наш компонент.
Пример на стандартном плагине Blog от RainLab. Допустим надо вывести посты не на страничке «все посты», а на другой и допустим не все количество? а только 15-ть.
Для этого вы воспользуемся классом плагина Post, непосредственно в нужной нам страничке в php блоке в хуке onStart. Получим все посты и занесем в переменную posts.
==
use RainLab\Blog\Models\Post;
function onStart()
{
$this['posts'] = Post::orderBy('created_at', 'desc')->get();
}
==
Далее с этой переменной делаем что нам необходимо. Во первых получим первые 15ть постов, во вторых через twig выведем их название в цикле.
==
use RainLab\Blog\Models\Post;
function onStart()
{
$this['posts'] = Post::orderBy('created_at', 'desc')->limit(15)->get();
}
==
{% for post in posts %}
{{post.title}}
{% endfor %}
October — это бесплатная самостоятельная платформа CMS с открытым исходным кодом, основанная на PHP-фреймворке Laravel. Эта статья научит вас, как развернуть October CMS с помощью docker, но если вы хотите получить дополнительную информацию об использовании October CMS, то я бы рекомендовал перейти на страницу туториалов.
Разверните сервер Ubuntu 18.04 с объемом оперативной памяти не менее 1 ГБ. Добавьте немного подкачки, если вы находитесь на чем-то вроде DigitalOcean, который использует локальные твердотельные накопители.
Шаги
Разверните сервер Ubuntu 18.04 с объемом оперативной памяти не менее 1 ГБ.