понедельник, 26 декабря 2016 г.

Ошибка "Не удалось проверить переданные данные" при отправке формы в Yii2

На Yii2 сделана защита от CSRF-атак. Когда она срабатывает, то при отправке формы вы получаете ошибку "Не удалось проверить переданные данные".

Я столкнулся с тем, что эта ошибка появлялась случайным образом. В итоге выяснилось, что проблема в настройках куки.

Два моих приложения, "backend" и "frontend", имели разный код для шифровки кук: "cookieValidationKey". Он настраивается в файле "config/main-local.php" для каждого из приложений.

Из-за этого, открыв сначала страницу на одном приложении, а потом на другом, сбрасывался CSRF-код - ведь шифровали куки с одним ключом, а расшифровывать пытаемся с другим.

Решение: прописать в конфигах одинаковые значения для "cookieValidationKey". Теперь всё работает )

четверг, 22 декабря 2016 г.

Решение конфликтов при слиянии для файлов Composer.

Как решить конфликты файлов "composer.lock" и "composer.json" при слиянии веток?

Обычно ситуация такая. Вы в своей ветке добавляете новые пакеты Composer, ваш напарник тоже добавляет новые пакеты Composer в своей ветке.
Оба файла "composer.json" и "composer.lock" при этом находятся в репозитории.

Попытавшись вытянуть изменения напарника, сделать слияние веток, вы скорее всего получите конфликт по обоим файлам. А если он ещё делал "composer update" по всем пакетам, то это практически гарантированно.

Не беспокойтесь, решается это достаточно просто.

1. Посмотрите composer.json - какие изменения были от вас, а какие от напарника.
Особенно запомните, какие изменения вносили вы.

2. Сбросьте оба файла на "внешнюю" версию ("theirs"). Таким образом, содержимое у них будет как в той ветке, из которой вы тянете изменения в свою.
Конфликты отмечаем как решённые, завершаем слияние.
Прогоняем "composer install". Вытянутся пакеты напарника.

3. Добавьте ваши изменения ещё раз. Это занимает немного времени, написать один или несколько раз "composer require" для нужных вам пакетов.

Теперь можно выкатывать обновлённые файлы "composer.json" и "composer.lock", они будут корректно работать.

суббота, 3 декабря 2016 г.

Создание проекта Yii2 по шаблону Ганимед

Ганимед - это мой шаблон для быстрой разработки сайтов. В него включены все минимально необходимые модули и настройки.

Шаблон разработан на базе "yiisoft/yii2-app-advanced".

https://github.com/Nex-Otaku/yii2-app-ganimede

Установка

1. Используем репозиторий https://github.com/Nex-Otaku/yii2-app-ganimede

Запускаем консоль OpenServer.
cd domains
composer create-project --prefer-dist --stability=dev nex-otaku/yii2-app-ganimede myhost.local

2. После установки
cd myhost.local
init
0
y

3. Создаём БД в менеджере БД.

4. Настраиваем подключение.

Указываем IP, указанный в настройках OpenServer,
либо "localhost", если не настроен доступ к серверу по локальной сети.
common/config/main-local.php
'dsn' => 'mysql:host=my.super.host.ip;dbname=mysuperdbname',

5. Запускаем миграцию, которая поднимает необходимые таблицы.
Запускаем консоль OpenServer.
cd domains
cd myhost.local
yii migrate

Автоматический вход SSH с помощью ключей

Задача: полностью автоматизировать вход пользователя на сервер посредством putty, по протоколу SSH.

Для этого нам понядобятся ключи авторизации SSH.


1. Создаём ключ на сервере.
ssh-keygen -t rsa

2. Сохраняем ключ в предлагаемый файл (/home/myuser/.ssh/id_rsa)

3. При необходимости указываем пароль на использование приватного ключа.
В этом случае его необходимо будет вводить при каждой новой сесии.

4. Копируем публичный ключ id_rsa.pub в authorized_keys
cd .ssh
cp id_rsa.pub authorized_keys

6. Проверяем права на файл. 
Должны быть 600, иначе может не сработать. Если права отличаются, устанавливаем значение 600.
chmod 600 authorized_keys

7. Копируем приватный ключ id_rsa в файл на локальном комьютере (например my_session.ppk)
more id_rsa

8. Прогоняем скопированный приватный ключ через puttygen.exe делая приватный ключ пригодным к использованию. (Там есть кнопочка "Load", напротив надписи "Load an existing private key file", юзаем сначала ее, а затем нажимаем "Save private key".)

9. Открываем Putty, загружаем нашу сессию, идем в SSH->Auth, указываем путь к готовому приватному ключу.

