Kohana 3.2 – Собственный блог шаг за шагом — Часть 4

tags

Приветствую всех моих читателей, а так же тех кто случайно попал на мой блог. Сегодня я хотел бы продолжить тему создания собственного блога на Kohana 3.2.

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

Ссылки для меню и стартовой страницы

Давайте добавим ссылки для стартовой страницы администратора для этого откроем файл /application/views/admin/dashboard.php и отредактируем его следующим образом:

<?php defined('SYSPATH') or die('No direct script access.');

/**
 * @var array      $config       Global blog configuration
 * @var Model_User $user         Global Kohana user object
 * @var string     $message      Global message
 * @var string     $message_type Global message type string
 *
 * @author     Novichkov Sergey(Radik) <novichkovsergey@yandex.ru>
 * @copyright  Copyrights (c) 2013 Novichkov Sergey
 */
?>
<?php echo View::factory('admin/block/menu') ?>

<div id="container">
    <div id="content" class="container">
        <div class="row">
            <div class="span12">
                <h1><?php echo __('Dashboard') ?></h1>
                <div class="row-fluid">
                    <div class="span2">
                        <h3><?php echo __('Security') ?></h3>
                        <table class="dashboard">
                            <tr>
                                <td><img src="<?php echo URL::site('/public/images/security.png') ?>" alt=""></td>
                                <td><i class="icon-user"></i> <a href="<?php echo URL::site('/admin/users') ?>"><?php echo __('Users List') ?></a><br/>
                                    <i class="icon-plus"></i> <a href="<?php echo URL::site('/admin/users/new') ?>"><?php echo __('New User') ?></a><br/>
                                    <i class="icon-film"></i> <a href="<?php echo URL::site('/admin/roles') ?>"><?php echo __('Roles List') ?></a><br/>
                                    <i class="icon-plus"></i> <a href="<?php echo URL::site('/admin/roles/new') ?>"><?php echo __('New Role') ?></a></td>
                            </tr>
                        </table>
                    </div>
                    <div class="span2">
                        <h3><?php echo __('Tags') ?></h3>
                        <table class="dashboard">
                            <tr>
                                <td><img src="<?php echo URL::site('/public/images/tag.png') ?>" alt=""></td>
                                <td><i class="icon-user"></i> <a href="<?php echo URL::site('/admin/tags') ?>"><?php echo __('Tags List') ?></a><br/>
                                    <i class="icon-plus"></i> <a href="<?php echo URL::site('/admin/tags/new') ?>"><?php echo __('New Tag') ?></a></td>
                            </tr>
                        </table>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<?php echo View::factory('admin/block/footer') ?>

Для добавления ссылок в меню, откроем файл /application/views/admin/block/menu.php и аналогично предыдущему файлу отредактируем его следующим образом:

<?php defined('SYSPATH') or die('No direct script access.');

/**
 * @var array      $config       Global blog configuration
 * @var Model_User $user         Global Kohana user object
 * @var string     $message      Global message
 * @var string     $message_type Global message type string
 *
 * @author     Novichkov Sergey(Radik) <novichkovsergey@yandex.ru>
 * @copyright  Copyrights (c) 2013 Novichkov Sergey
 */
