Пример создания простого приложения в Kohana framework. Часть 1.

Собеседовался я как-то на днях в наверное крупную компанию, во всяком случае есть о них страница в википедии. Скажу сразу – провалился 🙂
Разберу, может быть, если и когда дойдут руки до этого дела пару-тройку вопросов из собеседования.

Жаль не догадался включить запись экрана со звуком, был бы материал для разбора полетов. Ну да ладно.

Так вот, последнее задание натолкнуло на мысль сделать несколько небольших статей по созданию простого приложения.
Описать, как создается приложение для Kohana и как для Grails. Интерес тут в том, что на Kohana как-то уже полгода ничего не писалось, и хочется вспомнить, и второе – сравнить тем, как пишется на Grails.

Тестовое приложение на php mvc фреймворке Kohana

Что должно делать примерное приложение

Простое приложение должно будет делать следующие вещи (практически по заданию):

  1. Авторизация пользователя. Этого не было в задании, но думаю, что без этого пример будет не полным.
  2. Проверка прав пользователя
  3. Управление двумя сущностями – пользователь и группа.
  4. Должен быть функционал – создания; удаления, причем группу удалить можно, только если в ней нет
    пользователей; добавления пользователя в группу (если данного пользователя там еще нет); удаления пользователя
    из группы

Итак, начнем.

Схема базы данных.

Будут две таблицы, groups и users, для групп и юзеров соответственно.
В именовании таблиц следуем соглашению – модель будет называться user, соответственно таблица должна называться users.
Такое наименование не обязательное, но следуя этому соглашению таблицы будут подхватываться orm автоматически.

Также соглашением предусматривается, что у каждой таблицы должно быть поле с именем “id”, являющийся первичным ключом.

Т.к. в задании никак не указывается ограничения, например, пользователь может учавствовать только в одной группе, то буду считать, что пользователь может быть одновременно в нескольких группах. Так получается связь многие-ко-многим. Для ее реализации создам еще таблицу users_groups.

В этой таблице будет всего 2 поля – user_id и group_id, являющиеся внешними ключами, и ссылающимися соответсвтенно на таблицы пользователей и групп.

Так как таблицы создавались через редактор, то имена индексов такие страшные 🙂

CREATE TABLE backtestgr.user (
	id                   bigint  NOT NULL  AUTO_INCREMENT,
	password             varchar(255)  NOT NULL  ,
	name		             varchar(255)  NOT NULL  ,
	CONSTRAINT pk_user PRIMARY KEY ( id ),
	CONSTRAINT `UK_sb8bbouer5wak8vyiiy4pf2bx` UNIQUE ( name )
 );

 CREATE TABLE backtestgr.group (
	id                   bigint  NOT NULL  AUTO_INCREMENT,
	name		             varchar(255)  NOT NULL  ,
	CONSTRAINT pk_role PRIMARY KEY ( id ),
	CONSTRAINT `UK_irsamgnera6angm0prq1kemt2` UNIQUE ( name )
 );

CREATE TABLE backtestgr.users_groups (
	group_id              bigint  NOT NULL  ,
	user_id              bigint  NOT NULL  ,
	CONSTRAINT pk_user_role PRIMARY KEY ( group_id, user_id )
 );

CREATE INDEX FK_apcc8lxk2xnug8377fatvbn04 ON backtestgr.users_groups ( user_id );

ALTER TABLE backtestgr.users_groups ADD CONSTRAINT `FK_it77eq964jhfqtu54081ebtio` FOREIGN KEY ( group_id ) REFERENCES backtestgr.group( id ) ON DELETE NO ACTION ON UPDATE NO ACTION;

ALTER TABLE backtestgr.users_groups ADD CONSTRAINT `FK_apcc8lxk2xnug8377fatvbn04` FOREIGN KEY ( user_id ) REFERENCES backtestgr.user( id ) ON DELETE NO ACTION ON UPDATE NO ACTION;

db.schema

Настройка Kohana

Настройка виртуального хоста

Для начала нужно настроить виртуальный хост для того, чтобы локально запускать приложение. Буду считать (а так оно и есть), что Apache, MySQL и php уже установлены и проверены.

Для начала, в папке, куда есть доступ для вебсервера (у меня пользователь www-data) создаю каталог, где будет раположено приложение. Получился такой путь /var/www/backtest.

У меня веб-сервером крутится apache2, и файлы параметров вирутальных хостов лежат тут – /etc/apache2/sites-available

Создаем тут файл backtest.loc.conf со следующим содержимым:

    <VirtualHost *:80>
        ServerName              backtest.loc
        ServerAlias             www.backtest.loc

        DocumentRoot /var/www/backtest

        <Directory /var/www/backtest/ >
        Options FollowSymLinks ExecCGI Includes Indexes
        AllowOverride All
        Require all granted
        </Directory>

        ErrorLog        /var/log/apache2/backtest.loc-error.log
        CustomLog       /var/log/apache2/backtest.loc-access.log        combined
    </VirtualHost>

