среда, 28 сентября 2016 г.

Подключение yii2-user и yii2-admin для управления пользователями и правами доступа

Как настроить управление пользователями и правами доступа в Yii2 с нуля.

Будем использовать приложение Yii2 Advanced, подключим модули "yii2-user" и "yii2-admin".

Если у вас уже есть готовое приложение, шаги с 1 по 5 можно пропустить.

1. Создаём проект по шаблону Advanced.

Здесь предполагается, что вы уже настроили Composer. Если нет, см. документацию к шаблону.

composer create-project --prefer-dist yiisoft/yii2-app-advanced yii2-user-combo.local

cd yii2-user-combo.local
init 
0
yes

2. Удаляем миграцию стандартных юзеров, она нам не нужна: "console/migrations/m130524_201442_init.php".

3. Добавляем файлы ".htaccess" в папки "/frontend/web", "/backend/web", а также в корень проекта.

В моём примере, фронтенд будет доступен по адресу "http://yii2-user-combo.local".

Бэкенд по адресу "http://yii2-user-combo.local/admin".

/.htaccess

Options -Indexes
Options FollowSymlinks
RewriteEngine on

RewriteCond %{HTTP_HOST} ^www\.(.*)$
RewriteRule ^(.*)$ http://%1/$1 [L,R=301]

RewriteCond %{REQUEST_URI} ^/admin/$
RewriteRule ^(admin)/$ /$1 [R=301,L]
RewriteCond %{REQUEST_URI} ^/admin
RewriteRule ^admin(/.+)?$ /backend/web/$1 [L,PT]

RewriteCond %{REQUEST_URI} ^.*$
RewriteRule ^(.*)$ /frontend/web/$1

/backend/web/.htaccess

# use mode rewrite for pretty URL support
RewriteEngine on
# if a directory or a file exists, use the request directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# otherwise forward the request to index.php
RewriteRule . index.php

/frontend/web/.htaccess

<IfModule mod_rewrite.c>
        Options +FollowSymlinks

        # Включаем mod_rewrite и перенаправляем со слэша
        RewriteEngine On
        RewriteBase /
        RewriteCond %{HTTP_HOST} (.*)
        RewriteCond %{REQUEST_URI} /$ [NC]
        RewriteRule ^(.*)(/)$ $1 [L,R=301]

        # Если это папка или файл, открываем ее/его
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        # В противном случае перенаправляем на index.php
        RewriteRule . index.php
</IfModule>


4. Создаём БД, указываем её в конфиге "common/config/main-local.php".

5. Настраиваем конфиги.