?>
<div class="navbar navbar-inverse navbar-fixed-top">
    <div class="navbar-inner">
        <div class="container">
            <div class="row">
	        <div class="span12">
                    <a class="brand" href="<?php echo URL::site('/admin') ?>"><?php echo __('Kohana 3.2 Blog') ?></a>

                    <ul class="nav">
                        <li>
                            <a href="#"  class="dropdown-toggle" data-toggle="dropdown">
                                Security <i class="caret"></i>
                            </a>
                            <ul class="dropdown-menu pull-right">
                                <li><a href="<?php echo URL::site('/admin/users') ?>"><i class="icon-user"></i> <?php echo __('Users List') ?></a></li>
                                <li><a href="<?php echo URL::site('/admin/users/new') ?>"><i class="icon-plus"></i> <?php echo __('New User') ?></a></li>
                                <li><a href="<?php echo URL::site('/admin/roles') ?>"><i class="icon-film"></i> <?php echo __('Roles List') ?></a></li>
                                <li><a href="<?php echo URL::site('/admin/roles/new') ?>"><i class="icon-plus"></i> <?php echo __('New Role') ?></a></li>
                            </ul>
                        </li>
                        <li>
                            <a href="#"  class="dropdown-toggle" data-toggle="dropdown">
                                Tags <i class="caret"></i>
                            </a>
                            <ul class="dropdown-menu pull-right">
                                <li><a href="<?php echo URL::site('/admin/tags') ?>"><i class="icon-tag"></i> <?php echo __('Tags List') ?></a></li>
                                <li><a href="<?php echo URL::site('/admin/tags/new') ?>"><i class="icon-plus"></i> <?php echo __('New Tag') ?></a></li>
                            </ul>
                        </li>
                    </ul>

                    <div class="btn-group pull-right">
                        <a href="<?php echo URL::site('/admin/users/edit/' . $user->id) ?>" class="btn">
                            <?php echo __('Authorized as: :user', array(':user' => $user->username)) ?>
                        </a>
                        <a href="#" class="btn dropdown-toggle" data-toggle="dropdown">
                            <i class="caret"></i>
                        </a>
                        <ul class="dropdown-menu pull-right">
                            <li><a href="<?php echo URL::site('/admin/auth/logout') ?>"><i class="icon-off"></i> <?php echo __('Logout') ?></a></li>
                        </ul>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

Описание модели

В предыдущем уроке мы с вами пользовались базовой моделью пользователя поставляемую вместе с модулем ORM поэтому ранее мы пропустили этот шаг, но в нынешнем случае для дальнейшей работы нам требуется описать модель. Для этого давайте создадим файл /application/classes/model/tag.php с следующим содержанием:

<?php defined('SYSPATH') or die('No direct script access.');

/**
 * Tag ORM model class
 *
 * @property int    $id     Tag primary key
 * @property string $tag    Tag name
 */
class Model_Tag extends ORM {
    /**
     * Table columns
     * @var array
     */
    protected $_table_columns = array(
        'id'    => 'id',
        'tag'   => 'tag',
    );
} // End ORM Model Tag Class

Теперь давайте кратко посмотрим, что, а главное для чего мы тут делаем. Первое что мы делаем так это объявляем класс Model_Tag наследующий класс ORM, следующим шагом мы описываем защищенную переменную $_table_columns — это необходимо для того, что бы ORM вреймворка не запрашивал список полей у БД и делал 1 лишний запрос при первом использовании модели.

Как вы наверное уже заменили, модель у нас имеет имя Tag, а таблица в БД tags и мы ни где в модели не описали в какой таблице у нас хранятся данные модели, мы не стали описывать это потому, что мы с вами придерживаемся соглашения в наименовании таблиц БД которое принято в Kohana ORM и система самостоятельно определит имя таблицы в БД основываясь на имени модели.

Страница списка тегов (Tags List)

Создание контроллера

Так же как и в предыдущем уроке нам сначала нужно создать контроллер, класс которого будет располагаться в файле /application/classes/controller/admin/tags.php, с следующим содержанием (похожий содержанием на контроллер из предыдущей статьи):

<?php defined('SYSPATH') or die('No direct script access.');

class Controller_Admin_Tags extends Controller_Admin_Layout_Secure {

    /**
     * Tags List Action
     */
    public function action_index()
    {
        // Load tags list query
        $items = ORM::factory('tag')
            ->reset(FALSE);

        // Create pagination object
        $pagination = Pagination::factory(array(
            'group' => 'admin',
            'total_items' => $items->count_all(),
        ));

        // Modify tags list query
        $items = $items
            ->order_by('tag', 'ASC')
            ->offset($pagination->offset)
            ->limit($pagination->items_per_page)
            ->find_all();

        // Set content template
        $this->template->set('content', View::factory('admin/tags/list', array(
            'items' => $items,
            'pagination' => $pagination,
        )));
    }

