Добрый вечер всем читателям!
Хочу поделиться определёнными идеями и соображениями на тему создания обособленных проектов в 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 ./assets/stable
mkdir ./runtime/stable
mkdir ./upload/stable
mkdir ./assets/devel
mkdir ./runtime/devel
mkdir ./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
На этом основные подготовки закончены, переходим непосредственно к настройке проекта.
Настройка точки входа
Начнём с файла 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 как единого целого.
Спасибо всем, кто дочитал статью до конца!
Автор: Melorian