Как мы используем Yii

Александр Макаров

Yii core team, Stay.com


?

Если все и так знают, пропущу :)

  • PHP5 MVC.
  • Приятный API.
  • DAO, AR, миграции.
  • Построитель форм.
  • Темы.
  • Тесты.
  • Документирован.
  • Сообщество.
  • BSD.
  • Мощный кеш.
  • RBAC, авторизация.
  • Консоль.
  • Обработка ошибок, лог.
  • Gii.
  • CLDR, I18n.
  • Виджеты.

Prado, с 2004 → Yii 1.0, 2008 → Yii 1.1, 2010 → Yii 2

Что важно в фреймворке

  • Легко изучать.
  • Легко отлаживать и исправлять ошибки.
  • Не должен мешать вашему коду или любому нормальному стороннему коду.
  • Отличное сообщество.
  • Обратно совместимый и стабильный.
  • Не мешает расширять и настраивать.
  • Приятен ;)

Типичный проект

  • Основная веб-мордочка.
  • Админка.
  • Консоль.
  • API.

Проблемы?

  • Структура, общий код.
  • Команда.
  • Разные сервера.
  • Разные настройки.

Структура

Приложения

  • Common (↓)
  • Models
  • Parameters
  • Components
  • Console (↑)
  • Frontend (↑)
  • Admin (↑)

Алиасы


Yii::getPathOfAlias()
Yii::setPathOfAlias()
                        
  • root
  • common
  • application (Yii default)
  • webroot

Серверы

  • Машина разработчика.
  • Тестовый.
  • RC.
  • Production.

Как быть с конфигами?

  • Общий конфиг.
  • Конфиги для разных приложений.
  • Конфиги для разных серверов.
  • Свой конфиг у разработчика.
  • Пароли нельзя держать в VCS.

Environments

  • Development
  • Production
  • Локальные *-local.php (игнорируется VCS)
install.php <environment>

У каждого свой index.php.

Как перекрываются конфиги

  1. common/config/params.php
  2. common/config/params-local.php
  3. frontend/config/params.php
  4. frontend/config/params-local.php

$config1 = array(...);
$config2 = array(...);
$finalConfig = CMap::mergeArray($config1, $config2);
                        

VCS, код, схема БД

Как хранить код

  • Git или другая VCS. Git очень удобен.
  • Ветки: master, release-X.X, feature-XXX.
  • Теги: X.X.Y
  • Релиз.

Что делать с базой?

  • base-schema.sql — начальная структура.
  • base-data.sql — начальные данные.


Миграции

  1. Не использовать модели и код приложения.
  2. Если ушла в VCS и запускалась, не править.
  3. Если ушла в VCS и не запускалась — поправить.
  4. Не лезть в базу руками.

Автоматизация и развёртывание

Серверы

  • Машина разработчика.
  • Тестовый.
  • RC.
  • Production.

Деплой

  1. Pull.
  2. Билд.
  3. Чистим APC (stat=0).
  4. Рестарт вебсервера (если нужен).


  • На тестовый сервер и локально — автоматом.
  • На RC и production — полуавтоматом.

$github_ips = array('207.97.227.253', '50.57.128.197', '108.171.174.178');

if(in_array($_SERVER['REMOTE_ADDR'], $github_ips)) {
    $dir = '/var/www/path/to/your/git/root';
    exec("cd $dir && git pull");
    echo 'Done.';
}
else {
    header('HTTP/1.1 404 Not Found');
    echo '404 Not Found.';
    exit;
}
                        

Билд

  • LESS/SCSS → CSS.
  • TypeScript → JavaScript.
  • Собрать и минифицировать CSS и JS.
    yiic compress all (в паблике нет).
    Жмёт, генерит файл аля all_123hash123.js, прописывает его в frontend/config/params-local.php.
  • Применить миграции yiic migrate.

Данные, хранилища, i18n

Данные

  • MySQL.
  • Кеш в APC.
  • noSQL только когда нужен.
  • Поиск SOLR/Sphinx.

Внешние API

  • Facebook.
  • Google.
  • Могут не работать.
  • Могут меняться.
  • Кеш.

i18n

  • UTF-8.
  • Collation.
  • Yii::t, исходник всегда английский.
  • С данными всегда по-разному…

Производительность

Преждевременная оптимизация

  • Узкие места будут не там, где вы думаете.
  • Все будут использовать проект «не так».
  • Рост можно контролировать.
  • Время.

Что тормозит?

  • Тормозит не там, где вы думаете.
  • Не всё можно воспроизвести локально.
  • Следите за изменениями.

Что делать?

  • Отложить выполнение.
  • Очереди.
  • SQL.
  • Кеш.

AR vs SQL

  1. AR кушает больше, работает медленней.
  2. DAO/SQL актуальны только если на странице 50+ записей.
  3. Для изменения данных намного удобней AR.

Внешние сервисы

Внешние vs внутренние

Внешние Внутренние
Latency. Нужно мониторить.
Ломаются. Нужно ставить.
Без напряга. Нужно поддерживать.
Стоят денег. Детали.
Гарантии. Нет гарантий.

Внешние сервисы

Clientside

JavaScript

  • Без CClientScript::registerScriptFile().
    
    return array(
        'jquery.js',
    
        'widget.login.js',
        'widget.friends.js',
    
        'module.user.js',
        'module.post.js',
    );
                                
  • Модульная система, по модулю на 1-2 страницы.
  • + виджеты, структура примерно как у jQueryUI.
  • Все скрипты описываются явно в конфиге, жмутся при деплое.

CSS

  • LESS / SCSS …
  • Перечислены в конфиге, жмутся явно при деплое.

@base: #f938ab;

.box-shadow(@style, @c) when (iscolor(@c)) {
  box-shadow:         @style @c;
  -webkit-box-shadow: @style @c;
  -moz-box-shadow:    @style @c;
}
.box-shadow(@style, @alpha: 50%) when (isnumber(@alpha)) {
  .box-shadow(@style, rgba(0, 0, 0, @alpha));
}
.box {
  color: saturate(@base, 5%);
  border-color: lighten(@base, 30%);
  div { .box-shadow(0 0 5px, 30%) }
}
                        

Соглашения CSS/JS

views/post/edit.php:


<div class="post-edit">...</div>
                        

css/post.css:


.post-edit p { ... }
.post-view h2 { ... }
                        

widgets/friends/views/index.php:


<div class="widget-friends-index">...</div>
                        

widgets/friends/assets/friends.css:


.widget-friends-index div { ... }
                                                
  • Глобальные классы g-*. Стили в global.css.
  • Layout использует префикс layout- и файл layout.css.

Документация и задачи

Документация

  • Readme.
  • API.
  • Комментарии.

Задачи

Полезняшки

Шорткаты в global.php

Подключаются в index.php после инициализации приложения, но до запуска:


$app = Yii::createApplication('CWebApplication', $config);
include 'global.php';
$app->run();
                        

Примеры:


function app() {
    return Yii::app();
}

function user() {
    return Yii::app()->user;
}

function db() {
    return Yii::app()->db;
}
                        

Шорткаты в global.php


function t($message, $params, $category = 'myproject') {
    return Yii::t($category, $message, $params);
}
function h($text) {
    return CHtml::encode($text);
}
function l(…) {
    return CHtml::link(…);
}
function param($name, $default = null) {
    return isset(Yii::app()->params[$name] ? Yii::app()->params[$name] : $default);
}
                        

Вопросы?