Сайт вебмастера

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">
	...

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

Related Posts