Completed
Push — master ( a17ead...35004c )
by Kevin
02:36
created

Link::doClean()   D

Complexity

Conditions 9
Paths 12

Size

Total Lines 41
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 3
Bugs 0 Features 2
Metric Value
c 3
b 0
f 2
dl 0
loc 41
ccs 0
cts 29
cp 0
rs 4.909
cc 9
eloc 19
nc 12
nop 1
crap 90
1
<?php
2
3
namespace Groundskeeper\Tokens\Elements;
4
5
use Groundskeeper\Tokens\Element;
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
    protected function getAllowedAttributes()
13
    {
14
        $linkAllowedAttributes = array(
15
            '/^href$/i' => Element::ATTR_URI,
16
            '/^crossorigin$/i' => Element::ATTR_CS_STRING,
17
            '/^rel$/i' => Element::ATTR_CI_SSENUM . '("alternate","author","help","icon","license","next","pingback","prefetch","prev","search","stylesheet")',
18
            '/^media$/i' => Element::ATTR_CI_STRING,
19
            '/^hreflang$/i' => Element::ATTR_CS_STRING,
20
            '/^type$/i' => Element::ATTR_CI_STRING,
21
            '/^sizes$/i' => Element::ATTR_CI_STRING
22
        );
23
24
        return array_merge(
25
            $linkAllowedAttributes,
26
            parent::getAllowedAttributes()
27
        );
28
    }
29
30
    protected function doClean(LoggerInterface $logger)
31
    {
32
        // Must have "href" attribute.
33
        if (!$this->hasAttribute('href')) {
34
            $logger->debug('Element "link" requires "href" attribute.');
35
36
            return false;
37
        }
38
39
        // Must have either "rel" or "itemprop" attribute, but not both.
40
        $attrCount = 0;
41
        foreach ($this->attributes as $key => $value) {
42
            if ($key == 'rel' || $key == 'itemprop') {
43
                $attrCount++;
44
            }
45
46
            if ($attrCount > 1) {
47
                // If both, then we don't know which one should be kept,
48
                // so we recommend to delete the entire element.
49
                $logger->debug('Element "link" requires either "rel" or "itemprop" attribute, but not both.');
50
51
                return false;
52
            }
53
        }
54
55
        if ($attrCount == 0) {
56
            $logger->debug('Element "link" requires either "rel" or "itemprop" attribute.');
57
58
            return false;
59
        }
60
61
        // If inside "body" element, then we check if allowed.
62
        $body = new Body($this->configuration, 'body');
63
        if ($this->hasAncestor($body) && !$this->isAllowedInBody()) {
64
            $logger->debug('Element "link" does not have the correct attributes to be allowed inside the "body" element.');
65
66
            return false;
67
        }
68
69
        return true;
70
    }
71
72
    /**
73
     * Is this element allowed inside a body element?
74
     *
75
     * https://html.spec.whatwg.org/multipage/semantics.html#allowed-in-the-body
76
     *
77
     * @return boolean True if allowed.
78
     */
79
    public function isAllowedInBody()
80
    {
81
        if ($this->hasAttribute('itemprop')) {
82
            return true;
83
        }
84
85
        if ($this->hasAttribute('rel') &&
86
            ($this->attributes['rel'] == 'pingback' ||
87
             $this->attributes['rel'] == 'prefetch' ||
88
             $this->attributes['rel'] == 'stylesheet')) {
89
            return true;
90
        }
91
92
        return false;
93
    }
94
}
95