1: <?php
2: namespace Tokamak\Dom;
3:
4: use DOMDocument;
5: use Closure;
6:
7: /**
8: * Class Element
9: * @package Tokamak\Dom
10: * A Node implementation representing a standard DOM element.
11: */
12: class Element extends Node
13: {
14:
15: /**
16: * @var string The element name ('div', 'a', 'body', etc.)
17: */
18: protected $name;
19:
20: /**
21: * @var array Associative array of the element's attributes and their values.
22: * For "class", the value can also be an array of class names.
23: */
24: protected $attributes;
25:
26: /**
27: * @var string The text content of the element.
28: */
29: protected $content;
30:
31: /**
32: * @var \DOMElement The underlying DOMElement object
33: */
34: protected $node;
35:
36: /**
37: * Construct a DOM element and add it to the "domNodes" queue to be appended to the parent
38: * @param DOMDocument $dom The underlying DOMDocument
39: * @param string $name The element name ('div', 'a', 'body', etc.)
40: * @param array $attributes Associative array of the element's attributes and their values.
41: * For "class", the value can also be an array of class names.
42: * @param string $content The text content of the element.
43: */
44: public function __construct(DOMDocument $dom, $name, array $attributes = null, $content = '')
45: {
46: $this->dom = $dom;
47: $this->name = $name;
48: $this->content = $content;
49: $this->attributes = $attributes;
50:
51: // build the DOM subtree of child elements and components
52: $this->render();
53: }
54:
55: /**
56: * Builds the \DOMElement instance and adds it to the domNodes queue
57: */
58: protected function render()
59: {
60: $element = $this->dom->createElement($this->name, $this->content);
61:
62: if (!empty($this->attributes)) {
63: foreach ($this->attributes as $attribute => $value) {
64: if (is_array($value)) {
65: if ($attribute !== "class") {
66: throw new \InvalidArgumentException('Attributes except for "class" must be scalar values.');
67: } else {
68: $value = implode(" ", $value);
69: }
70: }
71: $element->setAttribute($attribute, $value);
72: }
73: }
74:
75: $this->addDomNode($element);
76:
77: $this->node = $element;
78: }
79:
80: /**
81: * Append another node (element or component) to this element.
82: * Returns the child element for method chaining.
83: * @param Node $child
84: * @return Node The child element, returned for method chaining.
85: */
86: public function append(Node $child)
87: {
88: while ($child->hasDomNodes()) {
89: $this->node->appendChild($child->getDomNode());
90: }
91: // Set the parent DOMNode of the component,
92: // so that any remaining fluent method calls
93: // can append directly to the node.
94: if($child instanceof Component){
95: $child->setParentNode($this->node);
96: }
97:
98: return $child;
99: }
100: }