    /**
     * Delete tag action
     */
    public function action_delete()
    {
        // Get tag id
        $item_id = $this->request->param('id');
        if (! $item_id)
        {
            throw new HTTP_Exception_404('Tag not found.');
        }

        // Get tag
        $item = ORM::factory('tag', $item_id);
        if (! $item->loaded())
        {
            throw new HTTP_Exception_404('Tag not found.');
        }

        // Set message
        Session::instance()
            ->set('message', __('Tag :item deleted successfully.', array(':item' => $item->tag)))
            ->set('message_type', 'success');

        // Delete tag
        $item->delete();

        // Redirect to base page
        $this->request->redirect($this->request->referrer());
    }

    /**
     * Create tag action
     */
    public function action_new()
    {
        // New tag
        $item = ORM::factory('tag');

        // Set content template
        $this->template->set('content', View::factory('admin/tags/new', array(
            'item' => $item->as_array(),
        )));
    }

    /**
     * Edit tag action
     *
     * @throws HTTP_Exception_404
     */
    public function action_edit()
    {
        // Get tag id
        $item_id = $this->request->param('id');
        if (! $item_id)
        {
            throw new HTTP_Exception_404('Tag not found.');
        }

        // Get tag
        $item = ORM::factory('tag', $item_id);
        if (! $item->loaded())
        {
            throw new HTTP_Exception_404('Tag not found.');
        }

        // Set content template
        $this->template->set('content', View::factory('admin/tags/edit', array(
            'item' => $item->as_array(),
        )));
    }

    /**
     * Save tag action
     *
     * @throws HTTP_Exception_404
     */
    public function action_save()
    {
        // Protect page
        if ($this->request->method() !== Request::POST)
        {
            throw new HTTP_Exception_404('Page not found.');
        }

        // Back
        if ($this->request->post('back'))
        {
            $this->request->redirect('/admin/tags');
        }

        // create and configure form validation
        $post = Validation::factory($this->request->post())
            ->labels(array(
                'tag' => __('Tag'),
            ))
            ->rule('tag', 'not_empty');

        // check validation
        if ($post->check())
        {
            // store
            $data = $post->data();

            /** @var Model_Tag $item **/
            $item = ORM::factory('tag', Arr::get($data, 'id'));

            // update tag
            $item->values($data, array('tag', ))->save();

            // message
            Session::instance()
                ->set('message', __(Arr::get($post->data(), 'id') ? 'Tag updated successfully.' : 'Tag created successfully.'))
                ->set('message_type', 'success');

            // redirect to list page
            $this->request->redirect(URL::site('/admin/tags'));
        }

        // Errors list
        View::set_global('errors', $post->errors('validation'));

        // Set content template
        $this->template->set('content', View::factory('admin/tags/' . (Arr::get($post->data(), 'id') ? 'edit' : 'new'),
            array(
                'item' => $post->data(),
            )
        ));
    }
} // End Admin Tags

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

Создание видов

Следующим шагом мы по аналогии с предыдущим уроком создадим виды для следующих действий контроллера index, new, edit.

Листинг вида index (/application/views/admin/tags/list.php):

<?php defined('SYSPATH') or die('No direct script access.');

/**
 * @var array           $config       Global blog configuration
 * @var Model_User      $user         Global Kohana user object
 * @var string          $message      Global message
 * @var string          $message_type Global message type string
 * @var Database_Result $items        Users list
 * @var Pagination      $pagination   Pagination object
 *
 * @author     Novichkov Sergey(Radik) <novichkovsergey@yandex.ru>
 * @copyright  Copyrights (c) 2013 Novichkov Sergey
 */
?>
<?php echo View::factory('admin/block/menu') ?>

