Как стать автором
Обновить

Yii app для начинающих. Часть 1 — структура и конфигурация

Привет, %username%.

В сети встречал много вопросов касательно того, как бы правильней писать приложения с замечательным фреймворком Yii. Хочу поделиться своим видением данного вопроса… Всех заинтересованных — прошу под кат.

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

Структура


Начнем со структуры приложения. Так как статья для начинающих, то ограничимся одной папкой приложения (более опытные пользователи могут разделить на common, frontend, backend, api,… и так далее).

Структура приложения
image


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

Начнем по ходу выполнения приложения. Не хочу сюда копировать тонны кода — предлагаю Вам подглядывать исходные коды файлов из репозитория. Так же надо скопировать папку framework из дистрибутива Yii — незачем хранить целый фреймворк в репозитории, за исключением случаев, когда вносятся ручные изменения в исходники.

Инициализация/запуск


web/index.php — наш входной скрипт. Как видно из комментариев, сначала инициализируем вспомогательные константы, конфигурируем PHP, определяем вспомогательные функции Yii и оборачиваем запуск приложения в функцию, чтобы не плодить 9000 глобальных переменных.
Остановим внимание на компиляции конфига. Он собирается с помощью функции CMap::mergeArray, которая рекурсивно склеивает массивы, что очень удобно в нашем случае.
Дальнейшие настройки приложения выходят за рамки этой статьи, лишь добавлю, что мы используем обертку над стандартным компонентом Request и Controller.

Примечание по поводу файлов конфигурации

В репозитории нет файла app/config/local.php. Его прототип лежит в app/config/local.example.php — там хранятся настройки подключения к базе данных и кэширования. Это сделано по двум причинам:
  • Каждый разработчик/сервер имеет свои настройки
  • Пароли не хранятся в репозитории

Есть еще один нюанс — app/config/params.php (будем использовать в следующей статье) подгружаем не сразу, а после инициализации приложения — это сделано для того, чтобы внутри него мы могли использовать компоненты приложения, такие как user.

Обзор скомпилированного конфига


config
Array
(
    [basePath] => /home/misha/bingo/app
    [import] => Array
        (
            [0] => application.components.*
            [1] => application.models.*
        )

    [preload] => Array
        (
            [0] => log
        )

    [components] => Array
        (
            [log] => Array
                (
                    [class] => CLogRouter
                    [routes] => Array
                        (
                            [0] => Array
                                (
                                    [class] => CWebLogRoute
                                    [levels] => info, trace
                                    [except] => system.CModule.*
                                    [showInFireBug] => 1
                                    [collapsedInFireBug] => 1
                                )

                            [1] => Array
                                (
                                    [class] => CProfileLogRoute
                                    [showInFireBug] => 1
                                )

                        )

                )

            [request] => Array
                (
                    [class] => Request
                    [enableCsrfValidation] => 1
                    [csrfTokenName] => h
                )

            [session] => Array
                (
                    [class] => CCacheHttpSession
                    [sessionName] => s
                    [cookieParams] => Array
                        (
                            [httponly] => 1
                        )

                )

            [urlManager] => Array
                (
                    [urlFormat] => path
                    [useStrictParsing] => 1
                    [showScriptName] => 1
                    [rules] => Array
                        (
                            [] => site/index
                        )

                )

            [db] => Array
                (
                    [connectionString] => mysql:host=127.0.0.1;dbname=test
                    [username] => root
                    [password] => 
                    [enableParamLogging] => 1
                    [enableProfiling] => 1
                )

            [cache] => Array
                (
                    [class] => CMemCache
                )

        )

)



basePath — путь к папке приложения, по которому будет создан алиас пути «application».
import — список алиасов и путей, которые будут использоваться автозагрузчиком классов. По данным маскам мы подключаем папки app/components и app/models.
preload — компоненты, которые надо инициализировать сразу. Иначе компонент будет инициализирован при первом обращении (lazy load).
components — собственно, самый ужас для начинающих, давайте разбираться. :)

Компоненты

log — логирование (с) к.о. В режиме dev собираем логи по категориям info и trace (за исключением вызовов system.CModule, чтобы не плодить component xxx loaded ...) в консоль браузера, а так же логи по профайлингам. В режиме продакшн пишутся логи ошибок и предупреждений в app/runtime/application.log (по умолчанию для CFileLogRoute).
request — компонент request, включаем защиту от csrf и ожидаем хэш по ключу «h» для POST/PUT/DELETE запросов. Класс переопределен на Request — он выполняет дополнительные манипуляции над входящими данными. Обратите внимание, если бы мы не подключили папку «application.components.*» в импорте, то в данном поле «class» пришлось бы писать «application.components.Request».
session — сессии. Используем класс CCacheHttpSession для хранения сессий в кэше, в нашем случае — memcache. Если вы используете несколько компонентов кэширования, скажем cache и cache2, и хотите хранить сессии в cache2 — используйте настройку cacheID (к слову, такая настройка есть у всех компонентов, которые так или иначе используют кэш). Так же мы указали, что сессии должны быть в режиме HttpOnly.
urlManager — ака роутер. Используем формат «path» для роутинга в виде /foo/bar. Параметр «useStrictParsing» говорит, что следует использовать правила только из поля «rules», иначе попробует загрузить пару controller/action для запрошенного пути. «showScriptName» — я использую значение IN_DEV, которое подставилось в единичку, чтобы во время разработки генератор ссылок (о нем в следующей части) добавлял index.php перед созданными ссылками — "/index.php/controller/action?foo=bar" вместо '/controller/action?foo=bar". И последнее поле, «rules» — ничего заоблачного, все великолепно описано в документации.
db — компоненты для работы с базой данных. Параметры «enableParamLogging» и «enableProfiling» подставились из конфига dev.php, то есть в режиме продакшн эти настройки использоваться не будут, а наоборот, добавится кэширование схемы баз для увеличения производительности.
cache — кэширование. Используем старый добрый надежный memcache. Внимание! Пользователи комплекса open-server иногда могут наблюдать ошибки вроде «Memcache pool ...», если не указано поле «servers» для кэширования через адаптер «memcache». Это можно исправить. Замените «localhost» на «127.0.0.1» в framework/caching/CMemCache:101

Немного о компонентах в целом


Хотел бы добавить, что по сути все компоненты Yii — это объекты определенного класса, а все настройки — зачастую его свойства.
Внимательней читайте документацию, все замечательно и понятно расписано.

Разработка в IDE


Для корректной работы в IDE файл «framework/yiilite.php» следует помечать как текстовый, либо игнорировать.
Так же я всегда ингорирую, либо исключаю папки «framework/cli», «framework/gii», «framework/vendors», «framework/web/js/sources». Иначе возможны проблемы с автокомплитом php/js.

To be continued..


Пока что все, надеюсь кому-то эта статья будет полезной. В следующей части расскажу о нескольких виджетах, моделях и кэшировании.
До встречи.
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.