# CSS классы в классе Tag

Пусть у нас дан вот такой инпут с атрибутом `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"> ?>`
←→
↑