<div id="container">
    <div id="content" class="container">
        <div class="row title">
	    <div class="span12">
                <h1 class="pull-left"><?php echo __('Tags list') ?></h1>
                <a class="btn btn-success pull-right"
                   href="<?php echo URL::site('/admin/tags/new') ?>"><i class="icon-plus"></i> <?php echo __('New') ?></a>
	    </div>
        </div>

	<?php if ($message) : ?>
	<div class="row">
	    <div class="span12">
                <div class="alert alert-<?php echo $message_type ?>">
                    <a href="#" class="close" data-dismiss="alert">×</a>
		    <?php echo $message ?>
                </div>
            </div>
	</div>
	<?php endif; ?>

	<div class="row">
	    <div class="span12">
                <table class="table table-bordered table-hover">
                    <thead>
                    <tr>
                        <th><?php echo __('ID') ?></th>
                        <th><?php echo __('Tag') ?></th>
                        <th><?php echo __('Actions') ?></th>
                    </tr>
                    </thead>

                    <tbody>
			<?php if ($items->count()) : ?>
			    <?php foreach ($items as $item) : ?>
	                        <tr>
	                            <td><?php echo $item->id ?></td>
	                            <td><?php echo $item->tag ?></td>
	                            <td class="actions">
		                            <div class="btn-group">
		                                <a class="btn" href="<?php echo URL::site('admin/tags/delete/' . $item->id) ?>"><i
				                                class="icon-remove"></i> <?php echo __('Delete') ?></a>
		                                <a class="btn btn-primary" href="<?php echo URL::site('admin/tags/edit/' . $item->id) ?>"><i
				                                class="icon-edit"></i> <?php echo __('Edit') ?></a>
                                    </div>
	                            </td>
	                        </tr>
			    <?php endforeach; ?>
			<?php else: ?>
		            <tr>
		                <td colspan="3"><?php echo __('No items') ?></td>
		            </tr>
			<?php endif; ?>
                    </tbody>

                    <tfoot>
	                <tr>
	                    <td colspan="2"><?php echo $pagination ?></td>
	                    <td class="cell-middle"><?php echo __('Total: :count', array(':count' => $pagination->total_items)) ?></td>
	                </tr>
                    </tfoot>
                </table>
            </div>
        </div>
    </div>
</div>

<?php echo View::factory('admin/block/footer') ?>

Листинг вида new (/application/views/admin/tags/new.php):

<?php defined('SYSPATH') or die('No direct script access.');

/**
 * @var array           $config       Global blog configuration
 * @var Model_User      $user         Global Kohana user object
 * @var string          $message      Global message
 * @var string          $message_type Global message type string
 * @var array           $item         Current item data
 *
 * @author     Novichkov Sergey(Radik) <novichkovsergey@yandex.ru>
 * @copyright  Copyrights (c) 2013 Novichkov Sergey
 */
?>
<?php echo View::factory('admin/block/menu') ?>

<div id="container">
    <div id="content" class="container">
    	<div class="row title">
            <div class="span12">
                <h1 class="pull-left"><?php echo __('New tag') ?></h1>
            </div>
	</div>

	<?php echo View::factory('admin/tags/form', array('item' => $item, )) ?>
    </div>
</div>

<?php echo View::factory('admin/block/footer') ?>

Листинг вида edit (/application/views/admin/tags/edit.php):

<?php defined('SYSPATH') or die('No direct script access.');

/**
 * @var array           $config       Global blog configuration
 * @var Model_User      $user         Global Kohana user object
 * @var string          $message      Global message
 * @var string          $message_type Global message type string
 * @var array           $item         Current item data
 *
 * @author     Novichkov Sergey(Radik) <novichkovsergey@yandex.ru>
 * @copyright  Copyrights (c) 2013 Novichkov Sergey
 */
?>
<?php echo View::factory('admin/block/menu') ?>

<div id="container">
    <div id="content" class="container">
        <div class="row title">
	    <div class="span12">
                <h1 class="pull-left"><?php echo __('Edit tag: :item', array(':item' => Arr::get($item, 'tag'))) ?></h1>
	    </div>
        </div>

        <?php echo View::factory('admin/tags/form', array('item' => $item, )) ?>
    </div>
</div>

<?php echo View::factory('admin/block/footer') ?>

Виды действий new и edit используют форму код которой содержится в виде form (/application/views/admin/tags/form.php), с следующим содержанием:

<?php defined('SYSPATH') or die('No direct script access.');

