Completed
Push — master ( a57c7d...d1bd01 )
by Joschi
02:32
created

PropertyProcessorTrait::setPropertyCache()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 2
crap 1
1
<?php
2
3
/**
4
 * rdfa-lite-microdata
5
 *
6
 * @category Jkphl
7
 * @package Jkphl\RdfaLiteMicrodata
8
 * @subpackage Jkphl\RdfaLiteMicrodata\Infrastructure
9
 * @author Joschi Kuphal <[email protected]> / @jkphl
10
 * @copyright Copyright © 2017 Joschi Kuphal <[email protected]> / @jkphl
11
 * @license http://opensource.org/licenses/MIT The MIT License (MIT)
12
 */
13
14
/***********************************************************************************
15
 *  The MIT License (MIT)
16
 *
17
 *  Copyright © 2017 Joschi Kuphal <[email protected]> / @jkphl
18
 *
19
 *  Permission is hereby granted, free of charge, to any person obtaining a copy of
20
 *  this software and associated documentation files (the "Software"), to deal in
21
 *  the Software without restriction, including without limitation the rights to
22
 *  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
23
 *  the Software, and to permit persons to whom the Software is furnished to do so,
24
 *  subject to the following conditions:
25
 *
26
 *  The above copyright notice and this permission notice shall be included in all
27
 *  copies or substantial portions of the Software.
28
 *
29
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
31
 *  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
32
 *  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
33
 *  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34
 *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35
 ***********************************************************************************/
36
37
namespace Jkphl\RdfaLiteMicrodata\Infrastructure\Parser;
38
39
use Jkphl\RdfaLiteMicrodata\Application\Context\ContextInterface;
40
use Jkphl\RdfaLiteMicrodata\Domain\Property\Property;
41
use Jkphl\RdfaLiteMicrodata\Domain\Thing\ThingInterface;
42
use Jkphl\RdfaLiteMicrodata\Domain\Vocabulary\VocabularyInterface;
43
44
/**
45
 * Property processor methods
46
 *
47
 * @package Jkphl\RdfaLiteMicrodata
48
 * @subpackage Jkphl\RdfaLiteMicrodata\Infrastructure
49
 */