10. Идем в Connection->Data и в секции Auto-login в поле username указываем логин сессии

11. При необходимости в пункте меню SSH в поле Remote Command можно указать команду, которая автоматически будет выполняться при входе пользователя.

12. Сохраняем сессию.

13. Делаем отдельный ярлык Putty, в котором указываем имя сессии, чтобы при запуске ярлыка нужная сессия запускалась автоматически.
"C:\Program Files (x86)\PuTTY\putty.exe" -load "mycoolproject"

Всё готово. Теперь по клику на ярлык откроется консоль на вашем сервере. Удобно и безопасно.

Инструкцию нашёл здесь: http://xpoint.ru/forums/computers/os/unix/thread/40057.xhtml

Развёртывание проекта с BitBucket на удалённый сервер.

1. Выбираем публичный ключ SSH, он хранится в файле "/.ssh/id_rsa.pub" в домашней папке.
Если его нет, создаём по инструкции.
Копируем содержимое ключа в буфер обмена.

Внимание: если вы копируете ключ с экрана Putty, то в буфере обмена ключ может быть разбит на несколько строк. Нам это не нужно. Уберите переводы строк. Весь ключ должен быть в одной длинной-длинной строке.

2. В настройках репозитория Битбакета добавляем в разделе "Access keys".
Теперь пользователь может читать из репозитория без ввода пароля, доступ осуществляется по ключу.

3. Клонируем репозиторий.
git clone CoolUser@bitbucket.org:CoolUser/cool-repo.git

четверг, 17 ноября 2016 г.

Развёртывание существующего проекта Yii2 для разработки.

Вам нужно развернуть проект на Yii2 для разработки.

У вас установлен и настроен OpenServer на локальной машине.

1. Клонируем репозиторий в папку доменов OpenServer. 

Называем папку проекта, например, "my-cool-project.local".

2. После успешного клонирования, устанавливаем файлы окружения.

Запускаем консоль OpenServer.
cd domains
cd my-cool-project.local
init
0
yes

3. Устанавливаем зависимости.

composer install

4. Создаём БД в менеджере БД.

5. Настраиваем подключение.

Указываем имя БД, пользователя и пароль в конфиге.
common/config/main-local.php
'dsn' => 'mysql:host=localhost;dbname=my_cool_project_dbname',

6. Запускаем миграции, которые создают необходимые таблицы.

yii migrate

вторник, 4 октября 2016 г.

Настройка IDE и окружения для разработки на Yii2

Вы решили делать сайты на Yii2, и используете:

Windows 10, IDE Netbeans, локальный сервер OpenServer.

У вас уже всё установлено? Хорошо!

Несколько дополнительных настроек сделает вашу работу легче и приятнее.

1. Включаем в OpenServer расширение PHP, необходимое для работы Yii2.
В файле php.ini раскомментируем строку
extension=php_intl.dll

Без этого расширения, вместо русских дат будут отображаться английские.

2. Настраиваем LESS.
OpenServer. http://nex-otaku-ru.blogspot.ru/2016/05/less-yii2-openserver.html
Netbeans. http://nex-otaku-ru.blogspot.ru/2016/08/less-netbeans.html

3. Настраиваем форматирование PSR в Netbeans.
https://github.com/bobsta63/netbeans-psr-formatting

4. Включаем строгое отображение ошибок на машине разработки.
В php.ini (трей OpenServer -> Дополнительно -> Конфигурация -> PHP x.x)
error_reporting = E_ALL

5. Настраиваем xDebug.
Включаем xDebug, настраиваем Netbeans. http://nex-otaku-ru.blogspot.ru/2016/09/xdebug-openserver-netbeans.html
Отключаем xDebug для Composer. http://nex-otaku-ru.blogspot.ru/2016/09/xdebug-composer-openserver.html

6. Настраиваем вывод UTF8 в консоли, для консольных команд Yii.
Запускаем консоль, правой кнопкой нажимаем на заголовок окна, выбираем Settings -> Startup -> Environment.
Дописываем строку
chcp 65001

Также можно настроить автоматический вход в папку "domains".
Прописываем в настройках
Startup -> Tasks -> Shells::cmd
В окошке "Commands", находим строку 
cmd.exe /k "%ConEmuBaseDir%\CmdInit.cmd"
дописываем в конец строки, указав полный путь к папке Опенсервера
-new_console:d:Z:\OpenServer\domains

Теперь сохраняем: "Save Settings".

Готово!

среда, 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',
        ],
    ]
]);

воскресенье, 29 мая 2016 г.

Настройка LESS в Yii2 на OpenServer.

Устанавливаем LESS-компилятор, чтобы Yii мог автоматически собирать ассеты с расширением ".less".