/**
 * @var array           $config       Global blog configuration
 * @var Model_User      $user         Global Kohana user object
 * @var string          $message      Global message
 * @var string          $message_type Global message type string
 * @var array           $item         Current item data
 * @var array           $errors       Errors array
 * @var Database_Result $roles        All roles list
 *
 * @author     Novichkov Sergey(Radik) <novichkovsergey@yandex.ru>
 * @copyright  Copyrights (c) 2013 Novichkov Sergey
 */
?>
<form action="<?php echo URL::site('/admin/tags/save') ?>" method="post" name="tag-form" class="tag-form">
    <div class="row">
	<div class="span9">
	    <fieldset>
	        <legend><?php echo __('Common') ?></legend>

                <div class="control-group<?php if (Arr::get($errors, 'tag')) : ?> error<?php endif; ?>">
		    <label for="tag" class="control-label"><?php echo __('Tag name') ?>:</label>
	            <div class="controls">
	                <input type="text" name="tag" id="tag" value="<?php echo Arr::get($item, 'tag') ?>"/>
			<?php if (Arr::get($errors, 'tag')) : ?>
			    <div class="help-block"><?php echo Arr::get($errors, 'tag') ?></div>
			<?php endif; ?>
	            </div>
	        </div>
	    </fieldset>
	</div>
    </div>
    <div class="row">
	<div class="span12 form-actions">
            <div class="pull-right">
                <input type="submit" name="back" class="btn" value="<?php echo __('Back') ?>" />
                <input type="submit" name="save" class="btn btn-primary" value="<?php echo __('Save') ?>" />
            </div>
	</div>

        <input type="hidden" name="id" value="<?php echo Arr::get($item, 'id') ?>">
    </div>
</form>

В качестве заключения хотел бы сказать, что весь написанный нами код в рамках данной статьи весьма похож, а точнее можно сказать практически идентичен коду контроллера и действий из предыдущей статьи т.к. в рамках данной статьи мы с вами создали типовой CRUD контроллер, единственное новое, что вы должны запомнить из данной статьи это, то как создавать модели и как их использовать в дальнейшем в вашем приложении.

В следующей статье мы с вами выполним следующий пункт из нашего списка, и еще на один шаг приблизимся к завершению нашего собственного блога! До встречи в следующих статьях.

Скачать исходные коды урока

11 комментариев

  1. Ivan:

    Когда будет продолжение ?

    • Radik:

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

  2. hmm:

    Интересует такой вопрос. Все правила для валидации прописаны в модели и в контроллерах используется try-catch для их отлова. Соответственно практически у каждого контроллера будет один и теже запросы CRUD. Разница составит, разве что в имени модели. Получается для каждой таблицы создавать одинаковые методы для простейших операций с БД?

    • hmm:

      Наслышан про внутренние запросы Request, но как реализовать уникальных 4 метода CRUD для того, чтобы небыло избыточности кода — пока не представляю.

    • radik:

      Чисто теоритически такое возможно, но для этого нужно будет создать норльманый CRUD контроллер, не зыбывайте, что по сути нужно будет еще учесть получение связных данных к примеру список категорий для постов и т.п. у каждой модели эти данные могут быть разными. Но так то я с вами согласен можно абстрагироваться и сделать универсальный CRUD контроллер к примеру на работе с Zend у нас так и сделано, в добавок еще реализован функционал гридов (таблиц) которые отвечают за вывод табличных данных, фильтры и сортировку. Такой подход весьма удобен, у меня возникала мысль сделать для Kohana нечто подобное, но пока к сожалению нет времени этим заняться.

  3. babur:

    Как сделать валидацию на уникальные поля ? при редактировании формы

  4. Тимур:

    Спасибо большое за туториал, пробую на Kohana 3.3
    Работает все отлично, правда пара методов изменились в связи с новой версией.
    А когда будет продолжение???

    • radik:

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

  5. Gambit:

    Почему пустая страница отображается, когда запускаешь исходник? Так все круто на уроках намучено, и так обидно, что не запускается. В чем я ошибаюсь?

    • radik:

      Проверьте все ли у вас стоит из расширений для php, версию php и подключение к базе данных. В оф. документации вы можете найти все требования для Kohana 3.2.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *