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 контроллер, единственное новое, что вы должны запомнить из данной статьи это, то как создавать модели и как их использовать в дальнейшем в вашем приложении.

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

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

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

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

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

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

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

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

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

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

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

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

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