
Добрый вечер всем хабраюзерам!
Хочу поделиться определёнными идеями и соображениями на тему создания обособленных проектов в Yii на основе одного общего ядра.
Некоторое время назад, перейдя по рабочей надобности с kohana на yii, я долго радовался его простоте и удобству, которые, как мне казалось, были в разы больше, чем у коханы (да простят меня любители этого фреймворка), а потом, все по той же рабочей надобности, пришлось углубиться в архитектуру Yii, и, частности, в возможности дистрибуции его проектов от одного обособленного ядра.
Изначально, что называется, «из коробки», Yii уже поставляется отдельными папками с самим ядром и несколькими демо-проектами на нём, но мне этого было мало, поскольку требовались несколько другие возможности по управлению и контролю за проектами, на основе чего и были созданы те идеи, которые я хочу изложить.
Маленькие оговорки
Начнем с того, что я не буду сейчас заморачиваться тонкими настройками апача, php, или иных вещей, потому что хочу изложить просто идею и узнать ваше, дорогие хабраюзеры, мнение о том, стоит ли развивать предложенный способ дальше и каким образом его можно модифицировать, потому сразу оговорюсь, что все описанные ниже действия происходят на свежеустановленной убунте 11.10 и традиционным lamp из коробки.
Так же предполагается, что читатель уже знаком с основами Yii и хотя бы примерно знает его структуру каталогов.
Подготовка
Итак, изначально у нас самый простой хост с примерно такими настройками:
<VirtualHost *:80> ServerName demo.lori ServerAlias demo.lori www.demo.lori DocumentRoot /home/lori/workspace/demo.lori/www ErrorLog /home/lori/workspace/demo.lori/logs/error.log CustomLog /home/lori/workspace/demo.lori/logs/access.log common </VirtualHost>
З.Ы. Доменная зона .lori выбрана для тестов и из всех возможных вариантов смысла несет в себе только принятое в народе альтернативное имя вашего покорного слуги.
Папки логов ��ыли выбраны для более быстрого доступа к ним в процессе разработки (я не претендую на звание гуру в области юникса, и потому, если мне кто-то скажет, что это не кошерно, с радостью выслушаю).
Дополнительно, в папке workspace создаем папку с названием yii, куда распаковываем свежескаченный архив в Yii, а конкретнее, папку framework из него (на момент создания статьи последней стабильной версией фреймворка была 1.1.10). Отныне это и будет наше ядро, и (чисто теоретически, разумеется), в дальнейшем прикасаться к нему мы будем очень редко.
После этого в папке /home/lori/workspace/demo.lori/www организуем следующую структуру (согласно модифицированным для данного способа рекомендациям Yii):
— www/
—— index.php
—— .htaccess
—— config/
——— devel/
———— <конфиг-файлы локации разработки>
——— stable/
———— <конфиг-файлы локации продакшена>
—— engine/
——— <файлы проекта проекта>
—— themes/
——— basic/ (название основной темы)
———— static/
————— images/
————— css/
————— js/
———— views/
————— <файлы всех наших view по темам>
Теперь, согласно указанной выше организации, все файлы проекта (контроллеры, компоненты, модели и прочее), будут храниться в папке engine, предназначение папки themes не меняется, здесь будут храниться темы и другой статичный контент вроде CSS- или JS-файлов. Папка config тоже остается канонической, однако, её внутренности несколько изменятся.
После того, как все папки и файлы были созданы, осталось, как верно сейчас заметили знатоки Yii, создать папки runtime и assets, однако, здесь начинаются первые существенные изменения. Эти папки у нас будут организованы по-особенному.
Сразу замечание: все дальнейшие команды выполняются через sudo, потому указывать его не буду, предполагая, что все права у нас уже есть.
Создаем некий общий склад для наших проектов:
mkdir -p /home/projects/data/demo.lori cd /home/projects/data/demo.lori mkdir -p ./assets/stable mkdir -p ./runtime/stable mkdir -p ./upload/stable mkdir -p ./assets/devel mkdir -p ./runtime/devel mkdir -p ./upload/devel
Теперь нам нужно позволить нашему фреймворку создавать файлы в этих папках, для этого выполняем:
chown www-data -R /home/projects
(Тут тоже маленький вопросик знатокам *unix, есть ли какие-то замечания по поводу прав?)
Теперь все, что нам остается, это создать симлинки на эти папки в нашем проекте:
ln -s /home/projects/data/demo.lori/assets /home/lori/workspace/demo.lori/www/assets ln -s /home/projects/data/demo.lori/runtime /home/lori/workspace/demo.lori/www/runtime ln -s /home/projects/data/demo.lori/upload /home/lori/workspace/demo.lori/www/upload
UPD1 (На основе комментариев): зачем используется подобная структура каталогов
1) По теории Yii, в assets должны храниться файлы, которые так или иначе присоединяются к проекту, например, какие-то сторонние js-скрипты, css-файлы, картинки и прочие вещи, поэтому, если я использую во всех своих проектах, например, тривиальные JQuery или CSS-reset, то будет логичнее хранить их в одном месте вне всех проектов.
2) runtime выносить особого смысла не было, но чисто теоретически он не играет особой роли в разработке и нужен самому Yii, потому, чтобы не захламлять папку самого проекта, этот каталог вынесен за его пределы.
3) Удаленный и централизованный upload нужен для того, чтобы, например, в случае, когда в локальной сети развернута некая девел-среда, файлы, используемые в проектах, были общими для всех разработчиков, например, если в некотором проекте есть загрузка аватара пользователю, то логичнее делать так, что если один человек грузит картинку, то все остальные разработчики должны ее видеть, если на нее есть некоторая ссылка в базе данных.
На этом основные подготовки закончены, переходим непосредственно к настройке проекта.
Настройка точки входа
Начнём с файла index.php, он почти ничем не отличается от стандартной точки входа Yii, за исключением поправок на разделение локаций на девел и продакшн:
<?php date_default_timezone_set('Europe/Moscow'); error_reporting(E_ALL); ini_set('display_errors', 1); // Подключаем Yii $yii = dirname(__FILE__).'/../../yii/yii.php'; /* Определяем, в какой локации мы сейчас находимся. Тут возможны различные вариации, в зависимости от того окружения, где вы работаете. Хотелось бы услышать ваши предложения, как ещё можно хитро разделить эти локации. */ define('DEVELOP_LOCATION', (gethostname() == 'lori-desktop' ? 'devel' : 'stable')); /* Некий свой способ включить дебаг, подсмотренный на текущей работе. Носит исключительно костыльный смысл. */ if (array_key_exists('HTTP_LORI_DEBUG', $_SERVER) and $_SERVER['HTTP_LORI_DEBUG'] == 'DEBUG IT, DEBUG!') { defined('YII_DEBUG') or define('YII_DEBUG',true); defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL', 10); } /* Способ корректно обработать невидимое перенаправление в .htaccess. Если кто подскажет более элегантное решение, буду рад, ибо гуголь не помог. */ if ($_SERVER['REQUEST_URI'] != $_SERVER['REDIRECT_URL']) $_SERVER['REQUEST_URI'] = $_SERVER['REDIRECT_URL']; // Подключаем основной конфиг в зависимости от локации $config = dirname(__FILE__).'/config/'.DEVELOP_LOCATION.'/main.php'; require_once($yii); Yii::createWebApplication($config)->run();
Сам .htaccess выглядит на данный момент примерно так:
AddDefaultCharset UTF-8 RewriteEngine on RewriteBase / RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^upload/(.*)$ /forbidden [L] RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^assets/(.*)$ /forbidden [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^assets/(.*)$ /nofile [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^upload/(.*)$ /nofile [L] RewriteCond %{REQUEST_URI} !^/assets RewriteCond %{REQUEST_URI} !^/upload RewriteRule ^(.*)$ index.php [L]
Точки входа готовы, теперь необходимо настроить под них конфиги.
Настройка настроек :)
Я не буду расписывать создание настроек для каждой из локаций, и опишу действия для devel-локации, так как именно на ней будут происходить все изменения, а создание конфига для продакшн-локации происходит идентично.
Для начала, в папке config/devel/ создаем файл main.php. Он будет выглядеть, как обычный main.php из конфига любого проекта на Yii, но мы внесем в него некоторые дополнения согласно нашей файловой организации:
<? return array( // Все файлы проекта у нас теперь находятся в папке engine 'basePath' => dirname(__FILE__).'/../../engine/', 'name' => 'Demo project', // Указываем новый путь к runtime для текущей локации 'runtimePath' => dirname(__FILE__).'/../../runtime/devel', // Указываем нашу тему по умолчанию из папки /themes 'theme' => 'basic', 'preload' => ..., 'import' => ..., 'defaultController' => 'default', // Здесь есть изменения в путях к некоторым папкам 'components' => array( 'assetManager' => array( 'basePath' => dirname(__FILE__).'/../../assets/devel', ), 'user' => ..., 'db' => ..., 'errorHandler' => ..., 'urlManager' => array( 'urlFormat' => 'path', 'rules' => require_once dirname(__FILE__).'/routes.php', ), 'log' => ... ), 'params' => require(dirname(__FILE__).'/params.php'), );
В приведённом выше конфиге троеточия заменяют стандартные блоки кода, которых не касаются текущие изменения в файловой организации и которые потому не нуждаются в описании.
Дополнительно стоит сказать про настройку urlManager:
Мне не очень нравится, что по классической схеме роутинг путается с конфигом, потому я выношу его всегда в отдельный файл routes.php в той же папке, что и main.php, и содержит он обычную структуру вида
<? return array( 'var1' => 'value1' );
Послесловие
На этом, в принципе, вся основная настройка проекта завершается — проект настроен.
Плюсы данного подхода:
— Обособленность проектов друг от друга
— Один движок на все проекты, что позволяет обновлять его или дополнять один раз и для всех проектов сразу
— Наличие разделения на локации разработки и продакшена, со своими конфигами и включаемыми файлами
— Удобство при работе с системами контроля версий вроде Git
— В какой-то мере отделённый от проекта каталог темизации
Минусы:
— пока не обнаружено
Данный подход нравится мне своей гибкостью, ведь, если разобраться, его можно достаточно серьёзно расширять, оперируя локациями через htaccess, создавая отдельные конфиги для различных окружений, и многое другое, при этом, не заботясь о том, чтобы каждый раз, при добавлении какой-нибудь плюшки в ядро, переносить изменения по всем своим проектам (ведь ядро, так же, как и любой проект, является само по себе проектом, который так же можно изменять на девел-локации и выгружать на продакшн.
Если у кого-то будут какие-то замечания или вопросы, я буду рад выслушать и по возможности ответить или исправить какие-то места в приведённом примере.
Так же, я хотел бы поинтересоваться у общественности на тему необходимости создания некоторого цикла статей, посвящённого полному циклу создания проекта на Yii, потому что, честно говоря, подобных статей в сети я не нашел, в основном есть куча статей на отдельные темы вроде кэширования или валидации, а оригинальный гайд, представленный разработчиками, тоже не дает полноценного восприятия проекта на Yii как единого целого.
Спасибо всем, кто дочитал статью до конца!
UPD: Некоторые все же высказались, что курс статей это не такое уж и плохое предложение, тогда хотелось бы спросить: если делать цикл на тему разработки ОТ и ДО, то какой не тривиальный (вроде предложенных блогов или адресной книги) сайт вам хотелось бы увидеть?
