тк 3 июля праздник (в беларуси), буду не онлайн (по возможности буду отвечать)

CSS классы в классе Tag ООП на PHP

Пусть у нас дан вот такой инпут с атрибутом class:

<input class="eee bbb kkk">

Как вы видите, атрибут class содержит в себе несколько значений, разделенных пробелами. Эти значения представляют собой несколько CSS классов нашего элемента.

Давайте реализуем в нашем классе Tag набор методов, которые будут работать с этими CSS классами.

Например, было бы удобно иметь метод addClass, добавляющий еще один класс в строку с классами.

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

Пример использования желаемого нами метода:

<?php // Выведет <input class="eee bbb">: echo (new Tag('input'))->addClass('eee')->addClass('bbb')->open(); ?>

Было бы также удобно иметь метод removeClass для удаления заданного класса элемента.

Практическое применение этих методов вы еще увидите в следующих уроках.

Давайте реализуем описанные методы.

Добавление класса

Как вы знаете, наш класс Tag хранит атрибуты тега в свойстве $this->attrs.

Данное свойство представляет собой массив. В этом массиве может быть элемент с ключом class, содержащий CSS классы элемента. Элемента с таким ключом может, однако, и не быть.

Все зависит от того, был ли при создании тега вызван метод setAttr для установки атрибута class или нет.

Вот пример того, когда он был вызван:

<?php // Выведет <input class="eee bbb">: echo (new Tag('input'))->setAttr('class', 'eee bbb')->open(); ?>

А вот пример того, когда он не был вызван:

<?php // Выведет <input id="test">: echo (new Tag('input'))->setAttr('id', 'test')->open(); ?>

В реализации нашего метода addClass нужно будет учесть оба варианта.

Получается, что если у элемента не заданы CSS классы, то вызов метода addClass должен просто создавать в массиве $this->attrs новый элемент с ключом class и записывать в него переданный класс:

<?php public function addClass($className) { // Если ключа class нет в массиве $this->attrs: if (!isset($this->attrs['class'])) { $this->attrs['class'] = $className; // запишем наш CSS класс } return $this; // возвращаем $this для работы цепочки } ?>

Обратите внимание на то, что параметр метода называется $className, а не $class, так как слово class является зарезервированным в PHP и его нельзя использовать в качестве имени переменной.

Давайте теперь рассмотрим второй вариант, когда в $this->attrs['class'] уже есть один или несколько классов.

Как уже упоминалось выше, эти классы были добавлены ранее с помощью метода setAttr. Эти классы также могли быть добавлены с помощью вызова метода (или цепочки методов) addClass.

Способ добавления, в общем-то, не имеет никакого значения, главное, что, если классы есть, то они хранятся в виде строки, разделенные пробелами. Либо, если там один класс, то в $this->attrs['class'] просто хранится его имя, без пробелов.

Пусть в $this->attrs['class'] хранится несколько классов. В этом случае будет удобнее работать не со строкой с пробелами, а с массивом CSS классов. Для этого можно просто разбить нашу строку в массив с помощью функции explode:

<?php public function addClass($className) { if (isset($this->attrs['class'])) { // Получаем массив классов: $classNames = explode(' ', $this->attrs['class']); } return $this; } ?>

Затем необходимо проверить отсутствие переданного класса в этом массиве классов. Это легко сделать с помощью функции in_array:

<?php public function addClass($className) { if (isset($this->attrs['class'])) { $classNames = explode(' ', $this->attrs['class']); // Если такого класса нет в массиве классов: if (!in_array($className, $classNames)) { // добавим новый класс } } return $this; } ?>

Если переданного класса нет в массиве классов, то добавим его к уже существующим классам. А если есть - то просто ничего не будем делать.

Давайте реализуем добавление класса:

<?php public function addClass($className) { if (isset($this->attrs['class'])) { $classNames = explode(' ', $this->attrs['class']); if (!in_array($className, $classNames)) { // Добавим новый класс в массив с классами: $classNames[] = $className; // Сольем массив в строку и запишем ее в $this->attrs['class']: $this->attrs['class'] = implode(' ', $classNames); } } return $this; } ?>

Рассмотрим теперь вариант, когда в $this->attrs['class'] хранится только один класс. На самом деле, реализованный выше код будет прекрасно работать и в этом случае: применение explode к строке без пробела просто вернет массив из одного элемента, представляющего собой эту строку.

Ну и далее все наши манипуляции будут работать также.

Давайте соберем весь наш код вместе:

<?php public function addClass($className) { if (isset($this->attrs['class'])) { $classNames = explode(' ', $this->attrs['class']); if (!in_array($className, $classNames)) { $classNames[] = $className; $this->attrs['class'] = implode(' ', $classNames); } } else { $this->attrs['class'] = $className; } return $this; } ?>

Самостоятельно реализуйте описанный метод и добавьте его в ваш класс Tag.

Проверьте работу созданного метода, используя приведенные ниже примеры:

<?php // Выведет <input class="eee">: echo (new Tag('input'))->addClass('eee')->open(); ?>
<?php // Выведет <input class="eee bbb">: echo (new Tag('input'))->addClass('eee')->addClass('bbb')->open(); ?>
<?php // Выведет <input class="eee bbb kkk">: echo (new Tag('input')) ->setAttr('class', 'eee bbb') ->addClass('kkk')->open(); ?>
<?php // Выведет <input class="eee bbb">: echo (new Tag('input')) ->setAttr('class', 'eee bbb') ->addClass('eee') // такой класс уже есть и не добавится ->open(); ?>
<?php // Выведет <input class="eee bbb">: echo (new Tag('input')) ->addClass('eee') ->addClass('bbb') ->addClass('eee') // такой класс уже есть и не добавится ->open(); ?>

Удаление класса

Давайте теперь реализуем удаление CSS класса.

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

<?php private function removeElem($elem, $arr) { $key = array_search($elem, $arr); // находим ключ элемента по его тексту array_splice($arr, $key, 1); // удаляем элемент return $arr; // возвращаем измененный массив } ?>

Используя метод removeElem мы теперь можем реализовать метод removeClass для удаления CSS классов. Реализуем:

<?php public function removeClass($className) { if (isset($this->attrs['class'])) { $classNames = explode(' ', $this->attrs['class']); if (in_array($className, $classNames)) { $classNames = $this->removeElem($className, $classNames); $this->attrs['class'] = implode(' ', $classNames); } } return $this; } ?>

Самостоятельно реализуйте описанный метод и добавьте его в ваш класс Tag. Проверьте его работу, например, так:

<?php echo (new Tag('input')) ->setAttr('class', 'eee zzz kkk') // добавим 3 класса ->removeClass('zzz') // удалим класс 'zzz' ->open(); // выведет <input class="eee kkk"> ?>