Благодаря FuelPHP классу fieldset, работа с формами может быть очень простой.
Используя несколько строк кода, вы можете легко сгенерировать и проверить форму. Сегодня мы узнаем, как это сделать. Здесь вы можете посетить бесплатный интернет магазин
Класс
Fieldset
используется для создания формы и управления её проверкой объектно-ориентированным способом. Он использует классыForm
иValidation
. Сам класс непосредственно предназначен только для того, чтобы смоделировать набор полей формы, в то время, как два других класса выполняют основную работу.
Установка Fuel
Нам нужно установить FuelPHP с подключённым пакетом RM. Мы собираемся использовать базу данных MySQL со стандартной таблицей. В то время, как класс Fieldset
может быть сконфигурирован с использованием обычной модели, использование ORM сэкономит нам немного времени.
Если вы не читали два урока, посвящённые FuelPHP, на сайте Nettuts+, сейчас самое время прочитать первую (eng.) и вторую (eng.) статьи от Phil Sturgeon.
Настройте соединение базы данных в 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' => 'root', ), ), ); |
Включите пакет ORM через fuel/app/config.php
1 2 3 |
'packages' => array( 'orm', ), |
И наконец, вот SQL код для таблицы, которую мы используем в этом уроке.
1 2 3 4 5 6 7 8 9 |
CREATE TABLE `blog`.`posts` ( `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , `post_title` VARCHAR( 100 ) NOT NULL , `post_content` TEXT NOT NULL , `author_name` VARCHAR( 65 ) NOT NULL , `author_email` VARCHAR( 80 ) NOT NULL , `author_website` VARCHAR( 60 ) NULL, `post_status` TINYINT NULL ) ENGINE = INNODB; |
Модель
Нам нужна модель для нашего контроллера, чтобы работать с таблицей постов. Создайте post.php
в app/classes/model/
. Затем создайте класс Model_Post
и убедитесь, что он расширяет \Orm\Model
. ORM автоматически будет использовать таблицу posts
в нашей базе данных, т.к. мы использовали только её. Если вы хотите установить другую таблицу, настройте статическое свойство $_table_name
.
1 2 3 4 |
class Model_Post extends \Orm\Model { protected static $_table_name = 'posts'; //установка названия таблицы вручную } |
Настройка свойств
Мы должны определить столбцы нашей таблицы постов в пределах нашей модели. В то же время, мы можем также установить метки, правила проверки формы для использования с нашим классом fieldset, чтобы сгенерировать форму. Всё это вместе входит в связанный массив $_properties
. Если собрать всё воедино, наша конечная модель должна выглядеть так:
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 |
class Model_Post extends \Orm\Model { protected static $_table_name = 'posts'; protected static $_properties = array( 'id', 'post_title' => array( //column name 'data_type' => 'string', 'label' => 'Post Title', //label for the input field 'validation' => array('required', 'max_length'=>array(100), 'min_length'=>array(10)) //правила валидации ), 'post_content' => array( 'data_type' => 'string', 'label' => 'Post Content', 'validation' => array('required') ), 'author_name' => array( 'data_type' => 'string', 'label' => 'Author Name', 'validation' => array('required', 'max_length'=>array(65), 'min_length'=>array(2)) ), 'author_email' => array( 'data_type' => 'string', 'label' => 'Author Email', 'validation' => array('required', 'valid_email') ), 'author_website' => array( 'data_type' => 'string', 'label' => 'Author Website', 'validation' => array('required', 'valid_url', 'max_length'=>array(60)) ), 'post_status' => array( 'data_type' => 'string', 'label' => 'Post Status', 'validation' => array('required'), 'form' => array('type' => 'select', 'options' => array(1=>'Published', 2=>'Draft')), ) ); } |
Давайте узнаем, какие опции мы можем использовать. data_type
просто определяет тип поля. Это может быть string (строка), integer (целое число) или mysql_date. Значение свойства label
будет показано, как метка поля, когда форма будет сформирована. validation
вводит массив правил проверки. По умолчанию, эти поля являются текстовыми. Но используя form
, вы можете изменить их тип на select
или texarea
.
ORM обрабатывает столбец под названием id
, как первичный, и он не будет показан во время генерации формы. Если у вас другой первичный столбец таблицы, используйте свойство $_primary_key
, чтобы определить его.
1 2 3 4 5 6 7 8 9 |
/** * Post Model */ class Model_Post extends \Orm\Model { protected static $_table_name = 'posts'; protected static $_primary_key = array('id'); //вы может установить несколько столбцов, .. $_primary_key => array('id', 'user_id') } |
Контроллер
Теперь, когда модель готова, давайте создадим контроллер. Контроллеры должны быть размещены в fuel/app/classes/controller/
. Мы создали контроллер, под названием Controller_Posts (posts.php)
и расширили его из Controller_Template
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/** * Post Controller fuel/app/classes/controller/posts.php */ class Controller_Posts extends \Controller_Template { //list posts function action_index() { } //add new one function action_add() { } //edit function action_edit($id) { } } |
Пользователи смогут видеть список постов, добавлять новые или редактировать существующие. Поскольку мы используем шаблонный контроллер, мы можем использовать для работы основной файл шаблона. Шаблоны находятся в fuel/app/views/template.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 33 34 35 |
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <?php echo Asset::css('bootstrap.css'); ?> </head> <body> <div id="content"> <p> <?php echo \Html::anchor('posts/index', 'Listing'), ' ', \Html::anchor('posts/add', 'Add'); ?> </p> <?php if(isset($messages) and count($messages)>0): ?> <div class="message"> <ul> <?php foreach($messages as $message) { echo '<li>', $message,'</li>'; } ?> </ul> </div> <?php endif; ?> <?php echo $content; ?> </div> </body> </html> |
Это просто стандартная HTML разметка. Переменная $content
будет содержать контент. Мы можем установить массив переменных, и если мы так сделаем, то этот массив будет отображён в виде неупорядоченного списка.
Добавление новых постов
Вот теперь начинаются развлечения. Мы собираемся создать форму для добавления новых постов. Как вы, возможно, предположили, мы будем работать с методом action_add()
. Давайте сгенерируем форму и передадим её нашему шаблону.
1 2 3 4 5 6 7 8 |
//добавить function action_add() { $fieldset = Fieldset::forge()->add_model('Model_Post'); $form = $fieldset->form(); $this->template->set('content', $form->build(), false); //false говорит fuel не преобразовывать html теги в безопасную строку. } |
Fieldset::forge()
возвращает новый экземпляр класса поля. Это идентично выполнению new Fieldset
. Однако, использование здесь метода forge
позволяет нам указать название нового экземпляра класса. Если мы назовём свой класс второй раз одинаковым именем, существующий экземпляр класса будет возвращён, если это доступно [the Factory pattern]. Чтобы назвать свой класс, передайте название методу forge
. Fieldset::forge('new_post')
Используя метод add_model
, мы передаём модель, из которой должны генерироваться формы. Fieldset возмет информацию из $_properties
, чтобы сгенерировать форму. Вызов метода form()
из объекта fieldset
возвратит экземпляр класса Form
, а вызывая метод build()
, мы можем получить html (строковый) вывод формы.
1 |
$this->template->set('content', $form, false); |
Наконец, мы передаём $form
шаблону, как контент. Другой метод передачи переменных шаблону это $this->template->content = $form
.
Запустите свой браузер и введите в адресную строку http://path_to_site/index.php/posts/add
. Вы должны увидеть форму, идентичную этой.
Нет кнопки подтверждения? Давайте исправим это. Нам нужно добавить новое поле нашему объекту формы.
1 |
$form->add('submit', '', array('type' => 'submit', 'value' => 'Add', 'class' => 'btn medium primary')); |
Используя метод add
, мы можем добавлять дополнительные поля в нашу форму. Первый параметр это новое название поля, второй — его метка, а третьим параметром мы передаём массив атрибутов.
После добавления, наш action_add()
будет выглядеть так.
1 2 3 4 5 6 7 8 |
function action_add() { $fieldset = Fieldset::forge()->add_model('Model_Post'); $form = $fieldset->form(); $form->add('submit', '', array('type' => 'submit', 'value' => 'Add', 'class' => 'btn medium primary')); $this->template->set('content', $form->build(), false); } |
А наша форма...
Проверка и сохранение
Теперь, когда у нас есть форма, давайте проверим её правильность и сохраним в базе данных. Объект fieldset
включает экземпляр класса валидации FuelPHP. Все правила применены и готовы к работе.
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 |
function action_add() { $fieldset = Fieldset::forge()->add_model('Model_Post'); $form = $fieldset->form(); $form->add('submit', '', array('type' => 'submit', 'value' => 'Add', 'class' => 'btn medium primary')); if($fieldset->validation()->run() == true) { $fields = $fieldset->validated(); $post = new Model_Post; $post->post_title = $fields['post_title']; $post->post_content = $fields['post_content']; $post->author_name = $fields['author_name']; $post->author_email = $fields['author_email']; $post->author_website = $fields['author_website']; $post->post_status = $fields['post_status']; if($post->save()) { \Response::redirect('posts/edit/'.$post->id); } } else { $this->template->messages = $fieldset->validation()->errors(); } $this->template->set('content', $form->build(), false); } |
$fieldset->validation()
передаёт экземпляр класса валидации, и обратившись к его методу run()
, мы можем проверить, пройдена ли валидация. Если так, мы добавляем новый пост в нашу базу данных. $fieldset->validated()
возвращает массив проверенных полей. Если проверка пройдена, и пост сохранён, пользователь будет переадресован на страницу редактирования, в противном случае ошибки проверки будут переданы нашему шаблону, как переменная сообщения.
Если вы попытаетесь подтвердить какие-либо недопустимые данные, вы получите подобный результат:
Всё, кажется, прекрасно, за исключением одной проблемы: данные, которые мы подтвердили не появляются после перезагрузки страницы. Не волнуйтесь, один запрос метода и всё готово.
1 |
$fieldset = Fieldset::forge()->add_model('Model_Post')->repopulate(); //метод repopulate заполнит форму сохранённой информацией |
Круто? Добавьте какие-то допустимые данные, и вы будете переадресованы к методу action_edit()
, который ещё не готов.
Редактирование поста
Редактирование очень похоже на добавление поста. За исключением того, что мы должны заполнить секцию данными из существующего поста. Мы собираемся дублировать код action_add
.
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 |
function action_edit($id) { $post = \Model_Post::find($id); $fieldset = Fieldset::forge()->add_model('Model_Post')->populate($post); //объект поста передан методу populate $form = $fieldset->form(); $form->add('submit', '', array('type' => 'submit', 'value' => 'Save', 'class' => 'btn medium primary')); if($fieldset->validation()->run() == true) { $fields = $fieldset->validated(); //$post = new Model_Post; $post->post_title = $fields['post_title']; $post->post_content = $fields['post_content']; $post->author_name = $fields['author_name']; $post->author_email = $fields['author_email']; $post->author_website = $fields['author_website']; $post->post_status = $fields['post_status']; if($post->save()) { \Response::redirect('posts/edit/'.$id); } } else { $this->template->messages = $fieldset->validation()->errors(); } $this->template->set('content', $form->build(), false); } |
С некоторыми небольшими модификациями нашего метода action_add()
, у нас есть свой метод редактирования. Метод repopulate()
был заменён на метод populate()
. Используя метод populate
, мы можем заполнить форму существующими данными поста.
В этом случае мы получаем пост из нашей базы данных, используя параметр $id
, а затем передаём его необходимому методу. Мы больше не нуждаемся в $post = new Model_Post;
, поскольку мы ничего не добавили в базу данных. Объект $post
, который мы создаём в начале, используется, чтобы назначить новые значения. Как только пост отредактирован, вы будете переадресованы назад к экрану редактирования. Всё готово! Добавьте несколько постов и попытайтесь их отредактировать.
Страницы списка
Давайте создадим раздел списка постов, так пользователи смогут увидеть все посты в одном месте.
Список будет обработан методом action_index()
.
1 2 3 4 5 6 7 8 9 10 |
//список function action_index() { $posts = \Model_Post::find('all'); $view = \View::forge('listing'); $view->set('posts', $posts, false); $this->template->content = $view; //In config file View objects are whitelisted so Fuelphp will not escape the html. } |
Model_Post::find('all')
возвратит массив объектов всех наших постов. Используя View::forge()
, мы создаём новый объект просмотра. Параметр для View::forge()
— это название нашего определённого просмотра. Они располагаются в app/views/listing.php
. Затем массив объектов постов ($posts
) передаётся нашему «view». «Listing» позаботится о списке, и наконец, мы назначаем просмотр на $this->template->content
.
В просмотре мы выполняем цикл в $posts
и генерируем список.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<?php /** * Listing view, views/listing.php */ if($posts): foreach($posts as $post): ?> <div class="post"> <h2><?php echo $post->post_title; ?> <small><?php echo \Html::anchor('posts/edit/'.$post->id, '[Edit]');?></small></h2> <p><?php echo $post->post_content; ?></p> <p> <small>By <?php echo $post->author_name; ?></small><br /> <small><?php echo $post->author_email; ?></small><br /> <small><?php echo $post->author_website; ?></small><br /> </p> </div> <?php endforeach; endif; ?> |
Если у вас есть несколько постов в базе данных, то это должно выглядеть так.
Некоторые конечные доработки
Кажется всё работает правильно; однако, есть некоторые незначительные проблемы. У сгенерированной формы есть текстовое поле для контента поста, которое будет лучше выглядеть, как textarea
.
1 2 3 4 5 6 7 |
//Model_Post 'post_content' => array( 'data_type' => 'string', 'label' => 'Post Content', 'validation' => array('required'), 'form' => array('type' => 'textarea') //даст нам поле textarea ), |
Вы можете передать все типы полей: text
, textarea
, select
, radio
и т.д. Для элементов select
или radio
вы можете установить опции. Установка опций для select
, используя другую таблицу также возможна. Если вы хотите изменить стандартную разметку, поместите файл конфигурации формы в fuel/app/config/form.php
. Если вы не уверены, что ставить туда, скопируйте материал из fuel/core/config/form.php
. Fuel использует этот файл для генерации форм.
Итоги
Мы надеемся, у вас теперь есть ясное понимание класса fieldset. Если у вас есть какие-нибудь вопросы, задавайте их в комментариях. Большое спасибо за чтение!
Очень интересно. Начинаю осваивать этот фреймворк, ваша статья очень помогла начать. Спасибо и удачи в развитии!
с очевидной ерундой...
А как при помощи ORM вставить несколько строк?
странно в контроллере обрабатывать вьюху. по уму они должны быть разделены. кст вот прикольный пакет для генерации круда одной строкойgithub.com/rizacelik/FuelScaffold