Класс Input

Давайте теперь сделаем класс Input для работы с инпутами. Вот готовая реализация этого класса:

<?php class Input extends Tag { public function __construct() { parent::__construct('input'); } } ?>

Давайте используем новый класс Input вместе с уже созданным нами классом Form:

<?php $form = (new Form)->setAttrs(['action' => '', 'method' => 'GET']); echo $form->open(); echo (new Input)->setAttr('name', 'year')->open(); echo (new Input)->setAttr('type', 'submit')->open(); echo $form->close(); ?>

В результате получится следующая форма:

<form action="" method="GET"> <input name="year"> <input type="submit"> </form>

Скопируйте себе мой код класса Input. Скопируйте пример формы. Запустите его в браузере, убедитесь, что форма действительно появляется. Вбейте какие-нибудь данные в инпут и нажмите на кнопку отправки. Убедитесь, что форма действительно рабочая.

Убираем open

Давайте уберем метод open, добавив магию метода __toString:

<?php class Input extends Tag { public function __construct() { parent::__construct('input'); } public function __toString() { return parent::open(); } } ?>

Перепишите приведенный ниже код с учетом нашей правки:

<?php $form = (new Form)->setAttrs(['action' => '', 'method' => 'GET']); echo $form->open(); echo (new Input)->setAttr('name', 'year')->open(); echo (new Input)->setAttr('type', 'submit')->open(); echo $form->close(); ?>

Некоторые замечания

Пока наш PHP код формы получается длиннее соответствующего HTML кода. Возникает вопрос: зачем нам PHP вариант, если все намного короче можно написать на HTML?

Все дело в том, что наша PHP реализация дает нам дополнительные возможности. Например, мы можем сделать так, чтобы данные из инпутов не исчезали после отправки формы.

И теперь преимущество в длине кода будет уже на стороне PHP варианта - длина HTML варианта существенно вырастет, а длина PHP варианта останется неизменной.

Реализация сохранения значений после отправки

Как вы должны знать, значение инпута задается в атрибуте value. Нам необходимо сделать следующее: если форма была отправлена, то в value инпута следует записать то значение, которое было в нем в момент отправки.

Каким образом получить это значение? Пусть имя инпута было year. В этом случае после отправки формы в $_REQUEST['year'] и будет находится нужное нам значение.

В нашем случае имя инпута хранится в родительском классе Tag в приватном свойстве $attrs. Наш класс Input как потомок класса Tag может получить доступ к любому атрибуту с помощью геттера, вот так: $inputName = $this->getAttr('name').

Давайте получим имя нашего инпута, достанем значение из $_REQUEST по этому имени и запишем в value инпута:

<?php class Input extends Tag { public function __construct() { parent:__construct('input'); } // Переопределяем метод родителя: public function open() { $inputName = $this->getAttr('name'); // имя инпута $value = $_REQUEST[$inputName]; // получаем значение инпута по его имени $this->setAttr('value', $value); // записываем в value инпута return parent::open(); // вызываем метод open родителя } public function __toString() { return $this->open(); // здесь теперь не метод родителя, а наш } } ?>

Приведенный выше код пока не очень корректный: он не учитывает того, что отправки формы могло еще и не быть. Давайте учтем:

<?php // Пока не запускайте этот код, есть нюансы... class Input extends Tag { public function __construct() { parent:__construct('input'); } // Переопределяем метод родителя: public function open() { $inputName = $this->getAttr('name'); // имя инпута // Если форма была отправлена и есть данные с именем нашего инпута: if (isset($_REQUEST[$inputName])) { $value = $_REQUEST[$inputName]; // получаем значение из $_REQUEST $this->setAttr('value', $value); // записываем в value инпута } return parent::open(); // вызываем метод open родителя } public function __toString() { return $this->open(); } } ?>

Вот теперь наш код уже достаточно рабочий, но есть пару нюансов.

Что будет, если у нашего инпута по умолчанию уже есть какое-то значение (например, текущий год), например, вот так:

<?php echo (new Input) ->setAttr('name', 'year') ->setAttr('value', date('Y')); // значение по умолчанию ?>

В этом случае в теории по заходу на страницу мы должны увидеть текущий год, но при желании можем его поменять, нажать на кнопку отправки - и после обновления страницы в инпуте будет тот год, который и был отправлен.

На самом деле наш код так и работает! Если была отправка формы, то мы попадем в условие и там изменим value инпута, но если отправки не было - value инпута останется таким, как и было задано.

Второй нюанс: есть инпуты, у которых нет атрибута name. Например, кнопка отправки формы. В этом случае с такими инпутами ничего и не надо делать. Учтем это дополнительным условием:

<?php class Input extends Tag { public function __construct() { parent:__construct('input'); } public function open() { $inputName = $this->getAttr('name'); // Если атрибут name задан у инпута: if ($inputName) { if (isset($_REQUEST[$inputName])) { $value = $_REQUEST[$inputName]; $this->setAttr('value', $value); } } return parent::open(); } public function __toString() { return $this->open(); } } ?>

Ну вот теперь можно пробовать. Можете запустить приведенный ниже код формы, вбить что-то в инпут и нажать на кнопку отправки - после обновления страницы данные из инпута не исчезнут:

<?php $form = (new Form)->setAttrs(['action' => '', 'method' => 'GET']); echo $form->open(); echo (new Input)->setAttr('name', 'year'); echo (new Input)->setAttr('type', 'submit'); echo $form->close(); ?>

А вот пример, когда в инпуте уже есть какое-то значение по умолчанию:

<?php $form = (new Form)->setAttrs(['action' => '', 'method' => 'GET']); echo $form->open(); echo (new Input)->setAttr('name', 'year')->setAttr('value', date('Y')); echo (new Input)->setAttr('type', 'submit'); echo $form->close(); ?>

Реализуйте самостоятельно сохранение значений инпутов после отправки. Проверьте работу данного механизма.

С помощью созданного класса сделайте форму с 5-ю инпутами. Пусть в каждый инпут можно ввести число. Сделайте так, чтобы после отправки на экран выводилась сумма этих чисел, а введенные значения не пропадали из инпутов.