CodeIgniter 4. Роутинг. Формы. REST

Работа 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">
    ...

После этого роутинг сработает и дальше обрабатываем данные как обычно.

Оставьте комментарий!

Комментарий будет опубликован после проверки. Вы соглашаетесь с правилами сайта.

(обязательно)