Completed
Push — master ( ffd1f4...e0c1a2 )
by Edgar
04:28
created

SVGElement::getIdFromUrl()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 5
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
namespace nstdio\svg;
3
4
use nstdio\svg\container\ContainerInterface;
5
use nstdio\svg\container\SVG;
6
use nstdio\svg\traits\ChildTrait;
7
use nstdio\svg\traits\ElementTrait;
8
use nstdio\svg\util\Identifier;
9
use nstdio\svg\util\Inflector;
10
use nstdio\svg\util\KeyValueWriter;
11
12
/**
13
 * Class SVGElement
14
 *
15
 * @property string $id
16
 * @property string $fill The fill color.
17
 *
18
 * @package nstdio\svg
19
 * @author  Edgar Asatryan <[email protected]>
20
 */
21
abstract class SVGElement implements ContainerInterface, ElementFactoryInterface
22
{
23
    use ElementTrait, ChildTrait;
24
25
    private static $notConvertable = ['diffuseConstant', 'pointsAtX', 'pointsAtY', 'pointsAtZ', 'limitingConeAngle', 'tableValues', 'filterUnits', 'gradientUnits', 'viewBox', 'repeatCount', 'attributeName', 'attributeType', 'stdDeviation'];
26
27
    /**
28
     * @var XMLDocumentInterface | ElementInterface | ElementFactoryInterface | ContainerInterface
29
     */
30
    protected $root;
31
32
    /**
33
     * @var XMLDocumentInterface | ElementInterface | ElementFactoryInterface | ContainerInterface
34
     */
35
    protected $element;
36
37
    public function __construct(ElementInterface $parent)
38
    {
39
        $this->child = new ElementStorage();
40
        $this->root = $parent;
0 ignored issues
show
Documentation Bug introduced by
It seems like $parent of type object<nstdio\svg\ElementInterface> is incompatible with the declared type object<nstdio\svg\XMLDocumentInterface> of property $root.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
41
        $this->element = $this->createElement($this->getName());
42
        $this->root->append($this);
43
    }
44
45
    public function createElement($name, $value = null, $attributes = [])
46
    {
47
        return $this->root->createElement($name, $value, $attributes);
0 ignored issues
show
Unused Code introduced by
The call to XMLDocumentInterface::createElement() has too many arguments starting with $attributes.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
48
    }
49
50
    abstract public function getName();
51
52
    final public function getRoot()
53
    {
54
        return $this->root;
55
    }
56
57
    final public function getElement()
58
    {
59
        return $this->element;
60
    }
61
62
    public function allAttributes(array $except = [])
63
    {
64
        return $this->element->attributes($except);
65
    }
66
67
    public function __get($name)
68
    {
69
        if ($name === 'filterUrl' || $name === 'fillUrl') {
70
            return $this->getIdFromUrl($name);
71
        }
72
73
        $name = Inflector::camel2dash($name);
74
        $value = $this->element->getAttribute($name);
75
        if ($value === '') {
76
            $value = $this->getXLinkAttribute($name);
77
        }
78
79
        return $value === '' ? null : $value;
80
    }
81
82
    public function __set($name, $value)
83
    {
84
        if ($name === 'id' && $value === null) {
85
            $this->element->setAttribute($name, Identifier::random('__' . $this->getName(), 5));
86
87
            return;
88
        }
89
90
        if ($value === null || $value === false || $value === '') {
91
            return;
92
        }
93
94
        if ($name === 'filterUrl' || $name === 'fillUrl') {
95
            $this->handleUrlPostfixAttribute($name, $value);
96
        }
97
98
        $name = $this->convertAttributeName($name);
99
        $this->element->setAttribute($name, $value);
100
    }
101
102
    public function getXLinkAttribute($name)
103
    {
104
        return $this->element->getAttributeNS('xlink', $name);
105
    }
106
107
    /**
108
     * @param $name
109
     *
110
     * @return string
111
     */
112
    private function convertAttributeName($name)
113
    {
114
        return !in_array($name, self::$notConvertable) ? Inflector::camel2dash($name) : $name;
115
    }
116
117
    /**
118
     * @inheritdoc
119
     */
120
    public function apply(array $assoc)
121
    {
122
        $filtered = [];
123
        foreach ($assoc as $attribute => $value) {
124
            $filtered[$this->convertAttributeName($attribute)] = $value;
125
        }
126
        KeyValueWriter::apply($this->element, $filtered);
127
128
        return $this;
129
    }
130
131
    protected function setAttribute($name, $value, $xLink = false)
132
    {
133
        if ($xLink === true) {
134
            $this->element->setAttributeNS('xlink', $name, $value);
135
        } else {
136
            $this->element->setAttribute($name, $value);
137
        }
138
    }
139
140
    protected function selfRemove()
141
    {
142
        $this->getRoot()->removeChild($this);
0 ignored issues
show
Bug introduced by
The method removeChild() does not seem to exist on object<nstdio\svg\XMLDocumentInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
143
    }
144
145
    protected function getSVG()
146
    {
147
        if ($this->root instanceof SVG) {
148
            return $this->root;
149
        }
150
        $element = $this->root;
151
152
        do {
153
            $element = $element->getRoot();
154
        } while (!($element instanceof SVG));
155
156
        return $element;
157
    }
158
159
    /**
160
     * @param $attribute
161
     * @param $value
162
     */
163
    private function handleUrlPostfixAttribute(&$attribute, &$value)
164
    {
165
        $attribute = substr($attribute, 0, strrpos($attribute, 'U'));
166
        if (strpos($value, "url(#") !== 0) {
167
            $value = "url(#" . $value . ")";
168
        }
169
    }
170
171
    private function getIdFromUrl($attribute)
172
    {
173
        $attribute = substr($attribute, 0, strrpos($attribute, 'U'));
174
        return str_replace(['url(#', ')'], '', $this->element->getAttribute($attribute));
175
    }
176
}