50
trait PropertyProcessorTrait
51
{
52
    /**
53
     * Create a property by prefix and name
54
     *
55
     * @param string $prefix Property prefix
56
     * @param string $name Property name
57
     * @param \DOMElement $element DOM element
58
     * @param ContextInterface $context Inherited Context
59
     * @param boolean $last Last property
60
     * @return ContextInterface Local context for this element
61
     */
62 8
    protected function processPropertyPrefixName($prefix, $name, \DOMElement $element, ContextInterface $context, $last)
63
    {
64 8
        $vocabulary = $this->getVocabulary($prefix, $context);
0 ignored issues
show
Bug introduced by
It seems like getVocabulary() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
65 8
        if ($vocabulary instanceof VocabularyInterface) {
66 8
            $context = $this->addProperty($element, $context, $name, $vocabulary, $last);
67 7
        }
68
69 7
        return $context;
70
    }
71
72
    /**
73
     * Add a single property
74
     *
75
     * @param \DOMElement $element DOM element
76
     * @param ContextInterface $context Inherited Context
77
     * @param string $name Property name
78
     * @param VocabularyInterface $vocabulary Property vocabulary
79
     * @param boolean $last Last property
80
     * @return ContextInterface Local context for this element
81
     */
82 8
    protected function addProperty(
83
        \DOMElement $element,
84 1
        ContextInterface $context,
85
        $name,
86
        VocabularyInterface $vocabulary,
87
        $last
88
    ) {
89 8
        $resourceId = $this->getResourceId($element);
0 ignored issues
show
Bug introduced by
It seems like getResourceId() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
90
91
        // Get the property value
92 8
        $propertyValue = $this->getPropertyValue($element, $context);
93 8
        $property = new Property($name, $vocabulary, $propertyValue, $resourceId);
94
95
        // Add the property to the current parent thing
96 7
        $context->getParentThing()->addProperty($property);
97
98 7
        return $this->addPropertyChild($propertyValue, $context, $last);
99
    }
100
101
    /**
102
     * Return a property value (type and tag name dependent)
103
     *
104
     * @param \DOMElement $element DOM element
105
     * @param ContextInterface $context Context
106
     * @return ThingInterface|string Property value
107
     */
108 8
    protected function getPropertyValue(\DOMElement $element, ContextInterface $context)
109
    {
110 8
        $value = $this->getPropertyCache($element);
111 8
        if ($value !== null) {
112 1
            return $value;
113
        }
114
115 8
        $propertyChild = $this->getPropertyChildValue($element, $context);
116 8
        if ($propertyChild instanceof ThingInterface) {
117 4
            return $this->setPropertyCache($element, $propertyChild);
118
        }
119
120
        // Return a string property value
121 8
        return $this->setPropertyCache($element, $this->getPropertyStringValue($element));
122
    }
123
124
    /**
125
     * Return a cached property value (if available)
126
     *
127
     * @param \DOMElement $element Element
128
     * @return mixed|null Property value
129
     */
130 8
    protected function getPropertyCache(\DOMElement $element)
131
    {
132 8
        $elementHash = spl_object_hash($element);
133 8
        return isset(self::$propertyCache[$elementHash]) ? self::$propertyCache[$elementHash] : null;
134
    }
135
136
    /**
137
     * Return a property child value
138
     *
139
     * @param \DOMElement $element DOM element
140
     * @param ContextInterface $context Context
141
     * @return ThingInterface|null Property child value
142
     */
143
    abstract protected function getPropertyChildValue(\DOMElement $element, ContextInterface $context);
144
145
    /**
146
     * Cache a property value
147
     *
148
     * @param \DOMElement $element DOM element
149
     * @param mixed $value Value
150
     * @return mixed $value Value
151
     */
152 8
    protected function setPropertyCache(\DOMElement $element, $value)
153
    {
154 8
        return self::$propertyCache[spl_object_hash($element)] = $value;
155
    }
156
157
    /**
158
     * Return a property value (type and tag name dependent)
159
     *
160
     * @param \DOMElement $element DOM element
161
     * @return string Property value
162
     */
163 8
    protected function getPropertyStringValue(\DOMElement $element)
164
    {
165
        // If HTML mode is active
166 8
        if ($this->html) {
0 ignored issues
show
Bug introduced by
The property html does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
167 7
            $value = $this->getPropertyHtmlValue($element);
168 7
            if ($value !== null) {
169 5
                return $value;
170
            }
171 7
        }
172
173
        // Return the text content
174 8
        return $element->textContent;
175
    }
176
177
    /**
178
     * Return a property value (type and tag name dependent)
179
     *
180
     * @param \DOMElement $element DOM element
181
     * @return string|null Property value
182
     */
183 7
    protected function getPropertyHtmlValue(\DOMElement $element)
184
    {
185 7
        $tagName = strtoupper($element->tagName);
186
187
        // Map to an attribute (if applicable)
188 7
        if (array_key_exists($tagName, self::$tagNameAttributes)) {
189 5
            $value = strval($element->getAttribute(self::$tagNameAttributes[$tagName]));
190 5
            if (($tagName != 'TIME') || strlen($value)) {
191 5
                return $value;
192
            }
193
        }
194
195 7
        return null;
196
    }
197
198
    /**
199
     * Add a property child
200
     *
201
     * @param string|ThingInterface Property value
202
     * @param ContextInterface $context Inherited Context
203
     * @param boolean $last Last property
204
     * @return ContextInterface Local context for this element
205
     */
206 7
    protected function addPropertyChild($propertyValue, ContextInterface $context, $last)
207
    {
208
        // If the property value is a thing and this is the element's last property
209 7
        if (($propertyValue instanceof ThingInterface) && $last) {
210
            // Set the thing as parent thing for nested iterations
211 4
            $context = $context->setParentThing($propertyValue);
212 4
        }
213
214 7
        return $context;
215
    }
216
217
    /**
218
     * Create a property
219
     *
220
     * @param \DOMElement $element DOM element
221
     * @param ContextInterface $context Inherited Context
222
     * @return ContextInterface Local context for this element
223
     */
224
    abstract protected function processProperty(\DOMElement $element, ContextInterface $context);
225
}
226