В этом файле прописаны имя хоста, путь к его корню, пути к файлам логов доступа и ошибки, настройки для каталога корня.

Теперь разрешим этот хост. В консоли:

a2ensite backtest.loc.conf

После удачного выполнения команды нужно будет перегрузить конфигурацию apache:

service apache2 reload

Далее нужно прописать в файле хостов (/etc/hosts), что нужно искать backtest.loc на локалхосте – добавить запись:

127.0.0.1  bastest.loc

Мне этого делать не нужно, т.к. у меня настроен dnsmasque и все *.loc хосты ищутся на локалке.

Установка Kohana

Теперь нужно скачать фреймворк. Взять его можно на kohanaframework.org. На момент написания этой заметки последняя стабильная версия 3.3.2
Скачиваем, распаковываем так, чтобы index.php и install.php были в DocumentRoot хоста. Для того, чтобы можно было уйти дальше вглубь от корня сайта (даллее корень сайта – слеш после доменного имени bastest.loc для url и DocumentRoot хоста для файлов).

Если нужно меняем владельца файлов на пользователя – вебсервера (www-data). В любом случае нужно сделать доступными для записи и просмотра каталоги – application/cache и application/logs. Если настройка доступа к этим папкам забылась, то при первом запуске будет выполнен файл install.php, который и проверит это и еще разные вещи.

После проверки работспособности (или соответствия настроек хоста требуемым файл install.php можно удалить.
Осталось переименовать example.htaccess в .htaccess

На данном этапе, если в браузере открыть наш локальный адрес backtest.loc, должно выводиться “Hello world!” – это результат работы демонстрационного контроллера.

Настройка параметров

Теперь если установлена версия php 5.5, а может быть и еще некоторые ранее (не проверял), то просто использовать орм не получится: использование mysql драйвера (покажу далее в настройках бд) вызовет ошибку из-за использования deprecated mysql-функций. Так же использовать pdo не получится, т.к. для орм нужно получать среди прочего список столбцов таблицы, а pdo этого не делает. В следующих выпусках разработчики Kohana обещают включить в поставку mysqli.

Самое простое решение в нашем случае – в файле index.php отключить проверку ошибок:

error_reporting(E_ALL & ~E_DEPRECATED);

На том же уровне, что и index.php по-умолчанию находятся 3 каталога:

application
Каталог приложения. Тут будет весь код примера.
modules
Каталог модулей. Тут располагаются модули – готовые “кирпичики” – код, который можно использовать как самостоятельную единицу для разных приложений.
system
Какталог фреймворка. Тут собственно и располагается Кохана

Параметры bootstrap.php

В этом файле находятся основные параметры приложения.

Если все установлено так, как описано выше, никакие каталоги не переименовывались и не перемещались, то изменить в настройках нужно немного.

Таймзона – по-умолчанию стоит таймзона для Чикаго, я поставил – Europe/Moscow.
Окружение (environment) – для этого примера (т.к. не пердполагается публикация в продакшене) задал напрямую. Нашел строку

if (isset($_SERVER['KOHANA_ENV'])) ...

и после закрытия тела условного оператора добавил такую строчку:

Kohana::$environment = Kohana::DEVELOPMENT;

Вообще у Коханы можно делать некоторые настройки/проверки и просто код, зависимым от того, какое стоит окружение (продакшен, девелопмент или тестинг).
И очень удобно настроить соответствующую переменную в параметрах виртуального хоста апача через SenEnv.
Но нужно учитывать, что если предполагается использовать вызов приложения из командной строки, например через крон, то будет использоваться другой php.ini, чем при запросе через веб-сервер.

Соль – это следующее, что потребуется для работы с куками/сессиями. Это просто уникальная строка, которая будет добавляться в качестве соли, например, к паролям при авторизации.

Cookie::$salt = 'тут какая-то уникальная строка';

Параметры инициализации – задаются в виде ключей – значений массива параметра для функции Kohana::init().
В частности можно отключить использование index.php файла из url, чтобы строка запроса выглядела, например так

mysite.com/catalog/view/14

вместо дефолтного вида:

mysite.com/index.php/catalog/view/14

Выглядеть это будет так:

    Kohana::init(array(
	    'index_file' => false
    ));

Следующее интересное в bootstrap.php – подключение модулей.
Подключение модулей – задается также в виде массива параметром при вызове функции Kohana::modules().

Модули в Кохане располагаются в каталоге modules. Но используются и запускаются только те, которые будут указаны в массиве для данной функции.
По-умолчанию сейчас перечисляются модули, как говорится – бандлед и все они закомментированы. Для текущего примера нужно будет раскомментировать модули auth, database, orm.

auth
базовые средства для аутентификации пользователей
database
средства для работы с бд – параметры подключения, запросы, рекордсеты и т.п. для того, чтобы не задумываться как отправить запрос к бд.
orm
Object Relation Mapping. Довольно удобно в простых случаях не писать ручками простую установку значений для полей таблицы, а установить их в объектной нотации. В этом слуачае orm возьмет на себя получение колонок из таблицы и построение sql по их заполнению.

Настройка параметров подключения к базе данных

После того как был подключен модуль database в приложении стала доступен функционал работы с базой данных. Настройки для модулей могут быть указаны в самом модуле – в папке config в каталоге самого модуля.
А могут быть указаны в настройках приложения – в папке application/config. Правильным, я думаю, держать настройки, отличающиеся от дефолтных в приложении. То есть для настроек соединения с базой данных нужно скопировать файл modules/database/config/database.php в каталог application/config.
Файлы настроек в Кохане, в принципе, просто возвращают массив с ключами – именами параметров и value элементов массива – это значения параметров.
В файле настроек для базы данных могут быть параметры для нескольких подключенй, то подключение, параметры которого имеют ключ defaults будут автоматически подхвачены фреймворком.

Вообще про использование нескольких баз данных можно почитать на форуме и в документации.
Для текущего примера достаточно будте задать параметры для соединения с mysql базой данных:

    'default' => array
	(
		'type'       => 'MySQL',
		'connection' => array(
			/**
			 * The following options are available for MySQL:
			 *
			 * string   hostname     server hostname, or socket
			 * string   database     database name
			 * string   username     database username
			 * string   password     database password
			 * boolean  persistent   use persistent connections?
			 * array    variables    system variables as "key => value" pairs
			 *
			 * Ports and sockets may be appended to the hostname.
			 */
			'hostname'   => 'localhost',
			'database'   => 'backtest',
			'username'   => 'root',
			'password'   => 'qwerty',
			'persistent' => FALSE,
		),
		'table_prefix' => '',
		'charset'      => 'utf8',
		'caching'      => FALSE,
	),

Тут указано, что бд типа MySQL располагается на локальном хосте, база данных называется backtest, параметры тестового пользователя – имя root, пароль – qwerty )), и указано, что соединение держать не надо.
Также дополнительно указано, что префикса таблиц нет, кодировка utf8 и не нужно кэшировать.
Все, сейчас этого достаточно.

