StylesheetParser   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 143
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
wmc 18
lcom 1
cbo 0
dl 0
loc 143
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 2
A getDocument() 0 4 1
A setDocument() 0 6 1
A extract() 0 21 4
A getStyleTags() 0 11 2
A getStyleTagContent() 0 9 3
A isStyleMediaAllowed() 0 11 3
A isStyleTypeAllowed() 0 6 2
1
<?php namespace Luminaire\Premailer\Parser;
2
3
/**
4
 * Created by Sublime Text 3
5
 *
6
 * @user     Kevin Tanjung
7
 * @website  http://kevintanjung.github.io
8
 * @email    [email protected]
9
 * @date     03/08/2016
10
 * @time     13:58
11
 */
12
13
use DOMDocument;
14
use DOMElement;
15
use RuntimeException;
16
17
/**
18
 * The "CSS Stylesheet Parser" class
19
 *
20
 * @package  \Luminaire\Premailer\Parser
21
 */
22
class StylesheetParser
23
{
24
25
    /**
26
     * The DOM Document instance
27
     *
28
     * @var \DOMDocument
29
     */
30
    protected $document;
31
32
    /**
33
     * Create a new instance of Style Sheet Extractor
34
     *
35
     * @param  \DOMDocument|null  $document
36
     */
37
    public function __construct(DOMDocument $document = null)
38
    {
39
        if ($document)
40
        {
41
            $this->setDocument($document);
42
        }
43
    }
44
45
    /**
46
     * Get the DOM Document instance
47
     *
48
     * @return \DOMDocument|null
49
     */
50
    public function getDocument()
51
    {
52
        return $this->document;
53
    }
54
55
    /**
56
     * Set the DOM Document instance
57
     *
58
     * @param  \DOMDocument  $document
59
     * @return $this
60
     */
61
    public function setDocument(DOMDocument $document)
62
    {
63
        $this->document = $document;
64
65
        return $this;
66
    }
67
68
    /**
69
     * Get all CSS in the mail template
70
     *
71
     * @return string
72
     *
73
     * @throws \RuntimeException
74
     */
75
    public function extract()
76
    {
77
        if ( ! $this->document)
78
        {
79
            throw new RuntimeException('There are no [DOMDocument] instance to work with. Use the [setDocument] method to pass an instance of the [DOMDocument].');
80
        }
81
82
        $stylesheet = "";
83
84
        foreach ($this->getStyleTags($this->document) as $node)
85
        {
86
            if ($content = $this->getStyleTagContent($node))
87
            {
88
                $stylesheet .= $content . "\r\n";
89
            }
90
91
            $node->parentNode->removeChild($node);
92
        }
93
94
        return $stylesheet;
95
    }
96
97
    /**
98
     * Get all DOM element that has "style" attribute
99
     *
100
     * @param  \DOMDocument  $doc
101
     * @return array
102
     */
103
    protected function getStyleTags(DOMDocument $doc)
104
    {
105
        $nodes = [];
106
107
        foreach ($doc->getElementsByTagName('style') as $element)
108
        {
109
            $nodes[] = $element;
110
        }
111
112
        return $nodes;
113
    }
114
115
    /**
116
     * Get the HTML <style> tag CSS content
117
     *
118
     * @param  \DOMElement  $node
119
     * @return string|null
120
     */
121
    protected function getStyleTagContent(DOMElement $node)
122
    {
123
        if ( ! $this->isStyleTypeAllowed($node) || ! $this->isStyleMediaAllowed($node))
124
        {
125
            return null;
126
        }
127
128
        return (string) $node->nodeValue;
129
    }
130
131
    /**
132
     * Check if the HTML <style> tag has no [media] attribute or if it has a
133
     * [media] attribute, then it must either have a value of "all" or "screen".
134
     *
135
     * @param  \DOMElement  $style_node
136
     * @return bool
137
     */
138
    private function isStyleMediaAllowed(DOMElement $style_node)
139
    {
140
        $media = $style_node->attributes->getNamedItem('media');
141
142
        if (is_null($media)) return true;
143
144
        $media       = str_replace(' ', '', (string) $media->nodeValue);
145
        $media_types = explode(',', $media);
146
147
        return in_array('all', $media_types) || in_array('screen', $media_types);
148
    }
149
150
    /**
151
     * Check if the HTML <style> tag has the default [type] attribute or the value
152
     * of the [type] attribute is set to "text/css".
153
     *
154
     * @param  \DOMElement  $style_node
155
     * @return bool
156
     */
157
    private function isStyleTypeAllowed(DOMElement $style_node)
158
    {
159
        $type = $style_node->attributes->getNamedItem('type');
160
161
        return is_null($type) || (string) $type->nodeValue == 'text/css';
162
    }
163
164
}
165