Link   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 86
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 16
lcom 1
cbo 3
dl 0
loc 86
ccs 34
cts 34
cp 1
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
B isAllowedInBody() 0 15 6
A getAllowedAttributes() 0 17 1
D removeInvalidSelf() 0 42 9
1
<?php
2
3
namespace Groundskeeper\Tokens\Elements;
4
5
use Groundskeeper\Tokens\Attribute;
6
use Groundskeeper\Tokens\ElementTypes\ClosedElement;
7
use Groundskeeper\Tokens\ElementTypes\MetadataContent;
8
use Psr\Log\LoggerInterface;
9
10
class Link extends ClosedElement implements MetadataContent
11
{
12 6
    protected function getAllowedAttributes()
13
    {
14
        $linkAllowedAttributes = array(
15 6
            '/^href$/i' => Attribute::URI,
16
            '/^crossorigin$/i' => Attribute::CS_STRING,
17
            '/^rel$/i' => Attribute::CI_SSENUM . '("alternate","author","help","icon","license","next","pingback","prefetch","prev","search","stylesheet")',
18
            '/^media$/i' => Attribute::CI_STRING,
19
            '/^hreflang$/i' => Attribute::CS_STRING,
20
            '/^type$/i' => Attribute::CI_STRING,
21
            '/^sizes$/i' => Attribute::CI_STRING
22
        );
23
24 6
        return array_merge(
25 6
            $linkAllowedAttributes,
26 6
            parent::getAllowedAttributes()
27
        );
28
    }
29
30 6
    protected function removeInvalidSelf(LoggerInterface $logger) : bool
31
    {
32
        // Must have "href" attribute.
33 6
        if (!$this->hasAttribute('href')) {
34 1
            $logger->debug('Removing ' . $this . '. Requires "href" attribute.');
35
36 1
            return true;
37
        }
38
39
        // Must have either "rel" or "itemprop" attribute, but not both.
40 5
        $attrCount = 0;
41 5
        foreach ($this->attributes as $attribute) {
42 5
            if ($attribute->getName() === 'rel' ||
43 5
                $attribute->getName() === 'itemprop') {
44 4
                ++$attrCount;
45
            }
46
47 5
            if ($attrCount > 1) {
48
                // If both, then we don't know which one should be kept,
49
                // so we recommend to delete the entire element.
50 1
                $logger->debug('Removing ' . $this . '. Requires either "rel" or "itemprop" attribute, but not both.');
51
52 5
                return true;
53
            }
54
        }
55
56 4
        if ($attrCount == 0) {
57 1
            $logger->debug('Removing ' . $this . '. Requires either "rel" or "itemprop" attribute.');
58
59 1
            return true;
60
        }
61
62
        // If inside "body" element, then we check if allowed.
63 3
        $body = new Body($this->configuration, 0, 0, 'body');
64 3
        if ($this->hasAncestor($body) && !$this->isAllowedInBody()) {
65 1
            $logger->debug('Removing ' . $this . '. Does not have the correct attributes to be allowed inside the "body" element.');
66
67 1
            return true;
68
        }
69
70 2
        return false;
71
    }
72
73
    /**
74
     * Is this element allowed inside a body element?
75
     *
76
     * https://html.spec.whatwg.org/multipage/semantics.html#allowed-in-the-body
77
     *
78
     * @return bool True if allowed.
79
     */
80 2
    public function isAllowedInBody() : bool
81
    {
82 2
        if ($this->hasAttribute('itemprop')) {
83 1
            return true;
84
        }
85
86 2
        if ($this->hasAttribute('rel') &&
87 2
            ($this->attributes['rel']->getValue() === 'pingback' ||
88 2
             $this->attributes['rel']->getValue() === 'prefetch' ||
89 2
             $this->attributes['rel']->getValue() === 'stylesheet')) {
90 1
            return true;
91
        }
92
93 1
        return false;
94
    }
95
}
96