CodeIgniter 4. Роутинг. Формы. REST
16-08-2019Время чтения ~ 6 мин.CodeIgniter 12847
Работа 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"> ...
После этого роутинг сработает и дальше обрабатываем данные как обычно.