Pull to refresh

Дискретные проекты Yii на основе общего ядра

Reading time 7 min
Views 7.1K

Добрый вечер всем хабраюзерам!

Хочу поделиться определёнными идеями и соображениями на тему создания обособленных проектов в 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: Некоторые все же высказались, что курс статей это не такое уж и плохое предложение, тогда хотелось бы спросить: если делать цикл на тему разработки ОТ и ДО, то какой не тривиальный (вроде предложенных блогов или адресной книги) сайт вам хотелось бы увидеть?
Tags:
Hubs:
+9
Comments 34
Comments Comments 34

Articles