CodeIgniter 4. Роутинг. Формы. REST
16-08-2019Reading time ~ 6 min.CodeIgniter 12063
Работа CodeIgniter базируется на роутинге, который принимает входящий url-адрес и выполняет подходящий контролёр. До этого мы использовали «автороутинг», когда первый сегмент адреса совпадал с именем контролёра. Но в большинстве случаев такая схема слишком примитивная, поэтому нужно будет настраивать роутинг на адреса, которые не совпадают с файлом контролёра.
Например мы хотим сделать адреса вида example.com/pages/about, где about может меняться произвольно. Формально мы можем сделать контролёр Pages и в нём разместить только метод index()
, где и «перехватывать» второй сегмент адреса. Однако мы всё-таки решим эту задачу «по взрослому» — научимся настраивать роутинг.
Конфигурация роутинга хранится в файле app/config/Routes.php
. Откройте его и в конце добавьте строчку:
$routes->add('pages/(:segment)', 'Blog::show/$1');
В данном случае метод add()
добавляет новое правило роутинга. Первым параметром указывается шаблон заголовка — placeholder, где можно использовать обычные регулярные выражения. Но, как правило, вполне достаточно существующих замен, например этих:
(:segment)
— заменяется на любой набор символом, ограниченный слэшем «/».(:any)
— просто любой набор символов.(:num)
— только цифры.
В этоме примере роутер сработает на адрес example.com/pages/about, но не сработает на example.com/pages и example.com/pages/about/23.
Вторым параметром указывается контролёр и его метод. Здесь это Blog и метод show(), которому будет передан параметр — второй сегмент адреса.
Создадим новый контролёр Blog.php
.
namespace App\Controllers; class Blog extends BaseController { public function show($segment) { $data['title'] = 'Страница ' . $segment; $data['header'] = 'Это страница ' . $segment; echo view('template/start', $data); echo view('about', $data); echo view('template/end', $data); } }
В качестве «вьюшки» будем использовать about из предыдущей статьи. Наберём в браузере example.com/pages/about и увидим сообщение:
Это страница about
Подобным образом можно настраивать любые адреса и контролёры. Я не буду описывать все возможности, но дам ссылку на страницу документации, где вы сами сможете посмотреть примеры.
REST
Мы добавляли новый роутинг с помощью метода add()
. Это «общий» вариант, когда адрес будет принимать и GET и POST http-запросы. Если мы хотим сделать полноценное приложение, то следует придерживаться концепции REST: http-метод указывает на какое-то действие.
Предположим у нас есть форма. Она отображается по адресу example.com/form и это соответствует http-запросу GET. Форму мы отправляем методом POST, который отправляется на тот же самый адрес. То есть на уровне роутинга нужно задать такие правила, чтобы GET обработал один метод контролёра, а POST — другой.
Во многих приложениях используются и другие (произвольные) http-методы: PUT, DELETE и т.д.
Допишем новые правила. В CodeIgniter для этого уже нужно использовать методы класса роутинга get(), post() и т.д. Cделаем это для нового контролёра Login.
$routes->get('form', 'Login::showForm'); $routes->post('form', 'Login::postForm');
Теперь код Login.php
:
namespace App\Controllers; class Login extends BaseController { public function showForm() { $data['title'] = 'Форма'; $data['header'] = 'Отображение формы'; echo view('template/start', $data); echo view('login', $data); echo view('template/end', $data); } public function postForm() { $data['title'] = 'Форма'; $data['header'] = 'POST-данные от формы'; echo view('template/start', $data); echo view('login', $data); echo view('template/end', $data); } }
Для простоты мы выводим разные заголовки для разных методов. Теперь сделаем «вьюшку» login.php
:
<h1><?= $header ?></h1> <form method="POST"> <h5>Username</h5> <input type="text" name="username" value="" size="50"> <h5>Password</h5> <input type="text" name="password" value="" size="50"> <div><button type="submit">Submit</button></div> </form>
Это самая обычная форма, которая отправляет POST-запрос на свой же адрес (нет параметра action). Откройте страницу в браузере. Выводится сообщение
Отображение формы
Если же нажать кнопку отправить, то оно изменится на
POST-данные от формы
То есть роутинг определяет нужный http-метод.
Валидация POST
В этом примере у нас пока нет процедуры валидации данных формы. На сей счёт есть несколько вариантов решений. Самый простой — это проверять результат обработки формы и если всё ok, выводить какую-то другую «вьюшку». Если есть ошибки, то вывести их и тут же новую форму или ссылку на форму.
Но немного удобней всё-таки использовать одну вьюшку, которая будет сама решать как и что выводить. Перепишем «вьюшку» login.php
:
<h1><?= $header ?></h1> <?php if ($validation) echo $validation->listErrors(); echo $message; ?> <?php if ($showForm) : ?> <form method="POST"> <h5>Username</h5> <input type="text" name="username" value="" size="50"> <h5>Password</h5> <input type="text" name="password" value="" size="50"> <div><button type="submit">Submit</button></div> </form> <?php endif ?>
Здесь мы управляем отображением формы с помощью переменой $showForm
. Переменная $message
выводит сообщение об успешной отправке формы. Переменная $validation
выводит список ошибок, если они есть.
Чтобы сформировать все эти данные, перепишем методы контролёра. Буду показывать по отдельности.
public function showForm() { $data['title'] = 'Форма'; $data['header'] = 'Отображение формы'; $data['validation'] = ''; $data['showForm'] = true; $data['message'] = ''; echo view('template/start', $data); echo view('login', $data); echo view('template/end', $data); }
По сути здесь всё осталось как и раньше, только добавились новые данные. Рассмотрим postForm().
public function postForm() { $data['title'] = 'Форма'; $data['header'] = 'POST-данные от формы'; $data['validation'] = ''; $data['showForm'] = true; $data['message'] = ''; $rules = [ 'username' => [ 'label' => 'Username', 'rules' => 'required', 'errors' => [ 'required' => 'Требуется указать имя пользователя', ] ], 'password' => [ 'label' => 'Password', 'rules' => 'required|min_length[10]', 'errors' => [ 'required' => 'Требуется указать пароль', 'min_length' => 'Пароль должен быть более 10 символов', ] ] ]; if (!$this->validate($rules)) $data['validation'] = $this->validator; else { $data['showForm'] = false; $data['message'] = 'Спасибо!'; } echo view('template/start', $data); echo view('login', $data); echo view('template/end', $data); }
Здесь мы используем валидацию POST-данных с помощью CodeIgniter. Для этого применяется метод $this->validate()
, который принимает массив правил. Работает это так: как только $this->validate()
возвратит false, то есть валидация не пройдена, в $data['validation']
мы передадим $this->validator
, которая будет состоять из списка (UL/LI) указаных ошибок.
Если же ошибок нет, то мы ставим флаг, чтобы форму не показывать и какое-то своё сообщение.
Правила проверки описаны на странице документации. Они довольно обширны, поэтому я не буду на них останавливаться.
Существует возможность задавать правила валидации в двух массивах: первый описывает только правила, второй - сообщения.
public function postForm() { $data['title'] = 'Форма'; $data['header'] = 'POST-данные от формы'; $data['validation'] = ''; $data['showForm'] = true; $data['message'] = ''; $rules = [ 'username' => 'required', 'password' => 'required|min_length[10]', ]; $errorMessages = [ 'username' => [ 'required' => 'Требуется указать имя пользователя', ], 'password' => [ 'required' => 'Требуется указать пароль', 'min_length' => 'Пароль должен быть более 10 символов', ] ]; if (!$this->validate($rules, $errorMessages)) $data['validation'] = $this->validator; else { $data['showForm'] = false; $data['message'] = 'Спасибо!'; } echo view('template/start', $data); echo view('login', $data); echo view('template/end', $data); }
RESTFul
Для полной реализации RESTFul не хватает поддержки других http-методов. Например вместо POST нужно использовать PUT.
Изменим роутинг:
$routes->get('form', 'Login::showForm'); $routes->put('form', 'Login::postForm');
То есть мы используем тот же метод контролёра, только уже для PUT. Если сейчас отправить форму, то получим 404-страницу — это очевидно, поскольку форма отправляет POST, а PUT она отправлять не умеет.
Чтобы обойти это ограничение в CodeIgniter, как и во многих других фреймворках используется дополнительное, обычно скрытое поле в форме с именем _method
в котором и указывается нужный http-метод.
<form method="POST"> <input type="hidden" name="_method" value="PUT"> ...
После этого роутинг сработает и дальше обрабатываем данные как обычно.