Печём пирожки или начало работы с CakePHP по-русски


Скоро товарищей, пишущих по старинке веб-страницы на голом php, можно будет показывать в зоопарках :) Наступает эра Фреймворков. И это хорошо, потому что программист избавлен от множества рутинных задач, и может сосредоточиться на создании логики приложения. В CakePHP используется подход MCV (Model - View - Controller). Теперь вместо одного файла *.php на одну страничку их будет целых три минимум %) - один для модели (описывает связь формы с базой данных, имеет расширение php), thtml файл будет описывать внешний вид страницы (view), третий (контроллер страницы с расширением php будет реализовывать логику формы и будет содержать методы, дополняющие функциональность родительского класса AppController.

Что ж, начнем печь приложения как пирожки :)) Но для этого придется преступить через себя и принять новый подход к программированию. Оно того стоит ^_^

Установка

Вам нужен Apache с установленным mod_rewrite и mod_php, php4 или php5, а также база данных (в нашем примере используется MySQL). Первым делом разживитесь на www.cakephp.org свежей версией CakePHP. Там же расположен неплохой мануал, которому я во многом буду следовать. Распакуйте архив в корневую директорию веб-сервера и наберите в браузере адрес сайта. Должна появиться приветственная страничка:

Your database configuration file is not present.

Нужно прописать соединение с базой данных. Делается это в директории app/config - берем за основу database.php.default и переименовываем его в database.php. Прописываем в файле параметры соединения с базой. Если все ОК то CakePHP сообщит об этом.

Your database configuration file is present.

Cake is able to connect to the database.

Все готово для творчества.

Модуль новостей

Напишем простейший модуль новостей, чтобы проиллюстрировать технологию создания сайтов на Фреймворке. Создадим в базе данных таблицу posts, в которой будут храниться новости.

CREATE TABLE `posts` (

  `id` bigint(20) NOT NULL auto_increment,

  `post_date` date NOT NULL default '0000-00-00',

  `post_header` varchar(255) NOT NULL default '',

  `post_text` text NOT NULL,

  `archived` tinyint(4) NOT NULL default '0',

  PRIMARY KEY  (`id`)

)

Вопрос: почему бы таблицу не назвать "news"? Таблица должна иметь имя сущности во множественном числе. В английском "новости" news всегда употребляется во множественном числе, тем более слово new является ключевым в php, что приводит к ошибке.

Модель

В папке app/models создадим файл модели post.php

<?php
class Post extends AppModel

{

    var $name = 'Post';

    var $validate = array(

        'post_header'  => VALID_NOT_EMPTY,

        'post_text'   => VALID_NOT_EMPTY,

        'post_date'   => VALID_NOT_EMPTY

    );

}

?>

В массиве $validate описываются ограничения накладываемые логикой приложения на данные. Мы запретили пустые поля Текст, Заголовок и Дата.

Контроллер

В папке app/controllers создадим файл posts_controller.php. Создадим объект, который реализует основные функции модуля новостей: отображение списка (index), просмотр новости (view), удаление новости (delete), добавления новости (add).

<?php

class PostsController extends AppController // наследуемся
// от AppController

{

    var $name = 'Posts';

    function index() // эта функция должна быть обязательно

    {

         $this->set('posts', $this->Post->findAll()); // выборка всех
записей //из таблицы $this->pageTitle = 'Новости'; } 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('Новость была успешно добавлена','/posts'); // flash выдает сообщение пользователю в виде ссылки на страницу, указанной во втором аргументе функции } } } function delete($id) // удаление новости { $this->Post->del($id); $this->flash('Новость была удалена', '/posts'); } 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('Новость была отредактирована','/posts'); } } } } ?>

Виды

В папке app/views создадим папку posts. В этой папке необходимо создать файлы видов для каждой функции, кроме функции Delete, которая не требует своего вида, а использует только функцию flash.

app/views/posts/index.thtml

<h1>Новости</h1>

<?

// длина строки новости, которая будет
// показываться до "далее" или "..."

  $news_teaser_length = 12;

  $news_more_annex = ' >>';

  if (count($posts)>0)

  {

?>

<table>

<tr>

 <th>Дата</th>

 <th>Заголовок</th>

 <th>Текст</th>

 <th> </th>

 <th> </th>

</tr>

    <?php foreach ($posts as $post): ?>

    <tr>

        <td>

        <?php

          echo $post['Post']['post_date'];

        ?>

        </td>

        <td>

        <?php

        echo $post['Post']['post_header'];

        ?>

        </td>

        <td>

            <?php

            // если новость слишком длиная
            //(слов больше чем $news_teaser_length)
            // то надо показать только $news_teaser_length
            // слов

            $line = $post['Post']['post_text'];

            $tmpline = preg_replace("/s+/", " ", $line);

            $mes_words = explode(' ',$tmpline);

            $text = "";

            if (count($mes_words) >= $news_teaser_length)

            {

              $last_word = $mes_words[$news_teaser_length -1];

              for ($i = 0; $i <= $news_teaser_length -1 ; $i++)

              {

                $text = $text.$mes_words[$i]." ";

              }

              echo $html->link($text.$news_more_annex,

                       '/posts/view/'.$post['Post']['id']);

            }

            else

            {

              echo $html->link($post['Post']['post_text'],
                  '/posts/view/'.$post['Post']['id']);

            }

            ?>

        </td>

        <td>

            <?php

            echo $html->link('Редактировать',
               '/posts/edit/'.$post['Post']['id']);

           ?>

        </td>

        <td>

           <?php

            echo $html->link('Удалить',
               '/posts/delete/'.$post['Post']['id']);

           ?>

        </td>

    </tr>

    <?php endforeach; ?>

</table>

<?

}

  else

  {

    echo "<p>Новостей пока нет</p>";

  }

?>

 <p><a href="/posts/add">Добавить новость?</a></p>

app/views/posts/add.thtml

<h1>Добавить новость</h1>

<form method="post" action="<?php
  echo $html->url('/posts/add')?>">

    <p>

        Название: <br>

        <?php echo $html->input('Post/post_header',
           array('size' => '40'))?>

        <?php echo $html->tagErrorMsg('Post/post_header',
           'Название не может быть пустым.') ?>

    </p>

    <p>

        Дата: <br>

        <?php echo $html->input('Post/post_date',
           array('size' => '40'))?>

        <?php echo $html->tagErrorMsg('Post/post_data',
            'Дата не может быть пустой.') ?>

    </p>

    <p>

        Текст:<br>

        <?php echo $html->textarea('Post/post_text',
           array('rows'=>'10')) ?>

        <?php echo $html->tagErrorMsg('Post/post_text',
             'Сообщение не может быть пустым.') ?>

    </p>

    <p>

        <?php echo $html->submit('Отправить') ?>

    </p>

</form>

app/views/posts/edit.thtml

<h1>Редактирование новости</h1>

<form method="post" action="<?php
   echo $html->url('/posts/edit')?>">

    <?php echo $html->hidden('Post/id'); ?>

    <p>

        Заголовок:<br>

        <?php echo $html->input('Post/post_header',
           array('size' => '40'))?>

        <?php echo $html->tagErrorMsg('Post/post_header',
           'Необходим заголовок.') ?>

    </p>

    <p>

        Дата:<br>

        <?php echo $html->input('Post/post_date',
           array('size' => '40'))?>

        <?php echo $html->tagErrorMsg('Post/post_date',
           'Необходима дата.') ?>

    </p>

    <p>

        Текст:<br>

        <?php echo $html->textarea('Post/post_text',
           array('rows'=>'10')) ?>

        <?php echo $html->tagErrorMsg('Post/post_text',
            'Текст не должен быть пустым!') ?>

    </p>

    <p>

        <?php echo $html->submit('Сохранить') ?>

    </p>

</form>

app\views\posts\view.thtml

<h1><?php echo $post['Post']['post_header']?></h1>

<p><small>Создана: <?php
  echo $post['Post']['post_date']?></small></p>

<p><?php echo $post['Post']['post_text']?></p>

Фу: вроде все почти готово :) Теперь осталось перенаправить пользователя c приветственной странички CakePHP на страничку app/posts.

Для этого идем в app/config/routes.php и меняем там строку

$Route->connect(’/', array(’controller’ =>
‘pages’, ‘action’ => ‘display’, ‘home’));

на строку

$Route->connect (’/', array(’controller’=>’posts’, ‘action’=>’index’));

Теперь можете в браузере набрать адрес сайта и понаблюдать CakePHP в действии :)

Небольшая обработка напильником

Полюбовавшись на полученное приложение, пытливый читатель скоро почувствует разочарование. Как поменять стиль страницы, убрать маленький баннер снизу и гордое "CakePHP Rapid Development" в верху каждой страницы? Как заставить функцию flash отображать текст по-русски? Для этой цели служат layouts. (Долго думал, как перевести layouts и решил остановиться на слове "шаблоны"). Бодро идем в папку app/views/layouts и помещаем там нужные файлы:

default.thtml, например, такой:

<html>

<head>

<META http-equiv="content-type"
content="text/html;charset=windows-1251" />

<title>CAKE_TEST<?php echo $title_for_layout?></title>

<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">

<link rel="stylesheet" type="text/css" href="/css/cake.generic.css" />

</head>

<body>

            <div id="wrapper">

                        <div id="container">

            <div id="content">

                                      <?php echo $content_for_layout ?>

                                   </div>

                        </div>

            </div>

</body>

</html>

Вылечим функцию flash от любви к utf8. Для этого разместим там же flash.thtml

<html>

<head>

<title><?php echo $page_title?></title>

<META http-equiv="content-type"
content="text/html;charset=windows-1251" />

<?php if(Configure::read() == 0) { ?>

<meta http-equiv="Refresh" content="<?php
  echo $pause?>;url=<?php echo $url?>"/>

<?php } ?>

<style><!--

P { text-align:center; font:bold small sans-serif }

A { color:red}

A:HOVER { text-decoration: underline; color:#44E }

--></style>

</head>

<body>

<p><a href="<?php echo $url?>"><?php
  echo $message?></a></p>

</body>

</html>

Прототипы этих файлов можно увидеть в папке cake/libs/view/templates/layouts

Вроде бы все :) Прошу php пуристов не критиковать мой код, ибо сделан он больше развлечения ради. Рекомендую сходить на cakeforge.org и скачать там мануал и помощь по API в формате chm. Удачи в печении плюшек!



Дополнительно

iXBT BRAND 2016

«iXBT Brand 2016» — Выбор читателей в номинации «Процессоры (CPU)»:
Подробнее с условиями участия в розыгрыше можно ознакомиться здесь. Текущие результаты опроса доступны тут.

Нашли ошибку на сайте? Выделите текст и нажмите Shift+Enter

Код для блога бета

Выделите HTML-код в поле, скопируйте его в буфер и вставьте в свой блог.