К сожалению, по умолчанию OpenServer этого не умеет. Поэтому устанавливаем вручную.

1. Скачать и установить Node.js: https://nodejs.org

2. В командной строке Windows выполнить:
npm install -g less
npm install -g less-plugin-autoprefix

3. Выбрать в настройках OpenServer "Сервер > Настройка использования переменной PATH" : "Свой Path + Win Path", перезагрузить компьютер.

Также см. Настройка LESS в Netbeans

четверг, 5 мая 2016 г.

Убираем отступы колонок Bootstrap

В бутстрапе есть замечательная система сетки, которая подстраивается под разные размеры окна. 

https://getbootstrap.com/examples/grid/

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

Есть выход - назначим всем "строкам", внутри которых отступы не нужны, специальный стиль с помощью класса "slim".

Таким образом, нам не потребуется добавлять правила обнуления для каждого блока, достаточно только указать

class="row slim"

Готовый код для вставки в CSS:

/* 
    Специальный класс для очистки от 
    вездесущих отрицательных границ и отступов бутстрапа. 

    Без него, контейнер и колонки добавляют отступы,
    а строки их нейтрализуют отрицательными границами.

    С этим приходится бороться, 
    обнуляя эти отступы и границы специальными правилами CSS.

    Чтобы не засорять файлы стилей постоянными обнулениями,
    мы зададим этот класс для всех строк, 
    которые не предполагают работы с границами и отступами.
*/
.row.slim {
    margin-left: 0;
    margin-right: 0;
}

.row.slim > [class^="col-"], .slim > [class*=" col-"] {
    padding-left: 0 !important;
    padding-right: 0 !important;
}

вторник, 26 апреля 2016 г.

Заполнение изначальной сортировки в MySQL.

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

Вы добавили код, который работает с сортировкой.

Но нужно ещё отсортировать ранее введённые данные. Когда их мало, это можно сделать вручную.

А если их много, то поможет такая процедура на MySQL:

CREATE DEFINER=`root`@`%` PROCEDURE `reindex_table`(IN `sorted_table` VARCHAR(50), IN `sorting_column` VARCHAR(50), IN `grouping_column` VARCHAR(50), IN `group_table` VARCHAR(50), IN `group_id_column` VARCHAR(50))
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT 'Заполняет поле сортировки.'
BEGIN

# Пример использования:
# CALL reindex_table('my_cool_table', 'sort', 'group_id', 'group_table', 'id');

DECLARE done INT DEFAULT 0;

# В нашей таблице используется бинарный UUID, 
# поэтому такой же тип назначаем переменной.
# В обычных таблицах, здесь был бы INT.
DECLARE group_id BINARY(16);

# Курсоры и обработчики объявляются последними.
DECLARE cur_1 CURSOR FOR SELECT id FROM group_table_tmp;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

# Создаём временную таблицу для прочёсывания курсором.
# Это единственный способ заставить курсор двигаться по таблице, 
# заданной водными параметрами.
# Есть ещё вариант с созданием VIEW, 
# с преимуществом по производительности и со своими недостатками.
# Так как скорость нас в данном случае не волнует, делаем через временную таблицу.
DROP TEMPORARY TABLE IF EXISTS group_table_tmp;
SET @sql_text = CONCAT('CREATE TEMPORARY TABLE group_table_tmp ENGINE=MEMORY AS SELECT ', group_id_column, ' AS id FROM ', group_table);
PREPARE stmt FROM @sql_text;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

# Проходим цикл по внешнему ключу, который разбивает нашу таблицу на группы сортировки.
OPEN cur_1;
REPEAT
FETCH cur_1 INTO group_id;
# Бинарный UUID нуждается в преобразовании.
# Если у вас обычный целочисленный ID, вставляйте его, как есть.
SET @group_id_converted = CONCAT('0x', HEX(group_id));

# Пронумеровываем строки.
SET @curRow = 0;
SET @sql_text = CONCAT('UPDATE ', sorted_table, ' sorted_tbl,',
' (SELECT @curRow := @curRow + 1 AS row_number, ', sorted_table, '.* FROM ', sorted_table, ' WHERE ', grouping_column, '=',  @group_id_converted, ' AND deleted=0 ORDER BY date_create) indexed_rows',
' SET sorted_tbl.', sorting_column, ' = indexed_rows.row_number',
' WHERE sorted_tbl.id = indexed_rows.id;');
PREPARE stmt FROM @sql_text;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

UNTIL done = 1 
END REPEAT;
CLOSE cur_1;

# Удаляем временную таблицу.
DROP TEMPORARY TABLE IF EXISTS group_table_tmp;

END