Инициализация

@version 29.12.2018
@author  Дмитрий Щербаков <atomcms@ya.ru>
555244
static function init()
    {
        if (SettingsDatabase::NEED_CONNECT) {
            $connection_string = 'mysql:host=' . SettingsDatabase::HOST . ';port=' . SettingsDatabase::PORT . ';dbname=' . SettingsDatabase::DBNAME;

            ORM::configure('connection_string', $connection_string);
            ORM::configure('username', SettingsDatabase::USERNAME);
            ORM::configure('password', SettingsDatabase::PASSWORD);
            ORM::configure('logging', SettingsDatabase::LOGGING);
            ORM::configure('driver_options', [
                PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
            ]);
        }
    }
664421
function sectionIndex()
    {
        /** @var TAdminUI $page */
        $page = Eresus_Kernel::app()->getPage();
        $root = Eresus_CMS::getLegacyKernel()->root.'admin.php?mod=pages&amp;';
        $this->cache['index_controls'] =
            $page->control('setup', $root.'id=%d') . ' ' .
            $page->control('position',
                array($root.'action=up&amp;id=%d',$root.'action=down&amp;id=%d')) . ' ' .
            $page->control('add', $root.'action=create&amp;owner=%d') . ' ' .
            $page->control('move', $root.'action=move&amp;id=%d') . ' ' .
            $page->control('delete', $root.'action=delete&amp;id=%d');
        $types = $this->loadContentTypes();
        for ($i=0; $i<count($types[0]); $i++)
        {
            $this->cache['content_types'][$types[1][$i]] = $types[0][$i];
        }
        $table = new AdminList;
        $table->setHead(array('text'=>'Раздел', 'align'=>'left'), 'Имя', 'Тип', 'Доступ', '');
        $table->addRow(array(admPagesRoot, '', '', '',
            array($page->control('add', $root.'action=create&amp;owner=0'), 'align' => 'center')));
        $table->addRows($this->sectionIndexBranch(0, 1));
        $result = $table->render();
        return $result;
    }
1240414
private function create()
    {
        $sections = $this->menuBranch();
        array_unshift($sections[0], 'ВСЕ РАЗДЕЛЫ');
        array_unshift($sections[1], 'all');
        $form = array(
            'name' => 'formCreate',
            'caption' => 'Добавить баннер',
            'width' => '600px',
            'fields' => array(
                array('type' => 'hidden', 'name' => 'action', 'value' => 'insert'),
                array('type' => 'edit', 'name' => 'caption', 'label' => '<b>Заголовок</b>',
                    'width' => '100%', 'maxlength' => '255', 'pattern' => '/.+/',
                    'errormsg' => 'Заголовок не может быть пустым!'),
                array('type' => 'listbox', 'name' => 'section', 'label' => '<b>Разделы</b>', 'height' => 5,
                    'items' => $sections[0], 'values' => $sections[1]),
                array('type' => 'edit', 'name' => 'block', 'label' => '<b>Блок баннера</b>',
                    'width' => '100px', 'maxlength' => 31,
                    'comment' => 'Для вставки баннера используйте макрос <b>$(Banners:имя_блока)</b>',
                    'pattern' => '/.+/', 'errormsg' => 'Не указан блок баннера!'),
                array('type' => 'edit', 'name' => 'priority', 'label' => 'Приоритет', 'width' => '20px',
                    'comment' => 'Если для одного раздела и одного блока задано несколько баннеров, будет ' .
                        'показан с большим приоритетом',
                    'default' => 0, 'pattern' => '/\d+/', 'errormsg' => 'Приоритет задается только цифрами!'),
                array('type' => 'edit', 'name' => 'showFrom', 'label' => 'Начало показов',
                    'width' => '100px', 'comment' => 'ГГГГ-ММ-ДД', 'default' => gettime('Y-m-d'),
                    'pattern' => '/[12]\d{3,3}-[01]\d-[0-3]\d/', 'errormsg' => 'Неправильный формат даты!'),
                array('type' => 'edit', 'name' => 'showTill', 'label' => 'Конец показов',
                    'width' => '100px', 'comment' => 'ГГГГ-ММ-ДД; Пустое - без ограничений',
                    'pattern' => '/([12]\d{3,3}-[01]\d-[0-3]\d)|(^$)/',
                    'errormsg' => 'Неправильный формат даты!'),
                array('type' => 'edit', 'name' => 'showCount', 'label' => 'Макс. кол-во показов',
                    'width' => '100px', 'comment' => '0 - без ограничений', 'default' => 0,
                    'pattern' => '/(\d+)|(^$)/', 'errormsg' => 'Кол-во показов задается только цифрами!'),
                /*array ('type' => 'edit', 'name' => 'mail', 'label' => 'e-mail владельца',
                    'width' => '200px', 'maxlength' => '63'),*/
                array('type' => 'checkbox', 'name' => 'active', 'label' => 'Активировать',
                    'default' => true),
                array('type' => 'header', 'value' => 'Свойства баннера'),
                array('type' => 'file', 'name' => 'image', 'label' => 'Картинка или Flash', 'width' => '50'),
                array('type' => 'edit', 'name' => 'width', 'label' => 'Ширина', 'width' => '100px',
                    'comment' => 'только для Flash'),
                array('type' => 'edit', 'name' => 'height', 'label' => 'Высота', 'width' => '100px',
                    'comment' => 'только для Flash'),
                array('type' => 'edit', 'name' => 'url', 'label' => 'URL для ссылки', 'width' => '100%',
                    'maxlength' => '255'),
                array('type' => 'select', 'name' => 'target', 'label' => 'Открывать',
                    'items' => array('в новом окне', 'в том же окне')),
                array('type' => 'header', 'value' => 'HTML-код баннера'),
                array('type' => 'memo', 'name' => 'html',
                    'label' => 'HTML-код (Если задан HTML-код, то предыдущие свойства игнорируются и могут ' .
                        'не заполняться)',
                    'height' => '4'),
            ),
            'buttons' => array('ok', 'cancel'),
        );

        /** @var TAdminUI $page */
        $page = Eresus_Kernel::app()->getPage();
        $result = $page->renderForm($form);
        return $result;
    }
