Passed
Push — main ( b967d0...137e5a )
by Sammy
07:06
created

Element::__set()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 6
c 0
b 0
f 0
nc 6
nop 2
dl 0
loc 10
rs 9.6111
1
<?php
2
3
declare(strict_types=1);
4
5
namespace HexMakina\Marker;
6
7
/**
8
 * The Element class provides a simple and useful implementation for creating,  and generating valid HTML elements using PHP
9
 * The __toString() method of the Element class generates the HTML code for the element based on its tag, attributes, and content
10
 *
11
 * Additionally, the Element class provides a static shorthand syntax, using __callStatic() matching the name of the HTML Element to create
12
 *
13
 * The first argument is the content, the second are the attributes
14
 *
15
 * $abbr = Element::abbr('RTFM', ['title' => 'read the file manual']);
16
 * $p = Element:p('You reading this means you know about '.$abbr);
17
 * echo $p; // <p>You reading this means you know about <abbr title="read the file manual">RTFM</abbr></p>
18
 *
19
 * ::span('inner text', ['class' => 'd-block'])
20
 * ::p('lorem ipsum')
21
 * ::img(null, ['src' => 'path/to/jpeg.png', alt='hyper descriptive', 'width' => 100, 'height'=>100])
22
 * ::a('click here', ['href' => 'url/to/destination', 'class' => 'nav-link'])
23
 * ::a('anchor title', ['name' => 'anchor_name'])
24
 *
25
 * Regarding the attributes array, the keys represent the attribute names, and the values represent the attribute values.
26
 * If an attribute key is an integer, the corresponding attribute name and value are treated as a boolean attribute.
27
 *
28
 *
29
 * Example usage:
30
 *
31
 * ```
32
 * $element = new Element('section', 'Hello World!', [
33
 *     'id' => 'publication',
34
 *     'class' => 'container',
35
 *     'data-toggle' => 'modal',
36
 *     'data-target' => '#myModal',
37
 * ]);
38
 *
39
 * <section id="publication" class="container" data-toggle="modal" "data-target"="#myModal">Hello World!</section>
40
 * ```
41
 *
42
 * Or, with void element and boolean attributes:
43
 *
44
 * $element = new Element('input', null, [
45
 *      'type' => 'checkbox',
46
 *      'checked',
47
 *      'disabled',
48
 *      'class' => 'checkbutton'
49
 * ]);
50
 *
51
 * <input type="checkbox" checked disabled class="checkbutton"/>
52
 *
53
 */
54
55
class Element
56
{
57
    protected string $tag;
58
    protected ?string $content;
59
    protected array $attributes = [];
60
61
    // shorthand syntax for creating elements
62
    public static function __callStatic(string $tag, array $arguments): Element
63
    {
64
        return new Element($tag, $arguments[0] ?? null, $arguments[1] ?? []);
65
    }
66
67
    /**
68
     * Creates a new Element instance.
69
     *
70
     * @param string $tag The HTML tag for the element.
71
     * @param string|null $content The content of the element (optional).
72
     * @param mixed[] $attributes An array of attributes for the element (optional).
73
     * 
74
     */
75
    public function __construct(string $tag, string $content = null, array $attributes = [])
76
    {
77
        $this->tag = $tag;
78
        $this->content = $content;
79
80
        foreach ($attributes as $name => $value) {
81
            if(is_int($name)) {
82
                $name = $value;
83
            }
84
85
            $this->$name = $value;
86
        }
87
    }
88
89
    /**
90
     * Magic method to set element attributes.
91
     *
92
     * If the value is an array, it is imploded using a space character.
93
     * If the value is null or empty, the attribute is removed.
94
     * If the attribute name equals it's value, the attribute is treated as
95
     * a boolean attribute (checked, disabled, etc.) and not formatted
96
     *
97
     * @param string $name The name of the attribute.
98
     * @param mixed $value The value of the attribute.
99
     * @return void
100
     */
101
    public function __set(string $name, $value)
102
    {
103
        if (is_array($value)) {
104
            $value = implode(' ', $value);
105
        }
106
107
        if ($value === null || $value === '') {
108
            unset($this->attributes[$name]);
109
        } else {
110
            $this->attributes[$name] = ($name === $value) ? $value : sprintf('%s="%s"', $name, $value);
111
        }
112
    }
113
114
    /**
115
     * This method returns the string representation of the Element object by formatting the tag, attributes, and content
116
     * of the element based on whether it is a void element or not. If the element is a void element, it returns the tag and
117
     * attributes only. Otherwise, it returns the tag, attributes, content, and closing tag.
118
     *
119
     * @return string The string representation of the Element object.
120
     */
121
    public function __toString(): string
122
    {
123
        $attributes = empty($this->attributes) ? '' : ' '.implode(' ', $this->attributes);
124
125
        return is_null($this->content)
126
            ? sprintf('<%s%s/>', $this->tag, $attributes)
127
            : sprintf('<%s%s>%s</%s>', $this->tag, $attributes, $this->content, $this->tag);
128
    }
129
}
130