Добро пожаловать в Cake! Возможно вы просматриваете это обучение, потому что хотите узнать больше о том как работает Cake. Это наша цель, увеличить продуктивность и сделать написание кода более приятным: мы надеемся вы осознаете это, когда углубитесь в код.
Это обучение проведет вас через создание простого приложения блогов. Мы будем доставать и устанавливать Cake, создавая и настраивая базу данных, создавать достаточно кода приложения, чтобы просматривать, добавлять, редактировать и удалять посты в блоге.
Вот, что вам понадобится:
Давайте начнем!
Сначала давайте достанем копию свеженького кода Cake. Самый последний релиз на момент этой документации это Cake PHP? 1.0.1.2708.
Для скачивания посетите проект Cake PHP? на Cakeforge: http://cakeforge.org/projects/cakephp/ и закачайте стабильный релиз.
Также можете посмотреть здесь: https://svn.cakephp.org/repo/trunk/cake/1.x.x.x/
Не важно как вы закачали, поместите код в ваш Document Root?. Директория должна выглядить как-то так:
Теперь неплохо будет узнать немного о том, как работает структура директории Cake: взгляните на Главу «Основные концепции» Раздел 3: Обзор размещения файлов Cake.
Далее, давайте настроем основную базу данных для нашео блога. Сейчас, мы просто создадим простую таблицу для хранения постов. Мы также вкинем туда несколько постов, чтобы ипользовать их в целях тестирования. Выполните следующий запрос SQL в вашей базе данных:
/* Сначала, создайте таблицу постов: */
CREATE TABLE posts (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(50),
body TEXT,
created DATETIME DEFAULT NULL,
modified DATETIME DEFAULT NULL
);
/* Затем вставим пару постов для тестирования: */
INSERT INTO posts (title,body,created)
VALUES ('The title', 'This is the post body.', NOW());
INSERT INTO posts (title,body,created)
VALUES ('A title once again', 'And the post body follows.', NOW());
INSERT INTO posts (title,body,created)
VALUES ('Title strikes back', 'This is really exciting! Not.', NOW());
Выбор имен таблицы и колоноки не случаен. Если вы следуете соглашению о присвоении имен баз данных Cake, и соглашению о присвоении имен классов Cake (оба выделены в дополнении «Соглашение Cake»), вы сможете получить выгоду из множества бесплатной функциональности и избежать настройки. Cake гибкий достаточно, чтобы совладать с самой страшной схемой базы данных, но твердое поддерживание соглашения сохранит ваше время.
Посмотрите на Соглашение Cake для справки, но достаточно сказать, что название таблицы 'posts' автоматически привязывает ее к модели Post, а поля названные 'modiefied' и 'created' автоматически будут управляться Cake'ом.
Давайте сообщим Cake где находится наша база данных и как с ней связаться. Это будет первый и последний этап, где вы что-либо настраиваете.
Копия конфигурации базы данных находится в /app/config/database.php.default. Скопируйте этот файл в ту же директорию, только переименуйте в database.php.
Конфиг-файл должен быть достаточно понятным: просто замените значения в масиве $default теми, что применены к вашей настройке. Образец завершенного массива настроек может выглядить как следующий:
<?
var $default = array('driver' => 'mysql',
'connect' => 'mysql_pconnect',
'host' => 'localhost',
'login' => 'cakeBlog',
'password' => 'c4k3-rUl3Z',
'database' => 'cake_blog_tutorial' );
?>
Когда вы сохранили ваш новый файл database.php, вы можете открыть свой браузер и увидеть приветственную страницу Cake. Она также должна сообщить вам, что файл соединения с базой данных найден, и что Cake может успешно связываться с базой.
Если приветсвенная страница Cake выгядит слегка смешно (без изображений или стилей css), это скорее всего значит, что mod_rewrite не работает на вашей системе. Вот несколько советов как заставить его работать:
Если вы не хотите или не можете заставить mod_rewrite (или подобный модуль) работать на вашем сервере, вам нужно использовать встроенный красивые ссылки Cake. В /app/config/core.php разкоментируйте линию, которая выглядит так:
<? define ('BASE_URL', env('SCRIPT_NAME')); ?>
Это сделает ваши ссылки похожимы на эти www.example.com/index.php/controllername/actionname/param rather than www.example.com/controllername/actionname/param.
Класс модели это хлеб и масло приложений Cake PHP?. Создавая модель Cake, которая будет взаимодействовать с нашей базой данных, мы получим потребность в создании операций показать, добавить, редактировать, и удалить.
Файлы класса модели Cake здесь /app/models, а файл который мы будем создавать будет сохранен в /app/models/post.php. Завершенный файл должен выглядить так:
/app/models/post.php
<?php
class Post extends AppModel
{
var $name = 'Post';
}
?>
В связи со способом, по которому классу и файлу даны имена, это говорит Cake'у, что вы хотите чтобы модель Post была доступна в вашем Post Controller?, который связан с таблицей в вашей базе данных 'posts'.
Переменная $name всегда стоит того, чтобы ее добавили, и используется чтобы совладать с некоторыми именами классов в PHP4.
Больше о моделях, таких как префиксы таблиц, колбеки и верификация, посмотрите главу Модели.
Дальше мы создадим контроллер для наших постов. Контроллер это то, где будет весь код для взаимодействия с постами, и он также находится там где и все действия для этой модели. Вам нужно разместить этот новый контроллер в файл под названием posts_controller.php в вашем каталоге /app/controllers. Вот как должен выглядить основной контроллер:
/app/controllers/posts_controller.php
<?php
class PostsController extends AppController
{
var $name = 'Posts';
}
?>
Теперь давайте добавим действие в наш контроллер. Когда пользователи запришивают www.example.com/posts, это то же, что и запрос www.example.com/posts/index. С тех пор как мы хотим, чтобы пользователи могли просматривать список постов, когда они приходят по этой ссылке, действие index будет выглядить как это:
/app/controllers/posts_controller.php (действие index добавлено)
<?php
class PostsController extends AppController
{
var $name = 'Posts';
function index()
{
$this->set('posts', $this->Post->findAll());
}
}
?>
Позвольте мне немного пояснить действие. После определения функции index() в нашем Posts Controller?, пользователи могут получить доступ к коду запрашивая www.example.com/posts/index. Также, если бы мы определили функцию foobar(), пользователи могли бы получить доступ по адресу www.example.com/posts/foobar.
Простое указание в действие использует set() для вставки данных в отображение (которое мы создадим следующим). Устанавливается переменная отображения 'posts' еквивалентная возвращаемому значению метода findAll() модели Post. Наша модель Post автоматически доступна в $this->Post, потому что мы следили соглашению Cake по присвоению имен.
Узнать больше о контроллерах Cake можно в главе Контроллеры.
Теперь когда у нас есть наша база данных соединенна использованием нашей модели, а наш код приложения определен нашим контроллером, давайте создадим отображение для действия index, которое мы определили выше.
Отображения Cake это просто фрагменты HTML и PHP, которые устанавливаются в разметку приложения. Разметки можно определять и переключаться между ними, но пока, давайте просто использовать стандартную.
Помните в последнем разделе как мы назначали переменную 'posts' в отображении используя метод set()? Это будет передавать данные в отображение, которое будет выглядить как это:
Файлы отображений Cake хранятся в /app/views внутри каталога названного в честь контроллера к которому они принадлежат (мы должны создать каталог 'posts' в таком случае). Для форматирования данных постов в приятную таблицу, наш код отображения может выглядить так:
/app/views/posts/index.thtml
<h1>Blog posts</h1>
<table>
<tr>
<th>Id</th>
<th>Title</th>
<th>Created</th>
</tr>
<!--Здесь мы проходим цикл через наш масив $posts, выводя информацию о постах -->
<?php foreach ($posts as $post): ?>
<tr>
<td><?php echo $post['Post']['id']; ?></td>
<td>
<?php echo $html->link($post['Post']['title'], "/posts/view/".$post['Post']['id']); ?>
</td>
<td><?php echo $post['Post']['created']; ?></td>
</tr>
<?php endforeach; ?>
</table>
Надеюсь это выглядит в какой-то мере просто.
Возможно вы заметили использование объекта названного $html. Это отдельный пример из класса Html Helper?. Хелперы помогают делать ссылки, формы, Java Script? и Ajax. Подробнее о хелпрах в... вы угадали главе Хелперы, но что важно заметить здесь это то, что метод link() сгенерирует ссылки HTML с данным заголовком (первый параметр) и данным адресом (второй параметр).
Когда определяете ссылки в Cake, вы просто даете путь относящийся к базе приложения, а Cake заполняет оставшееся. То есть, ваши ссылки будут принимать форму /controller/action/id.
Теперь вы можете направить свой браузер на http://www.example.com/posts/index. Вы должны увидеть отображение, коректно сформатированное с заголовком и таблицей со списком постов.
Если вы нажмете на одну из ссылок, которые мы создали в этом отображении (эта ссылка это заголовок поста с адресом /posts/view/some_id), вы наверняка будете осведомлены Cake'ом, что действие еще не определено. Если вы не будете проинформированы, или что-то пошло не так, или же вы уже определили действие, в последнем случае вы подлец. В любом случае, мы создадим его сейчас:
/app/controllers/posts_controller.php (view action added)
<?php
class PostsController extends AppController
{
var $name = 'Posts';
function index()
{
$this->set('posts', $this->Post->findAll());
}
function view($id = null)
{
$this->Post->id = $id;
$this->set('post', $this->Post->read());
}
}
?>
Запрос set() должен казаться знакомым. Заметьте мы используем read() а не findAll(), потому что мы хотим получить информацию только об одном посте.
Заметьте что действие нашего отображение берет параметр. Этот параметр передан в приложение запросом URL. Если пользователь запрашивает /posts/view/3, тогда значение 3 будет вставлено как $id.
Теперь давайте создадим отображение для нашего нового действия 'view' и разместим в /app/views/posts/view.thtml.
/app/views/posts/view.thtml
<h1><?php echo $post['Post']['title']?></h1>
<p><small>Created: <?php echo $post['Post']['created']?></small></p>
<p><?php echo $post['Post']['body']?></p>
Проверьте работает ли это, пройдя по ссылкам /posts/index или запросом поста /posts/view/1.
Чтение постов из базы данных и показывание их нам это конечно хорошо, но давайте позволим добавление новых постов.
Во-первых, начнем с действия add() в Posts Controller?:
/app/controllers/posts_controller.php ( действие add добавлено)
<?php
class PostsController extends AppController
{
var $name = 'Posts';
function index()
{
$this->set('posts', $this->Post->findAll());
}
function view($id)
{
$this->Post->id = $id;
$this->set('post', $this->Post->read());
}
function add()
{
if (!empty($this->data))
{
if ($this->Post->save($this->data))
{
$this->flash('Your post has been saved.','/posts');
}
}
}
}
?>
Позвольте мне прочесть вам действие add() в простом языке: если данные формы не пустые, попробовать сохранить модель поста использовав эти данные. Если по каким-то причинам данные не сохраняются, выдать мне ошибки верификации данных и отрендерить отображение с показом этих ошибок.
Когда пользователь использует форму для отправки данных в ваше приложение, эта информация доступна в $this->params. Вы можете вывести их с помощью pr() если хотите увидеть их. $this->data это псеводоним для $this->params['data'].
Функция $this->flash() это функция контроллера, которая отображает сообщения пользователю на секунду (используя разметку для флеш-сообщений) потом перенаправляет пользователя по другому адресу (/posts, в нашем случае). Если DEBUG стоит на 0 $this->flash() переадресует автоматически, однако, если DEBUG на 0 вы сможете увидить флеш верстку и кликнуть на сообщении чтобы управлять переадресацией.
Вызываемый метод save() проверит наявность верификационных ошибок и не сохранит данные если таковые присутствуют. Доступно несколько методов, которыми вы сможете проверить верификационные ошибки, но мы немного поговорим о запросе validateErrors(), так что будьте на связи, когда я расскажу как выглядит отображение, а пока мы переходим к разделу о верификации данных.
Cake уничтожает монотонность созданий проверок в форме. Все ненавидят прописывать бесконечные формы с их проверками, а Cake делает это легко и быстро.
Чтобы воспользоваться преимуществами возможностей проверки, вам надо использовать HTML хелпер в вашем отображении. HTML хелпер доступен по умолчанию во всех отображениях в $html.
Вот наше отображения для добавления:
/app/views/posts/add.thtml
<h1>Add Post</h1>
<form method="post" action="<?php echo $html->url('/posts/add')?>">
<p>
Title:
<?php echo $html->input('Post/title', array('size' => '40'))?>
<?php echo $html->tagErrorMsg('Post/title', 'Title is required.') ?>
</p>
<p>
Body:
<?php echo $html->textarea('Post/body', array('rows'=>'10')) ?>
<?php echo $html->tagErrorMsg('Post/body', 'Body is required.') ?>
</p>
<p>
<?php echo $html->submit('Save') ?>
</p>
</form>
Как и с $html->link(), $html->url() будет генерировать подходящую ссылку из контроллера и действия, которое мы предоставили. По умолчанию, это выводит тег формы POST, но это можно модифицировать вторым параметром. Функции $html->input() и $html->textarea() убирает элементы формы одинаковых имен. Первый параметр сообщает Cake, к которой модели/полю они относятся, а второй параметр для дополнительных аттрибутов HTML (как размер поля). Снова-таки посмотрите главу Хелперы для подробной информации о хелперах.
Функция tagErrorMsg() выводит сообщения об ошибках в случае появления верификационных проблем.
Если вы хотите обновить свое отображение /app/views/posts/index.thtml чтобы включить новую ссылку Add Post направляющую www.example.com/posts/add.
Выглядит достаточно круто, но как мне сообщить Cake о своих требованиях верификации? Вот где мы возвращаемся к модели.
/app/models/post.php (верификационный массив добавлен)
<?php
class Post extends AppModel
{
var $name = 'Post';
var $validate = array(
'title' => VALID_NOT_EMPTY,
'body' => VALID_NOT_EMPTY
);
}
?>
Массив $validate сообщает Cake как проверять ваши данные когда вызван метод save(). Значение для тех ключей просто константы установленные Cake'ом, который переводит их в регулярные выражения (см. /cake/libs/validators.php). Сейчас проверки Cake'а базируются на регулярных выражениях, но вы так же можете использовать Model::invalidate() чтобы просмотреть свои собственные верификации.
Теперь когда ваши проверки на месте, используйте приложение чтобы попробовать добавить новый пост без заголовка или тела, чтобы глянуть как это работает.
Теперь давайте создадим возможность пользователям удалять посты. Начнем с действия delete() в Posts Controller?:
<?
/app/controllers/posts_controller.php (только действие delete)
function delete($id)
{
$this->Post->del($id);
$this->flash('The post with id: '.$id.' has been deleted.', '/posts');
}
?>
Этот код удаляет пост определенный по $id, и использует flash() чтобы показать пользователю сообщение подтверждения перед переадрисаций в /posts.
Поскольку мы просто выполняем некий код и переадресовуем, это действие не имеет отображения. Вы можете обновить отображения index чтобы позволить пользователям удалять посты.
/app/views/posts/index.thtml (добавленны ссылки добавления и удаления)
<h1>Blog posts</h1>
<p><?php echo $html->link('Add Post', '/posts/add'); ?></p>
<table>
<tr>
<th>Id</th>
<th>Title</th>
<th>Created</th>
</tr>
<!-- Цикл в котором показуются посты -->
<?php foreach ($posts as $post): ?>
<tr>
<td><?php echo $post['Post']['id']; ?></td>
<td>
<?php echo $html->link($post['Post']['title'], '/posts/view/'.$post['Post']['id']);?>
<?php echo $html->link(
'Delete',
"/posts/delete/{$post['Post']['id']}",
null,
'Are you sure?'
)?>
</td>
</td>
<td><?php echo $post['Post']['created']; ?></td>
</tr>
<?php endforeach; ?>
</table>
Этот код отображения также позволяет использовать Html хелпер, чтобы подсказать пользователю диалог подтверждения Java Script? перед попыткой удалить пост.
Итак... редактирование поста: начнем-с. Теперь вы профессионал в Cake, так что вы должны были подобрать образец. Сделайте действие, потом отображение. Вот как будет выглядить действие редактирования Posts Controller?:
/app/controllers/posts_controller.php (только действие edit)
<?
function edit($id = null)
{
if (empty($this->data))
{
$this->Post->id = $id;
$this->data = $this->Post->read();
}
else
{
if ($this->Post->save($this->data['Post']))
{
$this->flash('Your post has been updated.','/posts');
}
}
}
?>
Это проверяет на наличие отправленных данных формы. Если ничего не отправлено, идем искать пост и отправляем его в отображение. Если какие-то данные были отправлены, пробуем сохранить модель Post (или возвращает назад пользователя и показываем верификационные ошибки).
Отображение редактирования может выглядить так:
/app/views/posts/edit.thtml
<h1>Edit Post</h1>
<form method="post" action="<?php echo $html->url('/posts/edit')?>">
<?php echo $html->hidden('Post/id'); ?>
<p>
Title:
<?php echo $html->input('Post/title', array('size' => '40'))?>
<?php echo $html->tagErrorMsg('Post/title', 'Title is required.') ?>
</p>
<p>
Body:
<?php echo $html->textarea('Post/body', array('rows'=>'10')) ?>
<?php echo $html->tagErrorMsg('Post/body', 'Body is required.') ?>
</p>
<p>
<?php echo $html->submit('Save') ?>
</p>
</form>
Это отображение выводит форму редактирования (с заполненными значениями), и нужные сообщения об ошибках (если есть). Одна вещь на заметку: Cake будет подразумевать, что вы редактируете модель если поле 'id' существует в текущей сохраненной модели. Если нет 'id' (оглянитесь на наше отображение добавления), Cake будет подразумевать, что вы вводите новую модель, когда вызываете save().
Теперь вы можете обновить ваше отображение index ссылками на редактирование определенных постов:
/app/views/posts/index.thtml (edit links added)
<h1>Blog posts</h1>
<p><?php echo $html->link("Add Post", "/posts/add"); ?>
<table>
<tr>
<th>Id</th>
<th>Title</th>
<th>Created</th>
</tr>
<!-- Здесь в цикле отображаются посты -->
<?php foreach ($posts as $post): ?>
<tr>
<td><?php echo $post['Post']['id']; ?></td>
<td>
<?php echo $html->link($post['Post']['title'], '/posts/view/'.$post['Post']['id']);?>
<?php echo $html->link(
'Delete',
"/posts/delete/{$post['Post']['id']}",
null,
'Are you sure?'
)?>
<?php echo $html->link('Edit', '/posts/edit/'.$post['Post']['id']);?>
</td>
</td>
<td><?php echo $post['Post']['created']; ?></td>
</tr>
<?php endforeach; ?>
</table>
Эта часть опциональная, но полезная в понимании как формулируются ссылки к определенным функциям в Cake. Мы собираемся сделать только быстрые изменения в роутах в этом обучающем примере. Для более полной справки смотрите главу «Настройка», Раздел 3: Настройка роутов.
Роут по умолчанию Cake отведет человека, посещающего корень сайта (например http://www.example.com) к Pages Controller?'у, и отрендерит отображение под названием home. Вместо этого, мы хотим, чтобы пользователи нашего блога шли к нашему Posts Controller?'у, который скоро будет создан.
Роутинг Cake находится в /app/config/routes.php. Вы хотите разкоментировать или удалить линию похожую на эту:
$Route->connect ('/', array('controller'=>'pages', 'action'=>'display', 'home'));
Эта линия связывает ссылку / с домашней страницей Cake по умолчанию. Мы хотим связать ее с нашим собственным контроллером, так что добавьте линию, которая выгляит так:
$Route->connect ('/', array('controller'=>'posts', 'action'=>'index'));
Это должно связывать запрос пользователей '/' с действием index() нашего Posts Controller?.
Создание приложений таким способом выиграет вам время, честь, женщин и деньги и даже ваши самые дикие фантазии. Просто, не так ли? А теперь вспомните, что этот обучающий пример – основы. Cake обладает большим количеством возможностей и является очень гибким. Используйте это руководство как гид для создания более богатых на возможности приложений.
Теперь, когда вы создали начальное приложение, вы готовы к реальным вещам. Начните свой собственный проект, прочтите остальное руководство и API.
Если вам нужна помощь, приходите в #cakephp. Добро пожаловать в Cake!
супер!
жаль что про cake я не слышал пару лет назад...
щас не пришлось бы поддерживать столько беспорядочного кода =)
Полезным будет добавление к даному примеру использование страничной навигации.