62599
public function editAction()
    {
        /** @var Menus_Entity_Table_Menu $table */
        $table = ORM::getTable($this->plugin, 'Menu');
        /** @var Menus_Entity_Menu $menu */
        $menu = $table->find(arg('id', 'int'));

        if (is_null($menu))
        {
            return 'Такое меню не найдено.';
        }

        $req = Eresus_CMS::getLegacyKernel()->request;

        if ('POST' == $req['method'])
        {
            $menu->name = arg('name', 'word');
            $menu->caption = arg('caption', 'dbsafe');
            $menu->active = true;
            $menu->root = arg('root', 'int');
            $menu->rootLevel = arg('rootLevel', 'int');
            $menu->invisible = arg('invisible', 'int');
            $menu->expandLevelAuto = arg('expandLevelAuto', 'int');
            $menu->expandLevelMax = arg('expandLevelMax', 'int');
            $menu->dropDown = arg('dropDown', 'int');
            $menu->template = arg('template', 'dbsafe');

            $test = $table->findByName($menu->name);
            if (is_null($test) || $test->id == $menu->id)
            {
                $table->update($menu);
                HTTP::redirect('admin.php?mod=ext-menus&id=' . $menu->id);
            }
            else
            {
                ErrorMessage('Меню с таким именем уже есть');
            }
        }

        $form = new EresusForm($this->plugin->templates()->adminPath('form.html', false));
        $form->setValue('sections', $this->adminSectionBranch());
        $form->setValue('action', 'edit');
        $form->setValue('menu', $menu);
        $html = $form->compile();

        return $html;
    }
1125165
function init()
    {
        $this->_a['table'] = 'cms_terms';
        $this->_a['cols'] = array(
            // ID
            'id' => array(
                'type' => 'Pluf_DB_Field_Sequence',
                'blank' => false,
                'verbose' => 'first name',
                'help_text' => 'id',
                'editable' => false
            ),
            // Fields
            'name' => array(
                'type' => 'Pluf_DB_Field_Varchar',
                'is_null' => false,
                'size' => 200,
                'default' => '',
                'editable' => true
            ),
            'slug' => array(
                'type' => 'Pluf_DB_Field_Varchar',
                'is_null' => false,
                'size' => 200,
                'default' => '',
                'editable' => true
            ),
            /*
             * Foreign keys
             */
        );
    }