Роутинг

Вообще-то роутинг отностится к настройке параметров. Но это довольно сущетсвенная тема для работы приложения, поэтому несколько слов отдельно.
Почитать про разные параметры роутинга можно в документации на сайте коханы, посмотреть на их форуме или тут brotkin.ru/tag/routing/.

Я вообще не запоминаю как можно настроить роутинг, я считаю это как и регулярки – справочные темы, которые настраиваются один раз. Почитал как настраивать, создал выражения с настройками и забыл.

Итак, по-умолчанию настройки роутинга расположены в bootstrap.php, но при разрастании приложения можно выносить в отдельный файл, а в bootstrap.php просто инклюдить.
При задании роутов (маршрутов) нужно помнить о том, что чем ниже по коду расположен роут, тем более общее у него выражение. Это делается для того, чтобы роуты не “затирались”.
Так, например, если роут содержит общее выражение, а ниже расположен более частный случай, то до более частного случая выполнение не дойдет – будет использован первый найденный роут.

По-умолчанию в Кохане самый общий случай:

    Route::set('default', '(<controller>(/<action>(/<id>)))')
    ->defaults(array(
    'controller' => 'start',
    'action'     => 'index',
    ));

Общая структура задания выражения для роута такая: вначале имя роута, далее выражение, на соответствие которому и будет проверяться url запроса, далее могут быть ограничения на здначения параметров выражения роута, далее добавляются дефолтные значения, которые будут использованы при отсутствии в url каких-то параметров
Параметрами, которые должны быть обязательно – контроллер (controller) и метод (action). Тут в выражении любые параметры необязательны, появляться они могут не произвольно, а последовательно, т.е. нельзя задать action без задания controller, но для обязательных из них прописаны дефолтные значения.

Еще я задал два маршрута – login_logout и api, которые будут задавать маршруты соответственно для авторизации/выхода пользователей и собственно основного функционала примера.

    Route::set('login_logout','<action>',array('action'=>'(login|logout)'))
    ->defaults(array(
    'controller' => 'start'
    ));

    Route::set('api','<target>/<action>(/<id>)',array(
        'target'=> '(user|group)',
        ))
        ->defaults(array(
        'controller' => 'start',
        //		'action'=>'index'
        ));

С основными настройками пока все. В следующем посте будет непосредственно по заданию

Вторая часть

Tags:,
5 Comments
  1. Alexander Wilhelm
  2. UlvHare
  3. shrewmus
  4. find-way.net
    • shrewmus

Leave a Reply

Your email address will not be published. Required fields are marked *