====== Шаг3. Добавление форм для создания и редактирования новостей. Удаление новостей ======
===== Действие по добавлению новостей =====
==== Шаблон news/create.html для добавления новостей ====
Добавим в папку template/news файл шаблона create.html следующего содержимого:
Limb3 tutorial
Create news
По-сути это обычная hmtl-страница, однако есть кое-какие детали:
* **
** тег имеет атрибут **runat='server'**, который говорит шаблонизатору, что это не просто тег, а компонент шаблона и что ему присуще какое-либо активное поведение (какое именно - будет сказано потом). Обычно любым активным компонентам шаблона даются свои идентификаторы, то есть указывается атрибут **id**.
* Обратите внимание, что элементы формы имеют идентификаторы, совпадающие по названию с названиями полей таблицы news.
==== Изменения в контроллере NewsController ====
Теперь расширим наш контроллер NewsController чтобы он мог принимать данные с формы и добавлять новые записи в базу данных:
request->hasPost())
return;
$news = new News();
$news->import($this->request);
$news->save();
$this->redirect();
}
}
Мы добавили метод doCreate, который будет вызываться при получении нашим приложением запросов вида /news/create. Шаблон будет выбираться аналогично, то есть template/news/create.html, как в случае и с действием по-умолчанию display.
Разберем тело метода doCreate().
if(!$this->request->hasPost())
return;
lmbController для удобства по-умолчанию содержит в себе объекты Запроса **request** и Ответа **response** в качестве своих атрибутов и сокращения записи. Здесь мы проверяем, был ли POST запрос с нашей формы. Если нет - тогда мы просто в первый раз зашли на данную страницу и нужно просто отобразить форму.
$news = new News();
$news->import($this->request);
Мы создали экземпляр класс News и поместили в него все данные из запроса. News автоматически выберет из запроса только те поля, которые есть в таблице news (немного упрощенное описание, но пока оно нас устраивает). Именно поэтому мы дали полям формы в шаблоне create.html имена, совпадающие с названиями полей таблицы news.
$news->save();
Мы сохраняем новую записи в базу данных и ...
$this->redirect();
перебрасываем пользователя на страницу действия по-умолчанию, то есть на /news
Попробуем набрать в адресной строке /news/create. Должно получиться следующее:
{{{:limb3:ru:tutorials:basic:simple_create.png|:limb3:ru:tutorials:basic:simple_create.png}}}
===== Добавление валидации данных =====
Нам хотелось бы, чтобы к полям новостей применялись следующие правила:
* поля title, date и annotation были бы обязательными для заполнения,
* title был меньше 75 символов,
* content - заполнялся бы по желанию пользователя.
Для этого нам необходимо будет внести некоторые изменения в классы News, NewsController и расширить шаблон create.html.
==== Изменения в классе News ====
Итак, теперь класс News будет выглядеть следующим образом:
addRequiredRule('title');
$validator->addRequiredRule('annotation');
$validator->addRequiredRule('date');
lmb_require('limb/validation/src/rule/lmbSizeRangeRule.class.php');
$validator->addRule(new lmbSizeRangeRule('title', 75));
return $validator;
}
}
?>
lmbActiveRecord при вызове метода save() может проверять данные, которые в нее добавили при помощи валидатора. Валидатор создается при помощи метода _createValidator(). По-умолчанию, lmbActiveRecord :: _createValidator() возвращает пустой валидатор. Наша задача - создать свой собственный.
Валидатор - объект класса **lmbValidator**, который располагается в [[limb3:ru:packages:validation|пакете VALIDATION]]. Валидатор состоит из набора правил валидации, которые мы в него и добавляем в методе **_createValidator()**.
Обратите внимание, что строку
$validator->addRequiredRule('title');
можно переписать как
lmb_require('limb/validation/src/rule/lmbRequiredRule.class.php');
$validator->addRule(new lmbRequiredRule('title'));
по своей сути эквивалентны,а второй вариант приведен для ясности - в большинстве случаев используется именно сокращеннй первый вариант.
Итого мы использовали 2 правила:
* **lmbRequiredRule** - обязывает поле присутствовать в проверяемом объекте
* **lmbSizeRangeRule** - обязывает поле содержать определенное количество символов. В нашем случае - не больше 75.
==== Изменения в классе NewsController ====
В действие doCreate() контроллера NewsController нам нужно будет внести некоторые изменения:
request->hasPost())
return;
$news = new News();
$news->import($this->request);
$this->useForm('news_form');
$this->setFormDatasource($news);
if($news->trySave($this->error_list))
$this->redirect();
}
}
?>
Обратите внимание на следующие строки:
$this->useForm('news_form');
$this->setFormDatasource($news);
if($news->trySave($this->error_list))
$this->redirect();
При помощи первых двух строк мы связываем активный компонент формы, находящийся в шаблоне с объектом новости. Это позволит нам не терять данные в полях формы, если часть данных была введена неверно.
Метод lmbActiveRecord :: **trySave($error_list)** возвращает true, если все данные были введены верно и false, если существовали ошибки. trySave() является лишь "оберткой" для метода save(): метод save() при обнаружении ошибок валидации генерирует исключение класса lmbValidationException, которое ловится в методе trySave().
==== Изменения в шаблоне news/create.html ====
Теперь добавим в шаблон template/news/create.html код для отображения ошибок валидации:
[...]
Create news
Title :
[...]
Для вывода ошибок мы использовали тег ****, который передает список ошибок валидации из формы в компонент, указанный атрибутом **target**. Ошибки будут выводится при помощи тегов и работу которых уже была описана.
Ошибки валидации будут попадать в шаблон автоматически, так как мы связали объект класса News с активной формой в методе doCreate() контроллера NewsController.
Теперь попробуем ввести неверные данные и проверить систему валидации:
{{{:limb3:ru:tutorials:basic:simple_create_errors.png|:limb3:ru:tutorials:basic:simple_create_errors.png}}}
Если вы увидели нечто подобное, значит вы все делаете правильно.
===== Действие по редактированию новости =====
==== Шаблон edit.html ====
Шаблон по редактированию новости template/news/edit.html выглядит почти точно также как и template/news/create.html:
Limb3 tutorial
Edit news
Title :
Date :
Annotation :
Content :
Налицо большое дублирование, которое может быть легко устранено. Мы займемся оптимизацией шаблонов чуть позже.
==== Метод NewsController :: doEdit() ====
Теперь добавим метод doEdit в класс NewsController, чтобы наш контроллер мог правильно отрабатывать действие edit:
request->get('id'));
$this->useForm('news_form');
$this->setFormDatasource($news);
if(!$this->request->hasPost())
return;
$news->import($this->request);
if($news->trySave($this->error_list))
$this->redirect();
}
?>
Строкой
$news = new News((int)$this->request->get('id'));
мы загружаем объект новости с определенным идентификатором, который мы получаем из запроса.
Обратите внимание, что мы связали форму в шаблоне с новостью до проверки $this->request->hasPost(), так как нам нужно передавать данные в шаблон в любом случае. При первоначальном отображении формы поля уже будут заполнены полями из загруженной новости.
==== Модификация шаблона template/news/display.html ====
Теперь изменим шаблон template/news/display.html чтобы вывести ссылку на страницу редактирования новостей. Добавим новую колонку для вывода доступных действий:
Newsline
Newsline.
Create news
ID
Date
Title
Actions
{$id}
{$date}
{$title}
Edit
Delete
{$annotation}
Здесь мы использовали тег [[limb3:ru:packages:wact:tags:lmb_request_tags:lmb_route_url_tag|]], который является по сути аналогом тега , однако он умеет формировать атрибут href на основе параметров, которые ему указаны в атрибуте **params**. По сути route_url осуществляет процесс разбора строки запроса вида /news/create в обратном порядке.
Все, что касается деталей разбора запроса выходит за рамки данного туториала, однако если вам интересны правила, на основе которых осуществляется определение текущего контроллера, посмотрите файл limb/web_app/settings/routes.conf.php.
Поясним работу тега :
Create news
Этот код сформирует строку вида: Create news . news будет взят приложением автоматически, так как мы находимся на странице, за которую отвечает контроллер news. create будет взято из пары action:create, где action - это название параметра, а create - значение параметра.
Точно также формируются ссылки на действия edit и delete. Параметры в атрибуте params тега разделяются через запятую. То есть тег вида Edit сформирует ссылку вида: Edit
Если вы все сделали правильно, тогда вы должны иметь теперь возможность создавать и редактировать новости.
===== Удаление новостей =====
Для удаления объектов lmbActiveRecord используется метод destroy(). Добавим метод NewsController :: doDelete():
request->get('id'));
$news->destroy();
$this->redirect();
}
}
?>
Пояснять код нет необходимости.
===== Что дальше? =====
Далее: [[step4|Шаг4. Оптимизация шаблонов. Добавление постраничного вывода.]]