backend/config/main.php
    'components' => [
        'request' => [
            ...
            'baseUrl'=>'/admin',
        ],

common/config/main.php
    'language' => 'ru-RU',
    ...
    'components' => [
        ...
        'urlManager' => [
            'enablePrettyUrl' => true,
            'showScriptName' => false,
        ],

frontend/config/main.php
    'components' => [
        'request' => [
            // Избавляемся от /frontend/web
            'baseUrl' => '',
            ...
        ],

6. Ставим "yii2-user".

composer require dektrium/yii2-user

7. Убираем из конфига компонент "user", вместо него подключаем дектриумовский модуль.

Настройку модуля пользователей сделаем только для бэкенда. Для фронтенда настройки будут аналогичные.

backend/config/main.php
        'modules' => [
// ID модуля должен обязательно быть "user", иначе модуль не загрузится.
            'user' => [
                'class' => 'dektrium\user\Module',
'admins' => ['MegaAdmin'], // Хардкод для админского пользователя. После настройки прав доступа, нужно удалить эту строку.
            ],
        ],        

8. Подключаем консольные команды.

console/config/main.php
'modules' => [
            'user' => [
                'class' => 'dektrium\user\Module',
            ],
        ],

9. Создаём таблицы для пользователей.

yii migrate --migrationPath=@vendor/dektrium/yii2-user/migrations

10. Убираем неиспользуемые действия из контроллеров.

backend/controllers/SiteController.php

Приводим "behaviors" к такому виду.

public function behaviors()
{
    return [
        'access' => [
            'class' => AccessControl::className(),
            'rules' => [
                [
                    'actions' => ['error'],
                    'allow' => true,
                ],
                [
                    'actions' => ['index'],
                    'allow' => true,
                    'roles' => ['@'],
                ],
            ],
        ],
    ];
}


Убираем лишние действия.
public function actionLogin()
public function actionLogout()

11. Удаляем файл представления
/backend/views/site/login.php

12. Меняем в файле
/backend/views/layouts/main.php

/site/login на /user/security/login

/site/logout на /user/security/logout

13. Ставим расширение "yii2-admin".

composer require mdmsoft/yii2-admin

14. Настраиваем конфиги.

backend/config/main.php
    'bootstrap' => [
        ...
        'users-admin',
    ],
...
    'modules' => [
...
// ID модуля может быть любой.
        'users-admin' => [
            'class' => 'mdm\admin\Module',
            // Отключаем шаблон модуля,
            // используем шаблон нашей админки.
            'layout' => null,
        ]
    ],        
...
    'as access' => [
        'class' => 'mdm\admin\classes\AccessControl',
        // Маршруты, открытые по умолчанию всегда.
        // Открываем только для начальной разработки.
        // Как только основные данные о ролях заполнены,
        // убираем отсюда всё лишнее.
        'allowActions' => [
            // Маршруты модуля пользователей.
            // Логин и так разрешён, но разлогиниться 
            // без этой настройки и без настроенных ролей не получится.
            'user/*',
            'site/*',
            'users-admin/*',
            'debug/*',
        ]
    ],

common/config/main.php
    'components' => [
        'authManager' => [
            'class' => 'yii\rbac\DbManager',
        ],

15. Добавляем ассет для корректного отображения админки в нашем шаблоне.

backend\assets\AppAsset.php
    public $depends = [
        ...
        'dee\adminlte\AdminlteAsset',
    ];

16. Применяем миграции для использования RBAC.

yii migrate --migrationPath=@yii/rbac/migrations

17. Применяем миграции для редактирования меню.

yii migrate --migrationPath=@mdm/admin/migrations

18. Всё готово.

Управление правами доступа:
http://yii2-user-combo.local/admin/users-admin/

Управление пользователями:
http://yii2-user-combo.local/admin/user/admin

Настройки профиля:
http://yii2-user-combo.local/admin/user/settings/profile

Полный список маршрутов модуля пользователей: https://github.com/dektrium/yii2-user/blob/master/docs/available-actions.md



P.S. Можно подключать расширение "dektrium/yii2-rbac" для управления правами доступа.

Но расширение "mdmsoft/yii2-admin" удобнее.

Оба расширения позволяют полноценно настраивать права доступа.

Преимущества "yii2-admin":

1. Более удобное редактирование прав доступа.

2. Помощник для вывода меню с учётом прав доступа.

3. Редактор меню.

Преимущества "yii2-rbac":

1. Удобно создавать консольные миграции прав доступа.

2. Есть интеграция с yii2-user в виде общей админки.

воскресенье, 4 сентября 2016 г.

Создание расширения для Yii2

Основа расширения создаётся с помощью Gii.

1. Создание расширения в Gii.

Открываем "Extension Generator", заполняем форму.

Vendor Name: аккаунт на гитхабе, в моём случае "nex-otaku".

Package Name: например, "yii2-toolkit". Начинается с "yii2-".

Namespace: nex_otaku\toolkit\

Лицензию выбираем MIT, как самую простую и свободную.

2. Подключение локального репозитория.

Создаём репозиторий.
D:\repos\yii2-toolkit

Перемещаем туда сгенерированные файлы.

Подключаем в проекте локальный репозиторий:

"repositories": [
    {
        "type": "vcs",
        "url": "file://D:/repos/yii2-toolkit"
    }
]

По завершению тестирования, расширение нужно опубликовать на Гитхабе и зарегистрировать в Packagist. Тогда мы сможем подключать его через Composer.
Локальный репозиторий, соответственно, нужно будет удалить.

3. Подключение расширения.

Подключаем:

composer require nex-otaku/yii2-toolkit

4. Публикация в Github и Packagist.

Расширение протестировано и готово к публикации? Заливаем на Гитхаб и регистрируем его на Packagist.

Регистрация в Packagist:
Нажимаем кнопку "SUBMIT", вводим URL нашего репозитория на Гитхабе. Нажимаем "Check", потом "Submit". Наше расширение добавлено в каталог.

5. Настройка обновлений.

Включаем хук для автоматических обновлений на Гитхабе.

В репозитории Github:
"Settings" -> "Integrations & Services"
Добавляем сервис, выбираем из списка "Packagist".
Заполняем поля, имя пользователя Packagist (но не email), токен берём из профиля на сайте Packagist.
Поле "Domain" оставляем пустым.
Отправляем форму. Хук привязан.

Для проверки, нажимаем кнопку "Test service" (в правом верхнем углу в форме настроек хука).
После нажатия кнопки, со страницы пакета на Packagist должно пропасть предупреждение "This package is not auto-updated".

6. Использование.

Всё готово, можно править расширение и заливать изменения на Гитхаб. Пакет будет обновляться автоматически.

Версии пакета проставляются тегами в репозитории, и подгружаются из репозитория автоматически композером.

Можно версии вообще не указывать, если пакет подключен на "dev-master":
"nex-otaku/yii2-toolkit": "dev-master"
Пакет подключается так по умолчанию. При обновлении всегда будет загружаться последний коммит.

Если нам нужно обновить только наш пакет, а остальные не трогать, используем команду:
composer update nex-otaku/yii2-toolkit

Настройка xDebug в OpenServer, для среды NetBeans.

Настроим расширение xDebug для отладки PHP-скриптов в IDE Netbeans.

В качестве локального сервера мы используем OpenServer.

1. Включаем xDebug.

Open Server -> Дополнительно -> Конфигурация -> PHP x.x. (ваша версия PHP)
[Xdebug]
zend_extension="%sprogdir%/modules/php/%phpdriver%/ext/php_xdebug.dll"
xdebug.idekey = "netbeans-xdebug"
xdebug.remote_enable = 1

Дебажная сессия должна автоматически открываться в окне браузера, при запуске отладки.
Откроется адрес вида
http://myhost.local/?XDEBUG_SESSION_START=netbeans-xdebug

2. Настраиваем браузер.

Для того, чтобы удобно было включать режим отладки в Хроме, я использую расширение "Xdebug helper".

https://chrome.google.com/webstore/detail/eadndfjplgieldjbigjakmdgkmoaaaoc

Оно позволяет переключать режим на уже открытой странице, и не засоряет строку запроса.

Ключ отладки передаётся через куки.

В настройках плагина нужно выбрать ключ для Netbeans.

В настройках NetBeans снимаем галочку:
Сервис -> Параметры -> PHP -> Отладка -> Остановиться в первой строке

Если сразу не заработало, нужно перезапустить NetBeans.

3. Настраиваем IDE Netbeans.

3.1 В настройках проекта указываем:

Выполнить настройку -> Дополнительно -> Отладка URL-адреса -> Не открывать веб-браузер

Чтобы NetBeans не открывал на каждый сеанс отладчика новую вкладку в браузере.

Для управления режимом отладки, удобнее использовать расширение Chrome.

3.2 Ставим таймаут для отладки, иначе будет отваливаться SQL-соединение: wait_timeout=6000

Также см. Отключение xDebug для Composer на OpenServer.

Отключение xDebug для Composer на OpenServer

Композер обычно ругается на включенный xDebug.

You are running composer with xdebug enabled. This has a major impact on runtime performance.

Можно отключить xDebug в настройках PHP, но это расширение необходимо для отладки. Поэтому отключить его нужно только для композера.

Рассмотрим, как это сделать, если вы используете OpenServer.

Вот мой рецепт, как навсегда отключить xDebug при запуске композера.

1. Ищем файл "php.ini".

Путь к файлу "C:\path\to\OpenServer\modules\php\PHP-x.x\php.ini".

Вместо "x.x" - используемая вами версия PHP, "C:\path\to\" - директория установки OpenServer на вашей машине.

2. Создаём его копию в этой же папке, "php-no-xdebug.ini".

3. Открываем на редактирование файл "php-no-xdebug.ini", ищем строку:

zend_extension="c:\path\to\OpenServer\modules\php\PHP-x.x\ext\php_xdebug.dll"

Закомментируем её. Ставим точку с запятой, строка примет вид:

;zend_extension="c:\path\to\OpenServer\modules\php\PHP-x.x\ext\php_xdebug.dll"

Сохраняем файл.

4. Теперь меняем скрипт, запускающий сам композер.

Ищем файл "C:\path\to\OpenServer\modules\php\PHP-x.x\composer.bat".

Открываем его на редактирование, видим:

@"%PHP_BIN%" -d output_buffering=0 "%PHP_DIR%composer.phar" %* 

5. Меняем на следующую строку:

@"%PHP_BIN%" -c "%PHP_DIR%\php-no-xdebug.ini" -d output_buffering=0 "%PHP_DIR%composer.phar" %*

Сохраняем изменения.

Всё, теперь композер больше не ругается, а "глобально" xDebug остался включенным.

Убедитесь в этом, открыв страничку "Информация PHP" в меню OpenServer.

понедельник, 29 августа 2016 г.

Кроссдоменные куки с помощью AJAX

Кроссдоменные куки можно установить с помощью AJAX-запроса.

Для этого используем CORS.

Пример для Yii2:

<?php

namespace frontend\controllers;

use yii\web\Response;
use Yii;
use app\components\MyUtility;
use yii\web\Controller;

class CoolController extends Controller
{
    // Отключаем CSRF для контроллера.
    // Кроссдоменный запрос работает только без CSRF.
    public $enableCsrfValidation = false;

    public function behaviors()
    {
        // Включаем CORS для контроллера.
        return [
            'corsFilter' => [
                'class' => \yii\filters\Cors::className(),
                'cors' => [
                    // Разрешаем доступ с указанных доменов.
                    'Origin' => ['http://site1.com', 'http://site2.com'],
                    'Access-Control-Allow-Origin' => true,
                    // Куки от кроссдоменного запроса
                    // будут установлены браузером только при заголовке
                    // "Access-Control-Allow-Credentials".
                    'Access-Control-Allow-Credentials' => true,
                    // Разрешаем только метод POST.
                    'Access-Control-Request-Method' => ['POST'],
                ],
            ],
        ];
    }

    public function actionSelect()
    {
        Yii::$app->response->format = Response::FORMAT_JSON;
        return MyUtility::processPostParamsAndSetCookie(Yii::$app->request->post());
    }
}

Код JQuery:

$.ajax('http://site.com/set-global-cookie', {
    type : 'POST',
    data : {veryImportantData: someInformation},
    success : function (response) {
        if (response.status !== 'success') {
            if (response.status === 'error') {
                console.error('Возникла ошибка: ' + response.message);
            } else {
                console.error('Возникла неизвестная ошибка.');
            }
        }
    },
    error :  function(xhr, str){
        console.error('Возникла ошибка AJAX: ' + xhr.responseCode + ', "' + str + '"');
    },
    xhrFields: {
        // Необходимо для установки куков.
        withCredentials: true
    },
});

вторник, 23 августа 2016 г.

Настройка LESS в Netbeans

Для начала, настройте автоматическую сборку LESS на OpenServer: Настройка LESS в Yii2 на OpenServer.

LESS-файлы теперь компилируются автоматически, но при изменении в редакторе, приходится вручную чистить кеш.

Чтобы не чистить кеш вручную, настраиваем автоматическую компиляцию при сохранении.

При сохранении изменённого LESS-файла, Netbeans будет автоматически запускать компиляцию в CSS.

Открываем свойства проекта, "Препроцессоры CSS", вкладка "LESS".

Ставим галочку "Скомпилировать файлов при сохранении: LESS".

Заполняем список "корневыми" LESS-файлами, по-хорошему, это должен быть один файл на проект. Дополнительные LESS-файлы включаются в него с помощью директивы "@import".

Для Yii2 список аналогичен прописанному в файле "frontend\assets\AppAsset.php".
Ввод                              Вывод
/frontend/web/css/less/style.less /frontend/web/css/less/style.css

Для проверки компиляции, открываем "Окно -> Вывод". Здесь будут сообщения о запуске LESS-компилятора при сохранении LESS-файлов.


пятница, 8 июля 2016 г.

Настройка интеграции TinyMCE и "RESPONSIVE filemanager" в Yii2 Advanced Template.

Редактор TinyMCE очень хорош, но по умолчанию в бесплатной версии нет поддержки для загрузки файлов и картинок на сервер.

Для загрузки файлов и картинок подключаем отличное расширение "RESPONSIVE filemanager".

Для подключения самого редактора TinyMCE я использую расширение "2amigos/yii2-tinymce-widget".

1. Скачиваем расширение http://www.responsivefilemanager.com/, распаковываем целиком в папку, допустим "/backend/web/plugins/responsivefilemanager".

Папка "/backend/web" в моём проекте доступна по адресу "/admin/".

2. Открываем файл "/responsivefilemanager/filemanager/config/config.php".

3. Настраиваем пути.

    // Путь к загруженным файлам относительно корневого URL.
    'upload_dir' => '/uploads/',

    // Путь к папке для загрузки файлов относительно папки "/responsivefilemanager".
    'current_path' => '../../../../../frontend/web/uploads/',

    // Путь к папке для загрузки миниатюр относительно папки "/responsivefilemanager".
    'thumbs_base_path' => '../../../../../frontend/web/uploads_thumbs/',

4. Настраиваем максимальный размер загружаемых файлов. Я ставлю 50 мегабайт. Для большинства файлов этого хватает.

    'MaxSizeUpload' => 50,

5. Настраиваем язык интерфейса.

    'default_language' => "ru",

6. Создаём папки для загрузки:
    /frontend/web/uploads/
    /frontend/web/uploads_thumbs/

7. Прописываем необходимые настройки TinyMCE. Я делаю это в файле "/backend/config/bootstrap.php", чтобы настройки применялись глобально во всех формах.

// Конфигурация по умолчанию для виджета TinyMCE.
Yii::$container->set('dosamigos\tinymce\TinyMce', [
    'language' => 'ru',
    'options' => ['rows' => 20],
    'clientOptions' => [
        'plugins' => [
            "advlist autolink lists link charmap hr preview pagebreak",
            "searchreplace wordcount textcolor visualblocks visualchars code fullscreen nonbreaking",
            "save insertdatetime media table contextmenu template paste image responsivefilemanager filemanager",
        ],
        'toolbar' => "undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | responsivefilemanager link image media",
        'external_filemanager_path' => '/admin/plugins/responsivefilemanager/filemanager/',
        'filemanager_title' => 'Responsive Filemanager',
        'external_plugins' => [
            // Кнопка загрузки файла в диалоге вставки изображения.
            'filemanager' => '/admin/plugins/responsivefilemanager/filemanager/plugin.min.js',
            // Кнопка загрузки файла в тулбаре.
            'responsivefilemanager' => '/admin/plugins/responsivefilemanager/tinymce/plugins/responsivefilemanager/plugin.min.js',
        ],
    ]
]);