552606
public function validate()
    {
        $registers = $this->getRegisters();
        $triggerFunctions = $this->getTriggerFunctions();
        $globalActions = $this->getGlobalActions();
        $initialActions = $this->getInitialActions();
        $commonActions = $this->getCommonActions();
        $steps = $this->getSteps();
        $splits = $this->getSplits();
        $joins = $this->getJoins();


        ValidationHelper::validate($registers);
        ValidationHelper::validate($triggerFunctions);
        ValidationHelper::validate($globalActions);
        ValidationHelper::validate($initialActions);
        ValidationHelper::validate($commonActions);
        ValidationHelper::validate($steps);
        ValidationHelper::validate($splits);
        ValidationHelper::validate($joins);


        $actions = [];

        foreach ($globalActions as $action) {
            $actionId = $action->getId();
            if (array_key_exists($actionId, $actions)) {
                $errMsg = sprintf(
                    'Ошибка валидация. Действие с id %s уже существует',
                    $actionId
                );
                throw new InvalidWorkflowDescriptorException($errMsg);
            }
            $actions[$actionId] = $actionId;
        }

        foreach ($steps as $step) {
            $j = $step->getActions();

            foreach ($j as $action) {
                if (!$action->isCommon()) {
                    $actionId = $action->getId();
                    if (array_key_exists($actionId, $actions)) {
                        $errMsg = sprintf(
                            'Действие с id %s найденное у шага %s является дубликатом',
                            $actionId,
                            $step->getId()
                        );
                        throw new InvalidWorkflowDescriptorException($errMsg);
                    }
                    $actions[$actionId] = $actionId;
                }
            }
        }


        foreach ($commonActions as $action) {
            $actionId = $action->getId();
            if (array_key_exists($actionId, $actions)) {
                $errMsg = sprintf(
                    'common-action  с id %s является дубликатом',
                    $actionId
                );
                throw new InvalidWorkflowDescriptorException($errMsg);
            }
        }


        $this->validateDtd();
    }
1040317
public function actionProcess()
    {
        ini_set("memory_limit", "512M");

        $imaging = \Yii::$app->imaging;
        if (!$imaging) {
            //TODO: можно добавить проверку YII ensure...
            throw new \yii\base\Exception("Component Imaging not found");
        }

        $newFileSrc = \Yii::$app->request->getPathInfo();
        $extension = Imaging::getExtension($newFileSrc);

        if (!$extension) {
            throw new \yii\base\Exception("Extension not found: ".$newFileSrc);
        }


        if (!$imaging->isAllowExtension($extension)) {
            throw new \yii\base\Exception("Extension '{$extension}' not supported in Imaging component");
        }


        $newFile = File::object($newFileSrc);
        $strposFilter = strpos($newFileSrc, "/".Imaging::THUMBNAIL_PREFIX);
        if (!$strposFilter) {
            throw new NotFoundHttpException("This is not a filter thumbnail: ".$newFileSrc);
        }

        $originalFileSrc = substr($newFileSrc, 0, $strposFilter).".".$newFile->getExtension();

        //TODO: hardcode delete it in the future
        $webRoot = \Yii::getAlias('@webroot');

        $originalFileRoot = $webRoot.DIRECTORY_SEPARATOR.$originalFileSrc;
        $newFileRoot = $webRoot.DIRECTORY_SEPARATOR.$newFileSrc;
        $newFileRootDefault = $webRoot.DIRECTORY_SEPARATOR.str_replace($newFile->getBaseName(),
                Imaging::DEFAULT_THUMBNAIL_FILENAME.".".$extension, $newFileSrc);

        $originalFile = new File($originalFileRoot);

        if (!$originalFile->isExist()) {
            throw new NotFoundHttpException("The original file is not found: ".$newFileSrc);
        }

        //Проверено наличие оригинального файла, есть пути к оригиналу, и результирующему файлу.
        //Отслось собрать фильтр, и проверить наличие параметров. А так же проверить разрешены ли эти параметры, для этого в строке есть захэшированный ключь

        $filterSting = substr($newFileSrc, ($strposFilter + strlen(DIRECTORY_SEPARATOR.Imaging::THUMBNAIL_PREFIX)),
            strlen($newFileSrc));
        $filterCode = explode("/", $filterSting);
        $filterCode = $filterCode[0]; //Код фильтра

        //Если указаны парамтры, то ноужно проверить контрольную строчку, и если они не соответствуют ей, то ничего делать не будем
        if ($params = \Yii::$app->request->get()) {
            $pramsCheckArray = explode(DIRECTORY_SEPARATOR, $filterSting);
            if (count($pramsCheckArray) < 3) {
                throw new \yii\base\Exception("the control line not found: ".$newFileSrc);
            }

            $string = $imaging->getParamsCheckString($params);
            if ($pramsCheckArray[1] != $string) {
                throw new \yii\base\Exception("Parameters invalid: ".$newFileSrc);
            }
        }

        $filterClass = str_replace("-", "\\", $filterCode);


        if (!class_exists($filterClass)) {
            throw new \ErrorException("Filter class is not created: ".$newFileSrc);
        }

        /**
         * @var Filter $filter
         */
        $filter = new $filterClass((array)$params);
        if (!is_subclass_of($filter, Filter::className())) {
            throw new NotFoundHttpException("No child filter class: ".$newFileSrc);
        }

        try {
            //Проверяем а создан ли уже файл, и если да то просто делаем на него ссылку.
            $filter
                ->setOriginalRootFilePath($originalFileRoot)
                ->setNewRootFilePath($newFileRootDefault)
                ->save();

            if (PHP_OS === 'Windows') {
                if ($newFileRoot != $newFileRootDefault) {
                    //Не тестировалось
                    copy($newFileRootDefault, $newFileRoot);
                }
            } else {
                if ($newFileRoot != $newFileRootDefault) {
                    symlink($newFileRootDefault, $newFileRoot);
                }
            }

            $url = \Yii::$app->request->getUrl().($params ?
                    ""//"?" . http_build_query($params) . '&sx-refresh'
                    : '?sx-refresh');

            /*Header("HTTP/1.0 200 OK");
            Image::getImagine()->open($newFileRootDefault)->show('png');
            return '';*/

            return \Yii::$app->response->redirect($url, 302);

        } catch (\Exception $e) {
            return $e->getMessage();
        }
    }
711908
public static function init($config = [], $loader = null)
    {
        /**
         * Определение пути запуска скрипта
         */
        if (!defined('PUBLIC_PATH')) {
            $debug = debug_backtrace();
            define('PUBLIC_PATH', realpath(dirname($debug[0]['file'])) . DS);
        }

        if (!defined('BASE_PATH')) {
            define('BASE_PATH', realpath(dirname(PUBLIC_PATH)) . DS);
        }

        if (getenv('SOFI_DEVELOPER_MACHINE') === 'TRUE') {
            define('SOFI_MODE', 4);
            self::$dev = new Dev();
        } else {
            define('SOFI_MODE', 0);
        }
        
        register_shutdown_function([Sofi::class,'done']);

        self::addConfig(self::getConfigFile('sofi', BASE_PATH));
        self::addConfig($config);

        if (self::$general['project'] == '') {
            echo 'Empty Project name';
            die();
        }

        if (is_object($loader)) {
            self::$Loader = $loader;
            foreach (self::$general['paths'] as $name => $path) {
                self::$Loader->addPsr4($name, BASE_PATH . $path);
            }
        }

        /*
         * General init
         */
        foreach (self::$general['ini'] as $ini => $val) {
            if (is_int($ini)) {
                ini_set($val, true);
            } else {
                ini_set($ini, $val);
            }
        }

        if (self::$general['session']) {
            session_start();
        }

        ignore_user_abort(self::$general['ignore_user_abort']);

        set_time_limit(self::$general['time-limit']);
        date_default_timezone_set(self::$general['time-zone']);
        mb_internal_encoding(self::$general['charset']);
        mb_regex_encoding(self::$general['charset']);
    }
567017
public function setTableDefinition()
    {
        $this->setTableName('gallery_images');
        $this->hasColumns(array(
            'id' => array(
                'type' => 'integer',
                'unsigned' => true,
                'autoincrement' => true,
            ),
            'section' => array(
                'type' => 'integer',
                'unsigned' => true,
                'default' => null,
            ),
            'title' => array(
                'type' => 'string',
                'length' => 255,
                'default' => null,
            ),
            'image' => array(
                'type' => 'string',
                'length' => 128,
                'default' => null,
            ),
            'thumb' => array(
                'type' => 'string',
                'length' => 128,
                'default' => null,
            ),
            'posted' => array(
                'type' => 'datetime'
            ),
            'groupId' => array(
                'type' => 'integer',
                'unsigned' => true,
                'default' => 0,
            ),
            'cover' => array(
                'type' => 'boolean',
                'default' => 0,
            ),
            'active' => array(
                'type' => 'boolean',
                'default' => 0,
            ),
            'position' => array(
                'type' => 'integer',
                'unsigned' => true,
                'default' => 0,
            ),
        ));
        // TODO Проверить индексы
        $this->index('section', array('fields' => array('section')));
        $this->index('position', array('fields' => array('position')));
        $this->index('active', array('fields' => array('active')));
        $this->index('posted', array('fields' => array('posted')));
        $this->index('find_covers', array('fields' => array('section', 'active', 'cover')));
        $this->index('images_by_time', array('fields' => array('section', 'active', 'posted')));
        $this->index('images_by_position', array('fields' => array('section', 'active', 'position')));
        /* Проверенные индексы */
        $this->index('images_by_group_idx', array('fields' => array('groupId', 'active', 'position')));
    }
776271
public function validate()
    {
        $commonActions = $this->getCommonActions();
        $actions = $this->getActions();
        $hasActions = $this->hasActions;

        if ($hasActions && 0 === count($commonActions) && 0 === $actions->count()) {
            $stepName = (string)$this->getName();
            $errMsg = sprintf('Шаг %s должен содержать одни действие или одно общее действие', $stepName);
            throw new InvalidWorkflowDescriptorException($errMsg);
        }

        if (-1 === $this->getId()) {
            $errMsg = 'В качестве id шага нельзя использовать -1, так как это зарезериврованное значение';
            throw new InvalidWorkflowDescriptorException($errMsg);
        }

        $preFunctions = $this->getPreFunctions();
        $postFunctions = $this->getPostFunctions();
        $actions = $this->getActions();
        $permissions = $this->getPermissions();

        ValidationHelper::validate($preFunctions);
        ValidationHelper::validate($postFunctions);
        ValidationHelper::validate($actions);
        ValidationHelper::validate($permissions);

        $workflowDescriptor = $this->getParent();
        if (!$workflowDescriptor instanceof WorkflowDescriptor) {
            $errMsg = sprintf('Родительский элемент для шага должен реализовывать %s', WorkflowDescriptor::class);
            throw new InvalidWorkflowDescriptorException($errMsg);
        }
        foreach ($commonActions as $actionId) {
            try {
                $commonActionReference = $workflowDescriptor->getCommonAction($actionId);

                if (null === $commonActionReference) {
                    $stepName = (string)$this->getName();
                    $errMsg = sprintf('Common-action %s указанное для шага %s не существует', $actionId, $stepName);
                    throw new InvalidWorkflowDescriptorException($errMsg);
                }
            } catch (\Exception $e) {
                $actionIdStr = (string)$actionId;
                $errMsg = sprintf('Некорректный id для common-action: id %s', $actionIdStr);
                throw  new InvalidWorkflowDescriptorException($errMsg, $e->getCode(), $e);
            }
        }
    }
1128099
protected function checkEnvironment()
    {
        $errors = array();

        /* Проверяем наличие нужных файлов */
        $required = array('cfg/main.php');
        foreach ($required as $filename)
        {
            if (!file_exists($filename))
            {
                $errors []= array('file' => $filename, 'problem' => 'missing');
            }
        }

        /* Проверяем доступность для записи */
        $writable = array(
            'cfg/settings.php',
            'var',
            'data',
            'templates',
            'style'
        );
        foreach ($writable as $filename)
        {
            if (!is_writable($filename))
            {
                $errors []= array('file' => $filename, 'problem' => 'non-writable');
            }
        }

        if ($errors)
        {
            if (!Eresus_Kernel::isCLI())
            {
                require_once 'errors.html.php';
            }
            else
            {
                die("Errors...\n"); // TODO Доделать
            }
        }
    }
1207365
public function init()
    {
        //wczytywanie sesji
        $session = new \Mmi\Session\SessionSpace(\Cms\Model\ConnectorModel::SESSION_SPACE);
        try {
            $data = (new \Cms\Model\ConnectorModel)->getData($session->url, 'exportFileObject', [], $session->identity, $session->credential);
        } catch (\Cms\Exception\ConnectorException $e) {
            //rollback - puste dane
            $data = [];
        }

        //obiekty do przesłania
        if (!empty($data)) {
            //lista obiektów
            $this->addElement((new Element\MultiCheckbox('fileObjects'))
                ->setLabel('form.connectorImportFilesForm.fileObjects.label')
                ->setMultioptions($data)
                ->setValue($data));

            //submit
            $this->addElement((new Element\Submit('submit'))
                ->setLabel('form.connectorImportFilesForm.submit.label'));
        }
    }
