В первой части этой серии статей мы изучили основы Fuel PHP Framework. Во второй части поговорим о более серьезных темах. Мы создадим панель администратора для нашего приложения, пройдемся по основам использования ORM и научимся пользоваться пакетом Authentication для ограничения прав доступа. Также вы можете посмотреть уроки по php.
Итак, начнем!
Введение
После написания первой статьи Fuel был переименован в FuelPHP. Кроме того, в отличие от первой статьи, которая базировалась на версии 1.0.1, эта статья требует версию 1.1.0. Поэтому кое-что будет незначительно отличаться. Все теоретические сведения, которые Вы познали в первой статье, до сих пор вполне актуальны и почти не изменились.
Шаг 1 – Настройка Oil
Если Вы еще не установили утилиту для командной строки Oil и являетесь пользователем Linux, Mac, Solaris и т.д., то сделайте это с помощью следующей команды:
1 |
$ curl get.fuelphp.com/oil | sh |
Шаг 2 – Создание нового приложения
Команда oil
поможет Вам создать новый проект, используя всего несколько ключевых слов и алиас php oil
, находясь в Вашем приложении FuelPHP:
1 2 |
$ oil create Sites/blog $ cd Sites/blog |
Этим самым мы создадим приложение blog
. И если у Вас есть Apache или любой другой веб-сервер, работающий в папке “Sites”, то Вы сможете пройти по следующему URL-адресу и увидите страницу с приветствием.
Теперь, когда FuelPHP и Ваш веб-сервер готовы к работе, мы можем приступить к настройке нашего приложения.
Шаг 3 – Настройка приложения
Откройте Ваш любимый редактор кода, чтобы начать настройку соединения с базой данных и конфигурацию самого приложения. Все это делается практически также как и в версии 1.0.1, так что создайте базу данных и настройте пользователей SQL, как Вы это делали ранее. Когда дело дойдет до конфигурации базы данных, то здесь появятся два отличия:
- PDO сейчас является драйвером по умолчанию
- FuelPHP версии 1.1 имеет конфигурационные директории на основе окружающей среды.
Эти изменения очень просты, однако Вы всегда можете вернуться к использованию MySQL в качестве основного драйвера, если пожелаете. PDO очень полезен для разработчиков, т.к. Ваше приложение сможет работать с базой данных любого типа. Это значит, что Вы без проблем сможете перейти, например, от SQLite к PostgreSQL.
Просто откройте fuel/app/config/development/db.php
и отредактируйте настройки, указав имя базы данных, а также Ваши логин и пароль для доступа к серверу базы данных:
1 2 3 4 5 6 7 8 9 |
return array( 'default' => array( 'connection' => array( 'dsn' => 'mysql:host=localhost;dbname=blog', 'username' => 'root', 'password' => 'password', ), ), ); |
Далее откройте fuel/app/config/config.php
и активируйте пакеты auth и orm, как было сказано в первом абзаце.
1 2 3 4 5 6 7 8 9 |
/**************************************************************************/ /* Always Load */ /**************************************************************************/ 'always_load' => array( 'packages' => array( 'auth', 'orm', ), |
В этом конфигурационном файле нам необходимо сделать одно небольшое изменение в массиве whitelisted_classes
, что позволит нам передавать объекты в следующем виде:
1 2 3 4 5 6 7 |
'whitelisted_classes' => array( 'Fuel\\Core\\Response', 'Fuel\\Core\\View', 'Fuel\\Core\\ViewModel', 'Fuel\Core\Validation', 'Closure', ), |
Настройка групп
Пакет auth, включенный в FuelPHP основан на использовании драйверов. Мы же будем использовать “SimpleAuth”, который является единственным драйвером, включенным в пакет. Когда Вы наберетесь побольше опыта в работе с FuelPHP, то сможете создавать свои собственные драйверы для интеграции других систем – таких как сторонние форумы, системы управления контентом и т.д.
Для активации групп для SimpleAuth мы просто открываем fuel/packages/auth/config/simpleauth.php
и настраиваем группы следующим образом:
1 2 3 4 5 6 7 8 9 |
return array( 'groups' => array( -1 => array('name' => 'Banned', 'roles' => array('banned')), 0 => array('name' => 'Guests', 'roles' => array()), 1 => array('name' => 'Users', 'roles' => array('user')), 50 => array('name' => 'Moderators', 'roles' => array('user', 'moderator')), 100 => array('name' => 'Administrators', 'roles' => array('user', 'moderator', 'admin')), ), ); |
Группы, конечно же, могут быть любыми, но для нашей статьи мы будем использовать стандартный вариант.
Шаг 4 – Создание пользователей
Т.к. мы хотим создать панель администратора, то нам необходимо создать таблицу пользователей, а затем внести в нее запись с пользователем, который будет администратором. Можно воспользоваться чем-то вроде phpMyAdmin или графическим интерфейсом вроде Navicat, но лучше делать такие вещи с помощью Oil:
1 2 3 4 |
$ oil generate model users username:varchar[50] password:string group:int email:string last_login:int login_hash:string profile_fields:text Creating model: /Users/phil/Sites/blog/fuel/app/classes/model/user.php Creating migration: /Users/phil/Sites/blog/fuel/app/migrations/001_create_users.php $ oil refine migrate |
Этим самым мы создаем модель пользователей и миграцию, которая создаст таблицу пользователей. Далее нам необходимо создать администратора. Опять-таки, мы можем сделать это через графический интерфейс, но зачем нам это?
1 2 3 4 5 |
$ oil console Fuel 1.1-rc1 - PHP 5.3.6 (cli) (Sep 8 2011 19:31:33) [Darwin] >>> Auth::create_user('admin', 'password', 'phil@example.com', 100); 1 -- Ctrl + C to exit |
Мы воспользовались консолью Oil, чтобы написать команды в реальном времени и сразу же получить результат. Методу Auth::create_user()
были переданы следующие параметры: имя пользователя, пароль, e-mail адрес, идентификатор группы (group_id
) – 100, для того, чтобы показать, что он администратор. 1
– это ответ выполнения кода, который означает, что user_id
имеет значение 1
.
Шаг 5 – Генерация кода
Генераторы – это отличный способ автоматически сгенерировать большое количество шаблонного кода, на основе которого можно будет создавать приложение.
Как было рассказано в первой статье, используя скаффолдинг, мы можем очень быстро создавать большие фрагменты приложения. Это делается с помощью команды oil
и совсем не обязательно, но знайте, что это отличный способ создать большое количество кода с нуля. Некоторые люди относятся к генераторам кода как к “инструментам для тех, кто не умеет писать код” или думают, что это какая-то черная магия. Однако, если Вы только начинаете познавать фреймворк, и не хотите изучать, что и как в нем работает, то заставить систему сгенерировать код за Вас – не такой уж и плохой вариант.
FuelPHP версии 1.1 на счет генерации кода делает еще один небольшой шаг вперед. Вместо обычного скаффолдинга (незащищенных CRUD-операций) Вы можете сгенерировать админский код. Это работает точно также, но включает еще и простой шаблон администраторской части приложения, администраторский контроллер и т.д. Также используется пакет auth для защиты сгенерированного кода. Воспользовавшись Twitter Bootstrap, все это будет выглядеть очень симпатично. Вам нужно будет только немного настроить приложение, и оно будет готово к использованию.
Это делается из командной строки с помощью Oil. Сейчас мы сгенерируем немного кода, а потом разберем его.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ oil generate admin posts title:string slug:string summary:text body:text user_id:int Creating controller: /Users/phil/Sites/blog/fuel/app/classes/controller/base.php Creating controller: /Users/phil/Sites/blog/fuel/app/classes/controller/admin.php Creating views: /Users/phil/Sites/blog/fuel/app/views/admin/template.php Creating views: /Users/phil/Sites/blog/fuel/app/views/admin/dashboard.php Creating views: /Users/phil/Sites/blog/fuel/app/views/admin/login.php Creating migration: /Users/phil/Sites/blog/fuel/app/migrations/002_create_posts.php Creating model: /Users/phil/Sites/blog/fuel/app/classes/model/post.php Creating controller: /Users/phil/Sites/blog/fuel/app/classes/controller/admin/posts.php Creating view: /Users/phil/Sites/blog/fuel/app/views/admin/posts/index.php Creating view: /Users/phil/Sites/blog/fuel/app/views/admin/posts/view.php Creating view: /Users/phil/Sites/blog/fuel/app/views/admin/posts/create.php Creating view: /Users/phil/Sites/blog/fuel/app/views/admin/posts/edit.php Creating view: /Users/phil/Sites/blog/fuel/app/views/admin/posts/_form.php Creating view: /Users/phil/Sites/blog/fuel/app/views/template.php |
FuelPHP создаст несколько основных шаблонов и файлов, а потом создаст MVC-компоненты для секции post. Запомните, что это то же самое, что и написать код самому, но быстрее. Вы можете посмотреть на результат, перейдя к /blog/public/admin/posts
:
Объяснение сути контроллеров
Мы добавили Controller_Base
, который будет содержать логику для всего приложения. Он может быть унаследован каждым другим контроллером. Файл содержит следующий код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
abstract class Controller_Base extends Controller_Template { public function before() { parent::before(); // Assign current_user to the instance so controllers can use it $this->current_user = Auth::check() ? Model_User::find(Arr::get(Auth::get_user_id(), 1)) : null; // Set a global variable so views can use it View::set_global('current_user', $this->current_user); } } |
Благодаря тому, что мы унаследовали Controller_Template
, все виды будут обернуты в шаблон автоматически. Затем в функции before()
мы делаем небольшие манипуляции с текущим пользователем и делаем так, чтобы он был доступен как $this->current_user
в контроллерах и $current_user
в видах.
Еще один контроллер, который мы создали, имеет имя Controller_Admin
и наследует Controller_Base
. Так что вдобавок к тому, что мы будем иметь доступ к текущему пользователю, мы сможем проверить, является ли он администратором:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
abstract class Controller_Admin extends Controller_Base { public $template = 'admin/template'; public function before() { parent::before(); if ( ! Auth::member(100) and Request::active()->action != 'login') { Response::redirect('admin/login'); } } // .... } |
Вы, наверное, заметили, что он устанавливает конкретный шаблон, поэтому вместо fuel/app/views/template.php
будет использоваться fuel/app/views/admin/template.php
. А затем в функции before()
происходит проверка того, является ли пользователь администратором. Если нет – он будет отправлен на страницу авторизации приложения.
Наследование контроллеров
Возможность наследовать другие контроллеры во FuelPHP – это очень удобная функция. Обычно контроллеры просто напрямую загружаются классом Request после определения маршрута по URL-адресу, но иногда бывает очень полезно унаследовать другой контроллер, чтобы использовать его логику или методы. Например, мы проверяем права доступа в Controller_Admin
. Для того чтобы использовать эту логику нам необходимо унаследовать этот контроллер.
Controller_Admin_Posts
наследует Controller_Admin
. Это означает, что он имеет такую же проверку в функции before()
и поэтому защищен точно также как и любой контроллер в панели администратора.
Что дальше?
Генерация кода – это зачастую только первый шаг в работе над приложением. Нам все еще нужно настроить формы и создать интерфейс. Например, если Вы попробуете создать или отредактировать пост, то поле user_id
будет показано в textarea
.
Шаг 6 – Изменение CRUD-форм
Мы хотим изменить наш метод action_create()
в файле fuel/app/classes/admin/posts.php
, так чтобы нам был доступен список пользователей. Для этого изменим содержимое метода следующим кодом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
public function action_create($id = null) { $view = View::forge('admin/posts/create'); if (Input::method() == 'POST') { $post = Model_Post::forge(array( 'title' => Input::post('title'), 'slug' => Inflector::friendly_title(Input::post('title'), '-', true), 'summary' => Input::post('summary'), 'body' => Input::post('body'), 'user_id' => Input::post('user_id'), )); if ($post and $post->save()) { Session::set_flash('success', 'Added post #'.$post->id.'.'); Response::redirect('admin/posts'); } else { Session::set_flash('error', 'Could not save post.'); } } // Set some data $view->set_global('users', Arr::assoc_to_keyval(Model_User::find('all'), 'id', 'username')); $this->template->title = "Create Post"; $this->template->content = $view; } |
Код содержит всего пару изменений по сравнению с предыдущим:
1 |
$view = View::forge('admin/posts/create'); |
Это создает новый объект View. Мы можем назначать ему свойства, так чтобы данные о пользователях легко передавались и удобно использовались:
1 |
$view->users = array(1 => "User 1", 2 => "User 2"); |
Теперь аналогичным образом отредактируем action_edit()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
public function action_edit($id = null) { $view = View::forge('admin/posts/edit'); $post = Model_Post::find($id); if (Input::method() == 'POST') { $post->title = Input::post('title'); $post->slug = Inflector::friendly_title(Input::post('title'), '-', true); $post->summary = Input::post('summary'); $post->body = Input::post('body'); $post->user_id = Input::post('user_id'); if ($post->save()) { Session::set_flash('success', 'Updated post #' . $id); Response::redirect('admin/posts'); } else { Session::set_flash('error', 'Could not update post #' . $id); } } else { $this->template->set_global('post', $post, false); } // Set some data $view->set_global('users', Arr::assoc_to_keyval(Model_User::find('all'), 'id', 'username')); $this->template->title = "Edit Post"; $this->template->content = $view; } |
Однако, поскольку оба вида create.php
и edit.php
используют шаблон partial_form.php
, а свойства устанавливают переменные только конкретному виду, то нам придется использовать метод View::set_global()
:
1 |
$view->set\_global('users', Arr::assoc_to_keyval(Model\_User::find('all'), 'id', 'username')); |
Объект Model_User
используется для того, чтобы извлечь всех пользователей, а затем переконвертировать данные в ассоциативный массив для нашей формы.
Теперь нужно изменить HTML-код, поэтому удалите блок div, который служит контейнером, а затем измените поле user_id
с input на select:
1 2 3 4 5 6 7 8 |
<div class="clearfix"> <?php echo Form::label('User', 'user_id'); ?> <div class="input"> <?php echo Form::select('user_id', Input::post('user_id', isset($post) ? $post->user_id : $current_user->id), $users, array('class' => 'span6')); ?> </div> </div> |
Этим самым мы настроим select так, чтобы в нем отображались все пользователи. Это единственное изменение, которое требовалось. А сейчас давайте займемся интерфейсом.
Интерфейс
Создание базового интерфейса для блога – задача очень простая, поэтому можно без проблем использовать скаффолдинг.
Создайте новый контроллер fuel/app/classes/controller/blog.php
:
1 2 3 4 5 6 7 8 9 10 11 12 |
class Controller_Blog extends Controller_Base { public function action_index() { $view = View::forge('blog/index'); $view->posts = Model_Post::find('all'); $this->template->title = 'My Blog about Stuff'; $this->template->content = $view; } } |
И файл вида fuel/app/views/blog/index.php
:
1 2 3 4 5 6 7 8 9 |
<h2>Recent Posts</h2> <?php foreach ($posts as $post): ?> <h3><?php echo Html::anchor('blog/view/'.$post->slug, $post->title) ?></h3> <p><?php echo $post->summary ?></p> <?php endforeach; ?> |
Это обычный цикл по массиву $posts
, который содержит все Ваши статьи.
Для этого вида нам необходим цикл, гиперссылка и превью. А вот для того, чтобы отображать отдельный пост мы создадим еще один файл. Мы назовем этот метод контроллера action_view()
и создадим файл вида view.php
:
1 2 3 4 5 |
<h2><?php echo $post->title ?></h2> <p><strong>Posted: </strong><?php echo date('nS F, Y', $post->created_at) ?> (<?php echo Date::time_ago($post->created_at)?>)</p> <p><?php echo nl2br($post->body) ?></p> |
Вот метод для контроллера blog
:
1 2 3 4 5 6 7 8 9 |
public function action_view($slug) { $post = Model_Post::find_by_slug($slug); $this->template->title = $post->title; $this->template->content = View::forge('blog/view', array( 'post' => $post, )); } |
Метод find_by_slug()
– “магический”, он будет добавлять WHERE slug = "foo"
в запрос к базе данных и возвращать единственный экземпляр данных типа Model_Post
.
Вот теперь Вы можете наслаждаться функционалом своего нестилизированного и ужасно выглядящего блога. Также у Вас есть интерфейс администратора для управления блогом.
Шаг 7 – Использование ORM
До сих пор мы использовали ORM с нашими моделями для выполнения основных CRUD-операций. Однако связей мы пока не касались. С помощью ORM это делать очень просто. Чтобы настроить отношения, все, что нам необходимо сделать – это немного изменить наши модели, чтобы показать то, как ORM необходимо “относится” к данным.
Пост создается одним пользователем, поэтому мы можем сказать, что он принадлежит пользователю (“belongs to a user”). В модели Model_Post
необходимо добавить:
1 |
protected static $_belongs_to = array('user'); |
Пользователь может публиковать несколько постов, поэтому добавим следующую строку:
1 |
protected static $_has_many = array('posts'); |
Быстрый способ проверить, что это все работает – выполнить в консоли:
1 2 3 4 5 |
Fuel 1.1-rc2 - PHP 5.3.6 (cli) (Sep 8 2011 19:31:33) [Darwin] >>> $post = Model_Post::find('first'); >>> $post->user->username admin -- Ctrl + C to exit |
Отличная работа!
Теперь мы можем обращаться к $post->user
и выводить имя пользователя, поэтому давайте изменим файл fuel/app/views/blog/view.php
:
1 2 3 4 5 6 7 8 |
<h2><?php echo $post->title ?></h2> <p> <strong>Posted: </strong><?php echo date('nS F, Y', $post->created_at) ?> (<?php echo Date::time_ago($post->created_at)?>) by <?php echo $post->user->username ?> </p> <p><?php echo nl2br($post->body) ?></p> |
Это называется lazy loading. Вот что здесь происходит: когда Вы обращаетесь к $post->user
, то ORM возвращает объект пользователя, основанный на поле user_id
. Это означает, что для получения поста и первого пользователя необходимо выполнить два запроса. А если бы у нас было больше информации, то по мере загрузки страницы выполнялись бы третий, четвертый запросы и т.д. Все эти дополнительные запросы к базе данных сильно замедляют процесс загрузки страницы в целом.
Для увеличения скорости загрузки страниц Вы можете перейти от lazy loading к eager loading, которая, по сути, сообщает ORM о том, что Вы собираетесь использовать поле users в будущем. Это можно выполнить одним большим запросом, но ORM заботливо разделит его на меньшие так, что Вы даже ничего не заметите.
1 |
$post = Model_Post::find_by_slug($slug, array('related' => array('user'))); |
Если Вы взглянете на запрос, который составляет ORM, то он будет похож на что-то в этом роде:
1 |
SELECT <code>t0</code>.<code>id</code> AS <code>t0_c0</code>, <code>t0</code>.<code>title</code> AS <code>t0_c1</code>, <code>t0</code>.<code>slug</code> AS <code>t0_c2</code>, <code>t0</code>.<code>summary</code> AS <code>t0_c3</code>, <code>t0</code>.<code>body</code> AS <code>t0_c4</code>, <code>t0</code>.<code>user_id</code> AS <code>t0_c5</code>, <code>t0</code>.<code>created_at</code> AS <code>t0_c6</code>, <code>t0</code>.<code>updated_at</code> AS <code>t0_c7</code>, <code>t1</code>.<code>id</code> AS <code>t1_c0</code>, <code>t1</code>.<code>username</code> AS <code>t1_c1</code>, <code>t1</code>.<code>password</code> AS <code>t1_c2</code>, <code>t1</code>.<code>group</code> AS <code>t1_c3</code>, <code>t1</code>.<code>email</code> AS <code>t1_c4</code>, <code>t1</code>.<code>last_login</code> AS <code>t1_c5</code>, <code>t1</code>.<code>login_hash</code> AS <code>t1_c6</code>, <code>t1</code>.<code>profile_fields</code> AS <code>t1_c7</code>, <code>t1</code>.<code>created_at</code> AS <code>t1_c8</code>, <code>t1</code>.<code>updated_at</code> AS <code>t1_c9</code> FROM (SELECT <code>t0</code>.<code>id</code>, <code>t0</code>.<code>title</code>, <code>t0</code>.<code>slug</code>, <code>t0</code>.<code>summary</code>, <code>t0</code>.<code>body</code>, <code>t0</code>.<code>user_id</code>, <code>t0</code>.<code>created_at</code>, <code>t0</code>.<code>updated_at</code> FROM <code>posts</code> AS <code>t0</code> ORDER BY <code>t0</code>.<code>id</code> ASC LIMIT 1) AS <code>t0</code> LEFT JOIN <code>users</code> AS <code>t1</code> ON (<code>t0</code>.<code>user_id</code> = <code>t1</code>.<code>id</code>) WHERE (<code>t0</code>.<code>slug</code> = 'women-love-guys-who-use-fuelphp') ORDER BY <code>t0</code>.<code>id</code> ASC |
Сначала это может показаться ужасным, но ORM прекрасно знает, что происходит в этом запросе. Используя этот подход, некоторое время тому назад мы сократили 300+ запросов до 2-х очень быстрых.
Шаг 8 – Добавление комментариев
Большинство руководств по созданию блога заканчиваются на том моменте, когда уж пора перейти к созданию комментариев. Каждому блогу необходимы комментарии и наш не исключение. Давайте их быстро добавим. Начнем с построения интерфейса администратора:
1 2 3 4 5 6 7 8 9 10 11 12 |
$ oil generate admin comments name:string email:string website:string message:text post_id:int Creating migration: /Users/phil/Sites/blog/fuel/app/migrations/003_create_comments.php Creating model: /Users/phil/Sites/blog/fuel/app/classes/model/comment.php Creating controller: /Users/phil/Sites/blog/fuel/app/classes/controller/admin/comments.php Creating view: /Users/phil/Sites/blog/fuel/app/views/admin/comments/index.php Creating view: /Users/phil/Sites/blog/fuel/app/views/admin/comments/view.php Creating view: /Users/phil/Sites/blog/fuel/app/views/admin/comments/create.php Creating view: /Users/phil/Sites/blog/fuel/app/views/admin/comments/edit.php Creating view: /Users/phil/Sites/blog/fuel/app/views/admin/comments/_form.php $ oil refine migrate Migrated app:default to latest version: 3. |
Для комментариев придется выполнить несколько дополнительных изменений, как мы делали и для постов:
Model_User
1 2 |
protected static $_has_many = array('posts', 'comments'); protected static $_belongs_to = array('user'); |
Model_Post
1 2 |
protected static $_belongs_to = array('user'); protected static $_has_many = array('comments'); |
Model_Comment
1 |
protected static $_belongs_to = array('post', 'user'); |
Добавьте комментарий с помощью интерфейса администратора, перейдя по адресу http://localhost/blog/public/admin/comments/create
:
Теперь давайте снова проверим связи в консоли:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
Fuel 1.1-rc2 - PHP 5.3.6 (cli) (Sep 8 2011 19:31:33) [Darwin] >>> Model_Post::find(1)->comments array ( 1 => Model_Comment::__set_state(array( '_is_new' => false, '_frozen' => false, '_data' => array ( 'id' => '1', 'name' => 'Phil Sturgeon', 'email' => 'email@philsturgeon.co.uk', 'website' => 'http://philsturgeon.co.uk/', 'message' => 'This is an epic article.', 'post_id' => '1', 'created_at' => '1322931744', 'updated_at' => '1322931744', ), '_original' => array ( 'id' => '1', 'name' => 'Phil Sturgeon', 'email' => 'email@philsturgeon.co.uk', 'website' => 'http://philsturgeon.co.uk/', 'message' => 'This is an epic article.', 'post_id' => '1', 'created_at' => '1322931744', 'updated_at' => '1322931744', ), '_data_relations' => array ( ), '_original_relations' => array ( ), '_view' => NULL, '_iterable' => array ( ), )), ) |
Вывод массива всех ORM объектов немного избыточен, но зато мы видим все необходимые данные. Это означает, что связи отлично работают. Теперь давайте отредактируем ORM запрос в контроллере blog
в методе action_view()
для добавления комментариев:
1 |
$post = Model_Post::find_by_slug($slug, array('related' => array('user', 'comments'))); |
А теперь измените вид для вывода комментариев и отображения формы для добавления новых:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
<h2><?php echo $post->title ?></h2> <p> <strong>Posted: </strong><?php echo date('nS F, Y', $post->created_at) ?> (<?php echo Date::time_ago($post->created_at)?>) by <?php echo $post->user->username ?> </p> <p><?php echo nl2br($post->body) ?></p> <hr /> <h3 id="comments">Comments</h3> <?php foreach ($post->comments as $comment): ?> <p><?php echo Html::anchor($comment->website, $comment->name) ?> said "<?php echo $comment->message?>"</p> <?php endforeach; ?> <h3>Write a comment</h3> <?php echo Form::open('blog/comment/'.$post->slug) ?> <div class="row"> <label for="name">Name:</label> <div class="input"><?php echo Form::input('name'); ?></div> </div> <div class="row"> <label for="website">Website:</label> <div class="input"><?php echo Form::input('website'); ?></div> </div> <div class="row"> <label for="email">Email:</label> <div class="input"><?php echo Form::input('email'); ?></div> </div> <div class="row"> <label for="message">Comment:</label> <div class="input"><?php echo Form::textarea('message'); ?></div> </div> <div class="row"> <div class="input"><?php echo Form::submit('submit'); ?></div> </div> <?php echo Form::close() ?> |
Этот код выведет все комментарии в очень простом стиле с обычной формой, используя разметку Twitter Bootstrap. Мы уверены, что у Вас получится что-то более симпатичное.
Мы видим, что комментарии успешно отображаются, а новые корректно добавляются. Единственное, что осталось сделать – реализовать сохранение новых комментариев.
Строка Form::open('blog/comment/'.$post->slug)
передаст выполнение кода к blog/comment/women-love-guys-who-use-fuelphp
. Это означает, что контроллеру Controller_Blog
необходим новый метод action_comment($slug)
, который должен выглядеть примерно так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
public function action_comment($slug) { $post = Model_Post::find_by_slug($slug); // Lazy validation if (Input::post('name') AND Input::post('email') AND Input::post('message')) { // Create a new comment $post->comments[] = new Model_Comment(array( 'name' => Input::post('name'), 'website' => Input::post('website'), 'email' => Input::post('email'), 'message' => Input::post('message'), 'user_id' => $this->current_user->id, )); // Save the post and the comment will save too if ($post->save()) { $comment = end($post->comments); Session::set_flash('success', 'Added comment #'.$comment->id.'.'); } else { Session::set_flash('error', 'Could not save comment.'); } Response::redirect('blog/view/'.$slug); } // Did not have all the fields else { // Just show the view again until they get it right $this->action_view($slug); } } |
Выводы
В этой статье опущены такие вещи, как настройка красивых URL-адресов вместо localhost/blog/public и использование валидации форм в модели или контроллере, потому что все это можно найти в официальной документации FuelPHP. Мы хотели осветить такие темы, как загрузка файлов или миграции, но опять-таки все это есть в документации.
К этому моменту Вы научились достаточно, чтобы начать разработку любого проекта с помощью FuelPHP. А все небольшие пробелы в знаниях можно заполнить, прочитав документацию.
Удачи!
Спасибо большое за статью! Все подробно и очень полезно. Сам озаботился созданием админки на Fuel. А тут подробное руководство! :)
Спасибо за статью. Но вот все пишут про оил командную строку и тд, я пытаю изучить фуел на винде и эти команды мне не доступны. А интересует меня вот что — какие стили подключаются когда генерация проходит(если можно ссылку на них) и что там в темплате.пхп?
Виталий!
Вы работаете на Windows, то почему бы Вам не настроить поддержку PHP из командной строки, я на своем компьютере настроил и всё нормально, генерация из примеров очень даже хорошо проходит.
а будет статья про чпу?
добавьте
protected static $_has_many = array (
'comments' => array (
'key_from' => 'id',
'model_to' => 'Model_Comment',
'key_to' => 'post_id',
'cascade_save' => true,
'cascade_delete' => false,
'conditions' => array (
'order_by' => array (
'id' => 'DESC'
)
),
),
);