Введение в возможности CakePHP (как-создать-приложение-за-15-минут)

November 26, 2008 | By admin | Filed in: CakePHP, Переводы.

Вторая статья из серии переводов фида Кейкпхп. Оригинал здесь. Как перевести здоровенную статью за полчаса?.

Поехали.

Я бы хотел показать всю мощь CakePHP, создав вводное руководство, в котором будут рассмотрены некоторые базовые аспекты, а также более продвинутые техники, как, например, использование компонента авторизации пользователей Auth.

Цель данного руководства – создать работающее приложение, включающее следующую функциональность: регистрация пользователей, вход/выход пользователя из системы, домашняя страница пользователя, базовый контроль доступа, валидация данных (форм) и возможность дальнейшего гибкого развития приложения. И да, все это менее, чем за 15 минут, и всего лишь в 120 строках кода…

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

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

Давайте начнем…

Нам нужна таблица в БД для данных о пользователях (пример для MySQL):


CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(200) NOT NULL,
`email` varchar(200) NOT NULL,
`username` varchar(200) NOT NULL,
`password` varchar(200) NOT NULL,
`status` tinyint(1) NOT NULL default '1',
`company_id` int(11) NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;

Далее мы создаем “глобальный” контроллер – AppController. Его свойства и методы доступны всем остальным контроллерам приложения.

Создайте в главной папке вашего приложения (что-то вроде /home/teknoid/cake/app) файл app_controller.php следующего содержания:


class AppController extends Controller {
var $components = array('Auth');

function beforeFilter() {
$this->Auth->allow('display');
$this->Auth->loginRedirect = array('controller'=>'users', 'action'=>'index');
}
}

Посмотрим, что у нас здесь…
Мы знаем, что нам понадобится аутентификация пользователей в нашем приложении, поэтому мы подключаем компонент для этого с помощью var $components = array('Auth');
Далее мы создаем специальную функцию beforeFilter(), которая будет выполняться перед каждым действием в нашем приложении. Это самое подходящее место для того, чтобы сообщить компоненту аутентификации необходимую информацию.
Например, мы разрешаем выполнение специального действия  ‘display’: $this->Auth->allow('display'), а также сообщаем компоненту, что после входа в систему пользователь должен быть перенаправлен на действие ‘index’ (что соответствует домашней странице пользователя): $this->Auth->loginRedirect = array('controller'=>'users', 'action'=>'index');.
Я не буду углубляться в детали данных настроек, но в общем это довольно простой и общий способ настройки аутентификации приложения CakePHP.

Далее мы создаем UsersController.
В папке app/controllers создайте файл users_controller.php. Вот такой:


class UsersController extends AppController {

var $name = 'Users';
var $helpers = array('Time');

function beforeFilter() {
parent::beforeFilter();

if($this->action == 'add') {
$this->Auth->authenticate = $this->User;
}

$this->Auth->allow('add');
}

function index() {
$this->set('user', $this->User->find('first',
array(
'conditions'=>array(
'User.id'=>$this->Auth->user('id')))));
}

function add() {
if(!empty($this->data)) {
$this->User->save($this->data);
}
}

function login() {

}

function logout() {
$this->redirect($this->Auth->logout());
}

}

Что у нас здесь…
Мы подключили хелпер Time: var $helpers = array('Time');, который, в частности, помогает форматировать в удобочитаемый вид дату и время из базы данных. Позже мы используем его для форматирования даты/времени на странице пользователя.

Как вы могли заметить, у нас присутствует еще одна функция beforeFilter(), как и в App Controller. В данном случае мы наследуем родительскую (из AppController) функциональность, используя parent::beforeFilter(), и указываем дополнительные настройки для компонента Auth, которые касаются только UsersController.

Хочу заметить, что компонент Auth автоматически хеширует пароли при помощи sha1() и salt-значения, которое вы установили при настройке CakePHP. Убедитесь, что поле для пароля в вашей БД имеет достаточную длину для хранения хешированного пароля (мы не будем хранить пароли в открытом виде ).

Вот эта строчка –  $this->Auth->authenticate = $this->User; – может показаться немного необычной…
Если вкратце, то компонент Auth позволяет нам подменять некоторую базовую функциональность, что хорошо сказывается на гибкости приложения. Лично у меня были некоторые нестыковки с хешированием пароля данным компонентом, но, как видите,  только в действии ‘add’: if($this->action == 'add'). В данном случае я использовал собственный объект для аутентификации (модель User). Просто запомните это, позже все станет ясно.

Чтобы обеспечить безопасность приложения с самого начала, нужно явно обозначить, какие действия мы позволим выполнять пользователю до входа в систему. По умолчанию, Auth-компонент будет перенаправлять пользователя на страницу входа независимо от того, какую страницу тот пытается просмотреть. Конечно, пользователя это могло бы сильно обескуражить, если бы мы не указали, что действие ‘add’ может быть выполнено и без входа: $this->Auth->allow('add');.
Важно, что Auth заведомо считает действия ‘login’ и ‘logout’ доступными пользователю всегда, и их не нужно указывать в списке разрешенных действий.

Ок, базовая настройка проведена, и мы добавили несколько действий в UsersController.

index() Это будет домашняя страница нашего пользователя. Помните, как мы указали компоненту Auth, что пользователя нужно направить сюда: $this->Auth->loginRedirect = array('controller'=>'users', 'action'=>'index');? Теперь для этого все готово. Мы просто получаем всю информацию о вошедшем пользователе и передаем ее в представление.

add() Здесь все ясно – регистрация пользователя.

login() Довольно просто получить базовую функциональность возможности входа в систему… т.е. вам даже код не нужно писать для этого. Компонент Auth все сделает за вас. Конечно, вы можете изменить все, как это нужно вам, если хотите чего-то большего.

logout() Когда пользователь переходит по ссылке “Выход”, он попадает снова на страницу логина. Для примера этого вполне достаточно.

Теперь, когда некоторые действия готовы, давайте создадим представления для каждого из них (представление, по сути, и есть страница, которую пользователь увидит в браузере).

Идем в app/views/ и создаем папку ‘users’. В нее мы добавляем файл для каждого действия (кроме logout, т.к. для него представление не требуется).

index.ctp – домашняя страница


<?php echo $html->link('Log out', array('controller'=>'users', 'action'=>'logout')); ?>

<div>
Hello, <?php echo $user['User']['name']; ?>
</div>

<div>
Your account was created <?php echo $time->niceShort($user['User']['created']); ?>
</div>

Очень простая страница, но по ней видно, как можно получить доступ к различной информации пользователя в представлении. Если вы посмотрите на действие index() в UsersController, то увидите, что мы присваиваем значение переменной $user, содержащей массив данных пользователя, который теперь можно вывести на странице.
Помните, как мы подключали хелпер Time в UsersController? Теперь мы используем его для перевода значения типа DATETIME из БД в приятную для человеческого взгляда конструкцию: echo $time->niceShort($user['User']['created']);

login.ctp – вход в систему


if  ($session->check('Message.auth')) $session->flash('auth');
echo $form->create('User', array('action' => 'login'));
echo $form->input('username');
echo $form->input('password');
echo $form->end('Login');

Хоть нам и не нужно писать код для действия login(), форму для ввода данных пользователем создать придется. Ничего сверхъестественного, единственное – обратите внимание на первую строку: if ($session->check('Message.auth')) $session->flash('auth');, которая позволяет отобразить сообщения от компонента Auth.

add.ctp – регистрация


echo $form->create();
echo $form->input('name');
echo $form->input('email');
echo $form->input('username');
echo $form->input('password');
echo $form->input('password_confirm', array('type'=>'password'));
echo $form->end('Register');

Здесть мы создаем форму для регистрации. Ничего особенного, просто форма, созданная при помощи хелпера Form.

Теперь попробуйте следующее:

Перейти по адресу http://yourlocalhost/users/shouldntAccessThis
– Компонент Auth должен перенаправить вас на страницу входа, т.к. мы не указали действие ’shouldntAccessThis’ среди разрешенных.

Перейти по адресу http://yourlocalhost/users/add
– Вы должны увидеть форму регистрации

Пока все идет нормально. Теперь нужно добавить пару правил валидации для регистрационной формы…
Для этого мы создаем модель User.

В папке app/models/ создайте файл user.php

user.php


class User extends AppModel {

var $name = 'User';

var $validate = array(
'name'=>array(
'rule'=>array('minLength', 4),
'message'=>'Name has to be at least four characters'),

'email'=>array(
'rule'=>array('email'),
'message'=>'Please enter a valid email'),

'username'=>array(
'Username has to be at least four characters'=>array(
'rule'=>array('minLength', 4)
),
'This username is already taken, please try another'=>array(
'rule'=>'isUnique'
)),

'password'=>array(
'Password cannot be empty'=>array(
'rule'=>array('notEmpty')
),
'Password must be at least four characters'=>array(
'rule'=>array('minLength', 4)
),
'Passwords must match'=>array(
'rule'=>array('passwordCompare', 'password_confirm')
))
);

function passwordCompare($data, $fieldTwo) {

if($data['password'] != $this->data[$this->alias][$fieldTwo]) {
$this->invalidate($fieldTwo, 'Passwords must match');
return false;
}

return true;
}

function hashPasswords($data, $enforce=false) {

if($enforce &amp;&amp; isset($this->data[$this->alias]['password'])) {
if(!empty($this->data[$this->alias]['password'])) {
$this->data[$this->alias]['password'] = Security::hash($this->data[$this->alias]['password'], null, true);
}
}

return $data;
}

function beforeSave() {
$this->hashPasswords(null, true);

return true;
}
}

Вот и самая здоровая часть нашего приложения. Модель User занимается проверкой данных, а также заменяет некоторую функциональность компонента Auth. Помните, мы изменили изначальное поведение компонента в этой строчке действия ‘add’: $this->Auth->authenticate = $this->User; ? Я написал собственный метод hashPasswords(), который заменяет базовый. Не вдаваясь в подробные объяснения, скажу только, что предпочитаю хешировать пароли прямо перед сохранением данных (отсюда и метод beforeSave()), поскольку это упрощает жизнь, заодно демонстрируя гибкость компонента Auth.

Теперь рассмотрим метод passwordCompare(). Это специальный метод для сравнения значений полей ‘password’ и ‘password_confirm’ из формы регистрации.
Данная конструкция – $this->invalidate($fieldTwo, 'Passwords must match'); – приведет к тому, что поле ‘password_confirm’ будет помечено как ошибочное в случае несовпадения значений. Это пригодится в случае, если у вас есть CSS, который, например, обозначает поля, содержащие ошибку, красным цветом (заметьте, мы вдобавок устанавливаем сообщение об ошибке).
Еще одна фича (не уверен, что документированная) – использование удобочитаемых названий для правил валидации. Это полезно при наличии нескольких правил, как, например, с полем ‘password’. В случае возникновения ошибки в качестве текста сообщения об ошибке будет использовано название правила.

Теперь попробуйте запустить приложение как с ошибочными, так и с правильными данными… Если все пойдет , как надо, вы увидите лог SQL-запросов вставки данных пользователя в БД, что говорит о том, что форма работает корректно.

Вот и все… Полностью функциональное приложение за 10-12 минут. [а статья за 1:10]


One comment on “Введение в возможности CakePHP (как-создать-приложение-за-15-минут)

  1. […] по сути, продолжение статьи про быстрое создание приложения на Cake PHP. Оригинал – […]

Leave a Reply