623002
public function main()
    {
        $mainPageHTML = '';
        $dbMaterials = array();

        // Получим все материалы
        if (
        dbQuery('samsoncms\api\Material')
            ->join('user')
            ->cond('Active', 1)
            ->cond('Draft', 0)
            ->order_by('Created', 'DESC')
            ->cond('Name', "", dbRelation::NOT_EQUAL)
            ->limit(5)
            ->exec($dbMaterials)
        ) {
            // Render material rows
            $rowsHTML = '';
            foreach ($dbMaterials as $dbMaterial) {
                $rowsHTML .= $this->view('main/row')
                    ->set($dbMaterial, 'material')
                    ->set(isset($dbMaterial->onetoone['_user']) ? $dbMaterial->onetoone['_user'] : array(), 'user')
                    ->output();
            }

            for ($i = sizeof($dbMaterials); $i < 5; $i++) {
                $rowsHTML .= $this->view('main/row')->output();
            }

            // Render main template
            $mainPageHTML = $this->view('main/index')->set($rowsHTML, 'rows')->output();
        }

        // Return material block HTML on main page
        return $mainPageHTML;
    }
96412
public function boot() {
        foreach(Boot::$boots as $dir_boot) {
            $dir_boot = str_replace('\\', '/', $dir_boot);
            $files    = rglob('*.php', 0, $dir_boot);
            foreach($files as $path) {
                include_once $path;
            }
        }
        //регистрация политик моделей
        //        foreach(Boot::policies_model() as $model_class => $policy_class) {
        //            $gate->policy($model_class, $policy_class);
        //        }
        //регистрация путей шаблонов для пространств имен
        foreach(Boot::$langs as $alias => $pathes) {
            foreach($pathes as $path) {
                $this->loadTranslationsFrom($path, $alias);
                $this->publishes([
                    $path => resource_path('lang/vendor/' . $alias),
                ]);
            }
        }
        foreach(Boot::view_paths() as $v) {
            $namespace = Arr::get($v, 'namespace');
            $view_path = Arr::get($v, 'view_path');
            $this->loadViewsFrom($view_path, $namespace);
        }
        //регистрация команд
        $this->commands(Boot::commands());
        foreach(Boot::$observers as $model_class => $observers) {
            if('_USER_' == $model_class) {
                $model_class = config('auth.providers.users.model');
            }
            $instance = new $model_class;
            
            foreach($observers as $observer) {
                foreach($instance->getObservableEvents() as $event) {
                    if(method_exists($observer, $event)) {
                        $model_class::registerModelEvent($event, $observer . '@' . $event);
                    }
                }
            }
        }
    }
291631
private function linkAdminResources()
    {
        $page = Eresus_Kernel::app()->getPage();
        /** @var Eresus_Plugin $plugin */
        $plugin = $this->getModule();

        $resource = 'admin/default.css'; // В будущем «default» можно заменить именем темы
        if (file_exists($plugin->getCodeDir() . '/' . $resource))
        {
            $page->linkStyles($plugin->getCodeUrl() . $resource);
        }

        $resource = 'admin/scripts.js';
        if (file_exists($plugin->getCodeDir() . '/' . $resource))
        {
            $page->linkScripts($plugin->getCodeUrl() . $resource);
        }
    }
207472
public function addPluginSeo()
    {
        $row = new FormInput('seo_title', 'Title материала');
        $this->rows['seo_title'] = $rows_plugin[] = $row->setTab('seo', 'Seo')->setValid('max:255')
            ->setTypo()->setHelp('По-умолчанию равно заголовку материала');

        $row = new FormInput('seo_description', 'Description материала');
        $this->rows['seo_description'] = $rows_plugin[] = $row->setTab('seo', 'Seo')->setValid('max:255')
            ->setTypo()->setHelp('По-умолчанию равно заголовку материала');

        $row = new FormTextarea('seo_keywords', 'Keywords материала');
        $this->rows['seo_keywords'] = $rows_plugin[] = $row->setTab('seo', 'Seo')->setValid('max:255')
            ->setCssClass('not-editor uk-width-1-1');

        $this->plugins_backend['seo']['rows'] = $rows_plugin;

        $row = new FormInput('url', 'URL материала');
        $this->rows['url'] = $row->setTab('seo', 'SEO')
            ->setValid('max:155|required|unique:'.$this->table)->setCssClass('uk-width-1-1')->setFillable();

        return $this;
    }
771105
public static function create() 
    {
		$alias = func_get_arg(0);
		$name = func_get_arg(1);
		
        try {
            $m = self::getByAlias($alias);
        } catch (\Exception $e) {}
        
        if ($m) throw new Exception\CMS('Меню c таким алиасом уже существует.');
        
        self::getDbConnection()->insert('menus', array(
			'alias' => $alias,
			'name'  => $name
		));
  		return self::getById( self::getDbConnection()->lastInsertId() );
  	}