@@ -73,7 +73,7 @@ |
||
73 | 73 | if ($transaction->ID()) { |
74 | 74 | $info['TXN_status'] = $transaction->status_ID(); |
75 | 75 | $info['TXN_reg_steps'] = $transaction->reg_steps(); |
76 | - $index = 'EE_Transaction: ' . $transaction->ID(); |
|
76 | + $index = 'EE_Transaction: '.$transaction->ID(); |
|
77 | 77 | EEH_Debug_Tools::log($class, $func, $line, $info, $display_request, $index); |
78 | 78 | } |
79 | 79 | } |
@@ -11,73 +11,73 @@ |
||
11 | 11 | */ |
12 | 12 | class EE_Processor_Base |
13 | 13 | { |
14 | - /** |
|
15 | - * Used to indicate whether current request is for an IPN or not. |
|
16 | - * |
|
17 | - * @var bool |
|
18 | - */ |
|
19 | - protected static $IPN = false; |
|
14 | + /** |
|
15 | + * Used to indicate whether current request is for an IPN or not. |
|
16 | + * |
|
17 | + * @var bool |
|
18 | + */ |
|
19 | + protected static $IPN = false; |
|
20 | 20 | |
21 | - /** |
|
22 | - * Used to indicate whether SPCO is being revisited by registrant or not. |
|
23 | - * |
|
24 | - * @var bool |
|
25 | - */ |
|
26 | - protected $_revisit = false; |
|
21 | + /** |
|
22 | + * Used to indicate whether SPCO is being revisited by registrant or not. |
|
23 | + * |
|
24 | + * @var bool |
|
25 | + */ |
|
26 | + protected $_revisit = false; |
|
27 | 27 | |
28 | 28 | |
29 | - /** |
|
30 | - * @param bool|int|string $IPN truthy/falsey value |
|
31 | - */ |
|
32 | - public static function set_IPN($IPN) |
|
33 | - { |
|
34 | - self::$IPN = filter_var($IPN, FILTER_VALIDATE_BOOLEAN); |
|
35 | - } |
|
29 | + /** |
|
30 | + * @param bool|int|string $IPN truthy/falsey value |
|
31 | + */ |
|
32 | + public static function set_IPN($IPN) |
|
33 | + { |
|
34 | + self::$IPN = filter_var($IPN, FILTER_VALIDATE_BOOLEAN); |
|
35 | + } |
|
36 | 36 | |
37 | 37 | |
38 | - /** |
|
39 | - * Allows external class (usually checkout) to set whether SPCO is being revisited by registrant or not. |
|
40 | - * |
|
41 | - * @param bool|int|string $revisit |
|
42 | - * @return void |
|
43 | - */ |
|
44 | - public function set_revisit($revisit = false) |
|
45 | - { |
|
46 | - $this->_revisit = filter_var($revisit, FILTER_VALIDATE_BOOLEAN); |
|
47 | - } |
|
38 | + /** |
|
39 | + * Allows external class (usually checkout) to set whether SPCO is being revisited by registrant or not. |
|
40 | + * |
|
41 | + * @param bool|int|string $revisit |
|
42 | + * @return void |
|
43 | + */ |
|
44 | + public function set_revisit($revisit = false) |
|
45 | + { |
|
46 | + $this->_revisit = filter_var($revisit, FILTER_VALIDATE_BOOLEAN); |
|
47 | + } |
|
48 | 48 | |
49 | 49 | |
50 | - /** |
|
51 | - * debug |
|
52 | - * |
|
53 | - * @param string $class |
|
54 | - * @param string $func |
|
55 | - * @param string $line |
|
56 | - * @param EE_Transaction|null $transaction |
|
57 | - * @param array $info |
|
58 | - * @param bool $display_request |
|
59 | - * @throws EE_Error |
|
60 | - * @throws ReflectionException |
|
61 | - */ |
|
62 | - protected function log( |
|
63 | - string $class = '', |
|
64 | - string $func = '', |
|
65 | - string $line = '', |
|
66 | - ?EE_Transaction $transaction = null, |
|
67 | - array $info = [], |
|
68 | - bool $display_request = false |
|
69 | - ) { |
|
70 | - if (WP_DEBUG && false) { |
|
71 | - if ($transaction instanceof EE_Transaction) { |
|
72 | - // don't serialize objects |
|
73 | - $info = EEH_Debug_Tools::strip_objects($info); |
|
74 | - if ($transaction->ID()) { |
|
75 | - $info['TXN_status'] = $transaction->status_ID(); |
|
76 | - $info['TXN_reg_steps'] = $transaction->reg_steps(); |
|
77 | - $index = 'EE_Transaction: ' . $transaction->ID(); |
|
78 | - EEH_Debug_Tools::log($class, $func, $line, $info, $display_request, $index); |
|
79 | - } |
|
80 | - } |
|
81 | - } |
|
82 | - } |
|
50 | + /** |
|
51 | + * debug |
|
52 | + * |
|
53 | + * @param string $class |
|
54 | + * @param string $func |
|
55 | + * @param string $line |
|
56 | + * @param EE_Transaction|null $transaction |
|
57 | + * @param array $info |
|
58 | + * @param bool $display_request |
|
59 | + * @throws EE_Error |
|
60 | + * @throws ReflectionException |
|
61 | + */ |
|
62 | + protected function log( |
|
63 | + string $class = '', |
|
64 | + string $func = '', |
|
65 | + string $line = '', |
|
66 | + ?EE_Transaction $transaction = null, |
|
67 | + array $info = [], |
|
68 | + bool $display_request = false |
|
69 | + ) { |
|
70 | + if (WP_DEBUG && false) { |
|
71 | + if ($transaction instanceof EE_Transaction) { |
|
72 | + // don't serialize objects |
|
73 | + $info = EEH_Debug_Tools::strip_objects($info); |
|
74 | + if ($transaction->ID()) { |
|
75 | + $info['TXN_status'] = $transaction->status_ID(); |
|
76 | + $info['TXN_reg_steps'] = $transaction->reg_steps(); |
|
77 | + $index = 'EE_Transaction: ' . $transaction->ID(); |
|
78 | + EEH_Debug_Tools::log($class, $func, $line, $info, $display_request, $index); |
|
79 | + } |
|
80 | + } |
|
81 | + } |
|
82 | + } |
|
83 | 83 | } |
@@ -11,230 +11,230 @@ |
||
11 | 11 | |
12 | 12 | class CssToInlineStyles |
13 | 13 | { |
14 | - private $cssConverter; |
|
15 | - |
|
16 | - public function __construct() |
|
17 | - { |
|
18 | - if (class_exists('Symfony\Component\CssSelector\CssSelectorConverter')) { |
|
19 | - $this->cssConverter = new CssSelectorConverter(); |
|
20 | - } |
|
21 | - } |
|
22 | - |
|
23 | - /** |
|
24 | - * Will inline the $css into the given $html |
|
25 | - * |
|
26 | - * Remark: if the html contains <style>-tags those will be used, the rules |
|
27 | - * in $css will be appended. |
|
28 | - * |
|
29 | - * @param string $html |
|
30 | - * @param string $css |
|
31 | - * |
|
32 | - * @return string |
|
33 | - */ |
|
34 | - public function convert($html, $css = null) |
|
35 | - { |
|
36 | - $document = $this->createDomDocumentFromHtml($html); |
|
37 | - $processor = new Processor(); |
|
38 | - |
|
39 | - // get all styles from the style-tags |
|
40 | - $rules = $processor->getRules( |
|
41 | - $processor->getCssFromStyleTags($html) |
|
42 | - ); |
|
43 | - |
|
44 | - if ($css !== null) { |
|
45 | - $rules = $processor->getRules($css, $rules); |
|
46 | - } |
|
47 | - |
|
48 | - $document = $this->inline($document, $rules); |
|
49 | - |
|
50 | - return $this->getHtmlFromDocument($document); |
|
51 | - } |
|
52 | - |
|
53 | - /** |
|
54 | - * Inline the given properties on an given DOMElement |
|
55 | - * |
|
56 | - * @param \DOMElement $element |
|
57 | - * @param Css\Property\Property[] $properties |
|
58 | - * |
|
59 | - * @return \DOMElement |
|
60 | - */ |
|
61 | - public function inlineCssOnElement(\DOMElement $element, array $properties) |
|
62 | - { |
|
63 | - if (empty($properties)) { |
|
64 | - return $element; |
|
65 | - } |
|
66 | - |
|
67 | - $cssProperties = array(); |
|
68 | - $inlineProperties = array(); |
|
69 | - |
|
70 | - foreach ($this->getInlineStyles($element) as $property) { |
|
71 | - $inlineProperties[$property->getName()] = $property; |
|
72 | - } |
|
73 | - |
|
74 | - foreach ($properties as $property) { |
|
75 | - if (!isset($inlineProperties[$property->getName()])) { |
|
76 | - $cssProperties[$property->getName()] = $property; |
|
77 | - } |
|
78 | - } |
|
79 | - |
|
80 | - $rules = array(); |
|
81 | - foreach (array_merge($cssProperties, $inlineProperties) as $property) { |
|
82 | - $rules[] = $property->toString(); |
|
83 | - } |
|
84 | - $element->setAttribute('style', implode(' ', $rules)); |
|
85 | - |
|
86 | - return $element; |
|
87 | - } |
|
88 | - |
|
89 | - /** |
|
90 | - * Get the current inline styles for a given DOMElement |
|
91 | - * |
|
92 | - * @param \DOMElement $element |
|
93 | - * |
|
94 | - * @return Css\Property\Property[] |
|
95 | - */ |
|
96 | - public function getInlineStyles(\DOMElement $element) |
|
97 | - { |
|
98 | - $processor = new PropertyProcessor(); |
|
99 | - |
|
100 | - return $processor->convertArrayToObjects( |
|
101 | - $processor->splitIntoSeparateProperties( |
|
102 | - $element->getAttribute('style') |
|
103 | - ) |
|
104 | - ); |
|
105 | - } |
|
106 | - |
|
107 | - /** |
|
108 | - * @param string $html |
|
109 | - * |
|
110 | - * @return \DOMDocument |
|
111 | - */ |
|
112 | - protected function createDomDocumentFromHtml($html) |
|
113 | - { |
|
114 | - $document = new \DOMDocument('1.0', 'UTF-8'); |
|
115 | - $internalErrors = libxml_use_internal_errors(true); |
|
116 | - $document->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8')); |
|
117 | - libxml_use_internal_errors($internalErrors); |
|
118 | - $document->formatOutput = true; |
|
119 | - |
|
120 | - return $document; |
|
121 | - } |
|
122 | - |
|
123 | - /** |
|
124 | - * @param \DOMDocument $document |
|
125 | - * |
|
126 | - * @return string |
|
127 | - */ |
|
128 | - protected function getHtmlFromDocument(\DOMDocument $document) |
|
129 | - { |
|
130 | - // retrieve the document element |
|
131 | - // we do it this way to preserve the utf-8 encoding |
|
132 | - $htmlElement = $document->documentElement; |
|
133 | - $html = $document->saveHTML($htmlElement); |
|
134 | - $html = trim($html); |
|
135 | - |
|
136 | - // retrieve the doctype |
|
137 | - $document->removeChild($htmlElement); |
|
138 | - $doctype = $document->saveHTML(); |
|
139 | - $doctype = trim($doctype); |
|
140 | - |
|
141 | - // if it is the html5 doctype convert it to lowercase |
|
142 | - if ($doctype === '<!DOCTYPE html>') { |
|
143 | - $doctype = strtolower($doctype); |
|
144 | - } |
|
145 | - |
|
146 | - return $doctype."\n".$html; |
|
147 | - } |
|
148 | - |
|
149 | - /** |
|
150 | - * @param \DOMDocument $document |
|
151 | - * @param Css\Rule\Rule[] $rules |
|
152 | - * |
|
153 | - * @return \DOMDocument |
|
154 | - */ |
|
155 | - protected function inline(\DOMDocument $document, array $rules) |
|
156 | - { |
|
157 | - if (empty($rules)) { |
|
158 | - return $document; |
|
159 | - } |
|
160 | - |
|
161 | - $propertyStorage = new \SplObjectStorage(); |
|
162 | - |
|
163 | - $xPath = new \DOMXPath($document); |
|
164 | - |
|
165 | - usort($rules, array(RuleProcessor::class, 'sortOnSpecificity')); |
|
166 | - |
|
167 | - foreach ($rules as $rule) { |
|
168 | - try { |
|
169 | - if (null !== $this->cssConverter) { |
|
170 | - $expression = $this->cssConverter->toXPath($rule->getSelector()); |
|
171 | - } else { |
|
172 | - // Compatibility layer for Symfony 2.7 and older |
|
173 | - $expression = CssSelector::toXPath($rule->getSelector()); |
|
174 | - } |
|
175 | - } catch (ExceptionInterface $e) { |
|
176 | - continue; |
|
177 | - } |
|
178 | - |
|
179 | - $elements = $xPath->query($expression); |
|
180 | - |
|
181 | - if ($elements === false) { |
|
182 | - continue; |
|
183 | - } |
|
184 | - |
|
185 | - foreach ($elements as $element) { |
|
186 | - $propertyStorage[$element] = $this->calculatePropertiesToBeApplied( |
|
187 | - $rule->getProperties(), |
|
188 | - $propertyStorage->contains($element) ? $propertyStorage[$element] : array() |
|
189 | - ); |
|
190 | - } |
|
191 | - } |
|
192 | - |
|
193 | - foreach ($propertyStorage as $element) { |
|
194 | - $this->inlineCssOnElement($element, $propertyStorage[$element]); |
|
195 | - } |
|
196 | - |
|
197 | - return $document; |
|
198 | - } |
|
199 | - |
|
200 | - /** |
|
201 | - * Merge the CSS rules to determine the applied properties. |
|
202 | - * |
|
203 | - * @param Css\Property\Property[] $properties |
|
204 | - * @param Css\Property\Property[] $cssProperties existing applied properties indexed by name |
|
205 | - * |
|
206 | - * @return Css\Property\Property[] updated properties, indexed by name |
|
207 | - */ |
|
208 | - private function calculatePropertiesToBeApplied(array $properties, array $cssProperties) |
|
209 | - { |
|
210 | - if (empty($properties)) { |
|
211 | - return $cssProperties; |
|
212 | - } |
|
213 | - |
|
214 | - foreach ($properties as $property) { |
|
215 | - if (isset($cssProperties[$property->getName()])) { |
|
216 | - $existingProperty = $cssProperties[$property->getName()]; |
|
217 | - |
|
218 | - //skip check to overrule if existing property is important and current is not |
|
219 | - if ($existingProperty->isImportant() && !$property->isImportant()) { |
|
220 | - continue; |
|
221 | - } |
|
222 | - |
|
223 | - //overrule if current property is important and existing is not, else check specificity |
|
224 | - $overrule = !$existingProperty->isImportant() && $property->isImportant(); |
|
225 | - if (!$overrule) { |
|
226 | - $overrule = $existingProperty->getOriginalSpecificity()->compareTo($property->getOriginalSpecificity()) <= 0; |
|
227 | - } |
|
228 | - |
|
229 | - if ($overrule) { |
|
230 | - unset($cssProperties[$property->getName()]); |
|
231 | - $cssProperties[$property->getName()] = $property; |
|
232 | - } |
|
233 | - } else { |
|
234 | - $cssProperties[$property->getName()] = $property; |
|
235 | - } |
|
236 | - } |
|
237 | - |
|
238 | - return $cssProperties; |
|
239 | - } |
|
14 | + private $cssConverter; |
|
15 | + |
|
16 | + public function __construct() |
|
17 | + { |
|
18 | + if (class_exists('Symfony\Component\CssSelector\CssSelectorConverter')) { |
|
19 | + $this->cssConverter = new CssSelectorConverter(); |
|
20 | + } |
|
21 | + } |
|
22 | + |
|
23 | + /** |
|
24 | + * Will inline the $css into the given $html |
|
25 | + * |
|
26 | + * Remark: if the html contains <style>-tags those will be used, the rules |
|
27 | + * in $css will be appended. |
|
28 | + * |
|
29 | + * @param string $html |
|
30 | + * @param string $css |
|
31 | + * |
|
32 | + * @return string |
|
33 | + */ |
|
34 | + public function convert($html, $css = null) |
|
35 | + { |
|
36 | + $document = $this->createDomDocumentFromHtml($html); |
|
37 | + $processor = new Processor(); |
|
38 | + |
|
39 | + // get all styles from the style-tags |
|
40 | + $rules = $processor->getRules( |
|
41 | + $processor->getCssFromStyleTags($html) |
|
42 | + ); |
|
43 | + |
|
44 | + if ($css !== null) { |
|
45 | + $rules = $processor->getRules($css, $rules); |
|
46 | + } |
|
47 | + |
|
48 | + $document = $this->inline($document, $rules); |
|
49 | + |
|
50 | + return $this->getHtmlFromDocument($document); |
|
51 | + } |
|
52 | + |
|
53 | + /** |
|
54 | + * Inline the given properties on an given DOMElement |
|
55 | + * |
|
56 | + * @param \DOMElement $element |
|
57 | + * @param Css\Property\Property[] $properties |
|
58 | + * |
|
59 | + * @return \DOMElement |
|
60 | + */ |
|
61 | + public function inlineCssOnElement(\DOMElement $element, array $properties) |
|
62 | + { |
|
63 | + if (empty($properties)) { |
|
64 | + return $element; |
|
65 | + } |
|
66 | + |
|
67 | + $cssProperties = array(); |
|
68 | + $inlineProperties = array(); |
|
69 | + |
|
70 | + foreach ($this->getInlineStyles($element) as $property) { |
|
71 | + $inlineProperties[$property->getName()] = $property; |
|
72 | + } |
|
73 | + |
|
74 | + foreach ($properties as $property) { |
|
75 | + if (!isset($inlineProperties[$property->getName()])) { |
|
76 | + $cssProperties[$property->getName()] = $property; |
|
77 | + } |
|
78 | + } |
|
79 | + |
|
80 | + $rules = array(); |
|
81 | + foreach (array_merge($cssProperties, $inlineProperties) as $property) { |
|
82 | + $rules[] = $property->toString(); |
|
83 | + } |
|
84 | + $element->setAttribute('style', implode(' ', $rules)); |
|
85 | + |
|
86 | + return $element; |
|
87 | + } |
|
88 | + |
|
89 | + /** |
|
90 | + * Get the current inline styles for a given DOMElement |
|
91 | + * |
|
92 | + * @param \DOMElement $element |
|
93 | + * |
|
94 | + * @return Css\Property\Property[] |
|
95 | + */ |
|
96 | + public function getInlineStyles(\DOMElement $element) |
|
97 | + { |
|
98 | + $processor = new PropertyProcessor(); |
|
99 | + |
|
100 | + return $processor->convertArrayToObjects( |
|
101 | + $processor->splitIntoSeparateProperties( |
|
102 | + $element->getAttribute('style') |
|
103 | + ) |
|
104 | + ); |
|
105 | + } |
|
106 | + |
|
107 | + /** |
|
108 | + * @param string $html |
|
109 | + * |
|
110 | + * @return \DOMDocument |
|
111 | + */ |
|
112 | + protected function createDomDocumentFromHtml($html) |
|
113 | + { |
|
114 | + $document = new \DOMDocument('1.0', 'UTF-8'); |
|
115 | + $internalErrors = libxml_use_internal_errors(true); |
|
116 | + $document->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8')); |
|
117 | + libxml_use_internal_errors($internalErrors); |
|
118 | + $document->formatOutput = true; |
|
119 | + |
|
120 | + return $document; |
|
121 | + } |
|
122 | + |
|
123 | + /** |
|
124 | + * @param \DOMDocument $document |
|
125 | + * |
|
126 | + * @return string |
|
127 | + */ |
|
128 | + protected function getHtmlFromDocument(\DOMDocument $document) |
|
129 | + { |
|
130 | + // retrieve the document element |
|
131 | + // we do it this way to preserve the utf-8 encoding |
|
132 | + $htmlElement = $document->documentElement; |
|
133 | + $html = $document->saveHTML($htmlElement); |
|
134 | + $html = trim($html); |
|
135 | + |
|
136 | + // retrieve the doctype |
|
137 | + $document->removeChild($htmlElement); |
|
138 | + $doctype = $document->saveHTML(); |
|
139 | + $doctype = trim($doctype); |
|
140 | + |
|
141 | + // if it is the html5 doctype convert it to lowercase |
|
142 | + if ($doctype === '<!DOCTYPE html>') { |
|
143 | + $doctype = strtolower($doctype); |
|
144 | + } |
|
145 | + |
|
146 | + return $doctype."\n".$html; |
|
147 | + } |
|
148 | + |
|
149 | + /** |
|
150 | + * @param \DOMDocument $document |
|
151 | + * @param Css\Rule\Rule[] $rules |
|
152 | + * |
|
153 | + * @return \DOMDocument |
|
154 | + */ |
|
155 | + protected function inline(\DOMDocument $document, array $rules) |
|
156 | + { |
|
157 | + if (empty($rules)) { |
|
158 | + return $document; |
|
159 | + } |
|
160 | + |
|
161 | + $propertyStorage = new \SplObjectStorage(); |
|
162 | + |
|
163 | + $xPath = new \DOMXPath($document); |
|
164 | + |
|
165 | + usort($rules, array(RuleProcessor::class, 'sortOnSpecificity')); |
|
166 | + |
|
167 | + foreach ($rules as $rule) { |
|
168 | + try { |
|
169 | + if (null !== $this->cssConverter) { |
|
170 | + $expression = $this->cssConverter->toXPath($rule->getSelector()); |
|
171 | + } else { |
|
172 | + // Compatibility layer for Symfony 2.7 and older |
|
173 | + $expression = CssSelector::toXPath($rule->getSelector()); |
|
174 | + } |
|
175 | + } catch (ExceptionInterface $e) { |
|
176 | + continue; |
|
177 | + } |
|
178 | + |
|
179 | + $elements = $xPath->query($expression); |
|
180 | + |
|
181 | + if ($elements === false) { |
|
182 | + continue; |
|
183 | + } |
|
184 | + |
|
185 | + foreach ($elements as $element) { |
|
186 | + $propertyStorage[$element] = $this->calculatePropertiesToBeApplied( |
|
187 | + $rule->getProperties(), |
|
188 | + $propertyStorage->contains($element) ? $propertyStorage[$element] : array() |
|
189 | + ); |
|
190 | + } |
|
191 | + } |
|
192 | + |
|
193 | + foreach ($propertyStorage as $element) { |
|
194 | + $this->inlineCssOnElement($element, $propertyStorage[$element]); |
|
195 | + } |
|
196 | + |
|
197 | + return $document; |
|
198 | + } |
|
199 | + |
|
200 | + /** |
|
201 | + * Merge the CSS rules to determine the applied properties. |
|
202 | + * |
|
203 | + * @param Css\Property\Property[] $properties |
|
204 | + * @param Css\Property\Property[] $cssProperties existing applied properties indexed by name |
|
205 | + * |
|
206 | + * @return Css\Property\Property[] updated properties, indexed by name |
|
207 | + */ |
|
208 | + private function calculatePropertiesToBeApplied(array $properties, array $cssProperties) |
|
209 | + { |
|
210 | + if (empty($properties)) { |
|
211 | + return $cssProperties; |
|
212 | + } |
|
213 | + |
|
214 | + foreach ($properties as $property) { |
|
215 | + if (isset($cssProperties[$property->getName()])) { |
|
216 | + $existingProperty = $cssProperties[$property->getName()]; |
|
217 | + |
|
218 | + //skip check to overrule if existing property is important and current is not |
|
219 | + if ($existingProperty->isImportant() && !$property->isImportant()) { |
|
220 | + continue; |
|
221 | + } |
|
222 | + |
|
223 | + //overrule if current property is important and existing is not, else check specificity |
|
224 | + $overrule = !$existingProperty->isImportant() && $property->isImportant(); |
|
225 | + if (!$overrule) { |
|
226 | + $overrule = $existingProperty->getOriginalSpecificity()->compareTo($property->getOriginalSpecificity()) <= 0; |
|
227 | + } |
|
228 | + |
|
229 | + if ($overrule) { |
|
230 | + unset($cssProperties[$property->getName()]); |
|
231 | + $cssProperties[$property->getName()] = $property; |
|
232 | + } |
|
233 | + } else { |
|
234 | + $cssProperties[$property->getName()] = $property; |
|
235 | + } |
|
236 | + } |
|
237 | + |
|
238 | + return $cssProperties; |
|
239 | + } |
|
240 | 240 | } |
@@ -26,44 +26,44 @@ |
||
26 | 26 | */ |
27 | 27 | class CssSelectorConverter |
28 | 28 | { |
29 | - private $translator; |
|
30 | - private $cache; |
|
29 | + private $translator; |
|
30 | + private $cache; |
|
31 | 31 | |
32 | - private static $xmlCache = []; |
|
33 | - private static $htmlCache = []; |
|
32 | + private static $xmlCache = []; |
|
33 | + private static $htmlCache = []; |
|
34 | 34 | |
35 | - /** |
|
36 | - * @param bool $html Whether HTML support should be enabled. Disable it for XML documents |
|
37 | - */ |
|
38 | - public function __construct(bool $html = true) |
|
39 | - { |
|
40 | - $this->translator = new Translator(); |
|
35 | + /** |
|
36 | + * @param bool $html Whether HTML support should be enabled. Disable it for XML documents |
|
37 | + */ |
|
38 | + public function __construct(bool $html = true) |
|
39 | + { |
|
40 | + $this->translator = new Translator(); |
|
41 | 41 | |
42 | - if ($html) { |
|
43 | - $this->translator->registerExtension(new HtmlExtension($this->translator)); |
|
44 | - $this->cache = &self::$htmlCache; |
|
45 | - } else { |
|
46 | - $this->cache = &self::$xmlCache; |
|
47 | - } |
|
42 | + if ($html) { |
|
43 | + $this->translator->registerExtension(new HtmlExtension($this->translator)); |
|
44 | + $this->cache = &self::$htmlCache; |
|
45 | + } else { |
|
46 | + $this->cache = &self::$xmlCache; |
|
47 | + } |
|
48 | 48 | |
49 | - $this->translator |
|
50 | - ->registerParserShortcut(new EmptyStringParser()) |
|
51 | - ->registerParserShortcut(new ElementParser()) |
|
52 | - ->registerParserShortcut(new ClassParser()) |
|
53 | - ->registerParserShortcut(new HashParser()) |
|
54 | - ; |
|
55 | - } |
|
49 | + $this->translator |
|
50 | + ->registerParserShortcut(new EmptyStringParser()) |
|
51 | + ->registerParserShortcut(new ElementParser()) |
|
52 | + ->registerParserShortcut(new ClassParser()) |
|
53 | + ->registerParserShortcut(new HashParser()) |
|
54 | + ; |
|
55 | + } |
|
56 | 56 | |
57 | - /** |
|
58 | - * Translates a CSS expression to its XPath equivalent. |
|
59 | - * |
|
60 | - * Optionally, a prefix can be added to the resulting XPath |
|
61 | - * expression with the $prefix parameter. |
|
62 | - * |
|
63 | - * @return string |
|
64 | - */ |
|
65 | - public function toXPath(string $cssExpr, string $prefix = 'descendant-or-self::') |
|
66 | - { |
|
67 | - return $this->cache[$prefix][$cssExpr] ?? $this->cache[$prefix][$cssExpr] = $this->translator->cssToXPath($cssExpr, $prefix); |
|
68 | - } |
|
57 | + /** |
|
58 | + * Translates a CSS expression to its XPath equivalent. |
|
59 | + * |
|
60 | + * Optionally, a prefix can be added to the resulting XPath |
|
61 | + * expression with the $prefix parameter. |
|
62 | + * |
|
63 | + * @return string |
|
64 | + */ |
|
65 | + public function toXPath(string $cssExpr, string $prefix = 'descendant-or-self::') |
|
66 | + { |
|
67 | + return $this->cache[$prefix][$cssExpr] ?? $this->cache[$prefix][$cssExpr] = $this->translator->cssToXPath($cssExpr, $prefix); |
|
68 | + } |
|
69 | 69 | } |
@@ -25,49 +25,49 @@ |
||
25 | 25 | */ |
26 | 26 | class Specificity |
27 | 27 | { |
28 | - public const A_FACTOR = 100; |
|
29 | - public const B_FACTOR = 10; |
|
30 | - public const C_FACTOR = 1; |
|
28 | + public const A_FACTOR = 100; |
|
29 | + public const B_FACTOR = 10; |
|
30 | + public const C_FACTOR = 1; |
|
31 | 31 | |
32 | - private $a; |
|
33 | - private $b; |
|
34 | - private $c; |
|
32 | + private $a; |
|
33 | + private $b; |
|
34 | + private $c; |
|
35 | 35 | |
36 | - public function __construct(int $a, int $b, int $c) |
|
37 | - { |
|
38 | - $this->a = $a; |
|
39 | - $this->b = $b; |
|
40 | - $this->c = $c; |
|
41 | - } |
|
36 | + public function __construct(int $a, int $b, int $c) |
|
37 | + { |
|
38 | + $this->a = $a; |
|
39 | + $this->b = $b; |
|
40 | + $this->c = $c; |
|
41 | + } |
|
42 | 42 | |
43 | - public function plus(self $specificity): self |
|
44 | - { |
|
45 | - return new self($this->a + $specificity->a, $this->b + $specificity->b, $this->c + $specificity->c); |
|
46 | - } |
|
43 | + public function plus(self $specificity): self |
|
44 | + { |
|
45 | + return new self($this->a + $specificity->a, $this->b + $specificity->b, $this->c + $specificity->c); |
|
46 | + } |
|
47 | 47 | |
48 | - public function getValue(): int |
|
49 | - { |
|
50 | - return $this->a * self::A_FACTOR + $this->b * self::B_FACTOR + $this->c * self::C_FACTOR; |
|
51 | - } |
|
48 | + public function getValue(): int |
|
49 | + { |
|
50 | + return $this->a * self::A_FACTOR + $this->b * self::B_FACTOR + $this->c * self::C_FACTOR; |
|
51 | + } |
|
52 | 52 | |
53 | - /** |
|
54 | - * Returns -1 if the object specificity is lower than the argument, |
|
55 | - * 0 if they are equal, and 1 if the argument is lower. |
|
56 | - */ |
|
57 | - public function compareTo(self $specificity): int |
|
58 | - { |
|
59 | - if ($this->a !== $specificity->a) { |
|
60 | - return $this->a > $specificity->a ? 1 : -1; |
|
61 | - } |
|
53 | + /** |
|
54 | + * Returns -1 if the object specificity is lower than the argument, |
|
55 | + * 0 if they are equal, and 1 if the argument is lower. |
|
56 | + */ |
|
57 | + public function compareTo(self $specificity): int |
|
58 | + { |
|
59 | + if ($this->a !== $specificity->a) { |
|
60 | + return $this->a > $specificity->a ? 1 : -1; |
|
61 | + } |
|
62 | 62 | |
63 | - if ($this->b !== $specificity->b) { |
|
64 | - return $this->b > $specificity->b ? 1 : -1; |
|
65 | - } |
|
63 | + if ($this->b !== $specificity->b) { |
|
64 | + return $this->b > $specificity->b ? 1 : -1; |
|
65 | + } |
|
66 | 66 | |
67 | - if ($this->c !== $specificity->c) { |
|
68 | - return $this->c > $specificity->c ? 1 : -1; |
|
69 | - } |
|
67 | + if ($this->c !== $specificity->c) { |
|
68 | + return $this->c > $specificity->c ? 1 : -1; |
|
69 | + } |
|
70 | 70 | |
71 | - return 0; |
|
72 | - } |
|
71 | + return 0; |
|
72 | + } |
|
73 | 73 | } |
@@ -23,17 +23,17 @@ |
||
23 | 23 | */ |
24 | 24 | abstract class AbstractNode implements NodeInterface |
25 | 25 | { |
26 | - /** |
|
27 | - * @var string |
|
28 | - */ |
|
29 | - private $nodeName; |
|
26 | + /** |
|
27 | + * @var string |
|
28 | + */ |
|
29 | + private $nodeName; |
|
30 | 30 | |
31 | - public function getNodeName(): string |
|
32 | - { |
|
33 | - if (null === $this->nodeName) { |
|
34 | - $this->nodeName = preg_replace('~.*\\\\([^\\\\]+)Node$~', '$1', static::class); |
|
35 | - } |
|
31 | + public function getNodeName(): string |
|
32 | + { |
|
33 | + if (null === $this->nodeName) { |
|
34 | + $this->nodeName = preg_replace('~.*\\\\([^\\\\]+)Node$~', '$1', static::class); |
|
35 | + } |
|
36 | 36 | |
37 | - return $this->nodeName; |
|
38 | - } |
|
37 | + return $this->nodeName; |
|
38 | + } |
|
39 | 39 | } |
@@ -23,37 +23,37 @@ |
||
23 | 23 | */ |
24 | 24 | class ElementNode extends AbstractNode |
25 | 25 | { |
26 | - private $namespace; |
|
27 | - private $element; |
|
28 | - |
|
29 | - public function __construct(string $namespace = null, string $element = null) |
|
30 | - { |
|
31 | - $this->namespace = $namespace; |
|
32 | - $this->element = $element; |
|
33 | - } |
|
34 | - |
|
35 | - public function getNamespace(): ?string |
|
36 | - { |
|
37 | - return $this->namespace; |
|
38 | - } |
|
39 | - |
|
40 | - public function getElement(): ?string |
|
41 | - { |
|
42 | - return $this->element; |
|
43 | - } |
|
44 | - |
|
45 | - /** |
|
46 | - * {@inheritdoc} |
|
47 | - */ |
|
48 | - public function getSpecificity(): Specificity |
|
49 | - { |
|
50 | - return new Specificity(0, 0, $this->element ? 1 : 0); |
|
51 | - } |
|
52 | - |
|
53 | - public function __toString(): string |
|
54 | - { |
|
55 | - $element = $this->element ?: '*'; |
|
56 | - |
|
57 | - return sprintf('%s[%s]', $this->getNodeName(), $this->namespace ? $this->namespace.'|'.$element : $element); |
|
58 | - } |
|
26 | + private $namespace; |
|
27 | + private $element; |
|
28 | + |
|
29 | + public function __construct(string $namespace = null, string $element = null) |
|
30 | + { |
|
31 | + $this->namespace = $namespace; |
|
32 | + $this->element = $element; |
|
33 | + } |
|
34 | + |
|
35 | + public function getNamespace(): ?string |
|
36 | + { |
|
37 | + return $this->namespace; |
|
38 | + } |
|
39 | + |
|
40 | + public function getElement(): ?string |
|
41 | + { |
|
42 | + return $this->element; |
|
43 | + } |
|
44 | + |
|
45 | + /** |
|
46 | + * {@inheritdoc} |
|
47 | + */ |
|
48 | + public function getSpecificity(): Specificity |
|
49 | + { |
|
50 | + return new Specificity(0, 0, $this->element ? 1 : 0); |
|
51 | + } |
|
52 | + |
|
53 | + public function __toString(): string |
|
54 | + { |
|
55 | + $element = $this->element ?: '*'; |
|
56 | + |
|
57 | + return sprintf('%s[%s]', $this->getNodeName(), $this->namespace ? $this->namespace.'|'.$element : $element); |
|
58 | + } |
|
59 | 59 | } |
@@ -23,35 +23,35 @@ |
||
23 | 23 | */ |
24 | 24 | class PseudoNode extends AbstractNode |
25 | 25 | { |
26 | - private $selector; |
|
27 | - private $identifier; |
|
28 | - |
|
29 | - public function __construct(NodeInterface $selector, string $identifier) |
|
30 | - { |
|
31 | - $this->selector = $selector; |
|
32 | - $this->identifier = strtolower($identifier); |
|
33 | - } |
|
34 | - |
|
35 | - public function getSelector(): NodeInterface |
|
36 | - { |
|
37 | - return $this->selector; |
|
38 | - } |
|
39 | - |
|
40 | - public function getIdentifier(): string |
|
41 | - { |
|
42 | - return $this->identifier; |
|
43 | - } |
|
44 | - |
|
45 | - /** |
|
46 | - * {@inheritdoc} |
|
47 | - */ |
|
48 | - public function getSpecificity(): Specificity |
|
49 | - { |
|
50 | - return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0)); |
|
51 | - } |
|
52 | - |
|
53 | - public function __toString(): string |
|
54 | - { |
|
55 | - return sprintf('%s[%s:%s]', $this->getNodeName(), $this->selector, $this->identifier); |
|
56 | - } |
|
26 | + private $selector; |
|
27 | + private $identifier; |
|
28 | + |
|
29 | + public function __construct(NodeInterface $selector, string $identifier) |
|
30 | + { |
|
31 | + $this->selector = $selector; |
|
32 | + $this->identifier = strtolower($identifier); |
|
33 | + } |
|
34 | + |
|
35 | + public function getSelector(): NodeInterface |
|
36 | + { |
|
37 | + return $this->selector; |
|
38 | + } |
|
39 | + |
|
40 | + public function getIdentifier(): string |
|
41 | + { |
|
42 | + return $this->identifier; |
|
43 | + } |
|
44 | + |
|
45 | + /** |
|
46 | + * {@inheritdoc} |
|
47 | + */ |
|
48 | + public function getSpecificity(): Specificity |
|
49 | + { |
|
50 | + return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0)); |
|
51 | + } |
|
52 | + |
|
53 | + public function __toString(): string |
|
54 | + { |
|
55 | + return sprintf('%s[%s:%s]', $this->getNodeName(), $this->selector, $this->identifier); |
|
56 | + } |
|
57 | 57 | } |
@@ -23,44 +23,44 @@ |
||
23 | 23 | */ |
24 | 24 | class CombinedSelectorNode extends AbstractNode |
25 | 25 | { |
26 | - private $selector; |
|
27 | - private $combinator; |
|
28 | - private $subSelector; |
|
26 | + private $selector; |
|
27 | + private $combinator; |
|
28 | + private $subSelector; |
|
29 | 29 | |
30 | - public function __construct(NodeInterface $selector, string $combinator, NodeInterface $subSelector) |
|
31 | - { |
|
32 | - $this->selector = $selector; |
|
33 | - $this->combinator = $combinator; |
|
34 | - $this->subSelector = $subSelector; |
|
35 | - } |
|
30 | + public function __construct(NodeInterface $selector, string $combinator, NodeInterface $subSelector) |
|
31 | + { |
|
32 | + $this->selector = $selector; |
|
33 | + $this->combinator = $combinator; |
|
34 | + $this->subSelector = $subSelector; |
|
35 | + } |
|
36 | 36 | |
37 | - public function getSelector(): NodeInterface |
|
38 | - { |
|
39 | - return $this->selector; |
|
40 | - } |
|
37 | + public function getSelector(): NodeInterface |
|
38 | + { |
|
39 | + return $this->selector; |
|
40 | + } |
|
41 | 41 | |
42 | - public function getCombinator(): string |
|
43 | - { |
|
44 | - return $this->combinator; |
|
45 | - } |
|
42 | + public function getCombinator(): string |
|
43 | + { |
|
44 | + return $this->combinator; |
|
45 | + } |
|
46 | 46 | |
47 | - public function getSubSelector(): NodeInterface |
|
48 | - { |
|
49 | - return $this->subSelector; |
|
50 | - } |
|
47 | + public function getSubSelector(): NodeInterface |
|
48 | + { |
|
49 | + return $this->subSelector; |
|
50 | + } |
|
51 | 51 | |
52 | - /** |
|
53 | - * {@inheritdoc} |
|
54 | - */ |
|
55 | - public function getSpecificity(): Specificity |
|
56 | - { |
|
57 | - return $this->selector->getSpecificity()->plus($this->subSelector->getSpecificity()); |
|
58 | - } |
|
52 | + /** |
|
53 | + * {@inheritdoc} |
|
54 | + */ |
|
55 | + public function getSpecificity(): Specificity |
|
56 | + { |
|
57 | + return $this->selector->getSpecificity()->plus($this->subSelector->getSpecificity()); |
|
58 | + } |
|
59 | 59 | |
60 | - public function __toString(): string |
|
61 | - { |
|
62 | - $combinator = ' ' === $this->combinator ? '<followed>' : $this->combinator; |
|
60 | + public function __toString(): string |
|
61 | + { |
|
62 | + $combinator = ' ' === $this->combinator ? '<followed>' : $this->combinator; |
|
63 | 63 | |
64 | - return sprintf('%s[%s %s %s]', $this->getNodeName(), $this->selector, $combinator, $this->subSelector); |
|
65 | - } |
|
64 | + return sprintf('%s[%s %s %s]', $this->getNodeName(), $this->selector, $combinator, $this->subSelector); |
|
65 | + } |
|
66 | 66 | } |
@@ -25,52 +25,52 @@ |
||
25 | 25 | */ |
26 | 26 | class FunctionNode extends AbstractNode |
27 | 27 | { |
28 | - private $selector; |
|
29 | - private $name; |
|
30 | - private $arguments; |
|
28 | + private $selector; |
|
29 | + private $name; |
|
30 | + private $arguments; |
|
31 | 31 | |
32 | - /** |
|
33 | - * @param Token[] $arguments |
|
34 | - */ |
|
35 | - public function __construct(NodeInterface $selector, string $name, array $arguments = []) |
|
36 | - { |
|
37 | - $this->selector = $selector; |
|
38 | - $this->name = strtolower($name); |
|
39 | - $this->arguments = $arguments; |
|
40 | - } |
|
32 | + /** |
|
33 | + * @param Token[] $arguments |
|
34 | + */ |
|
35 | + public function __construct(NodeInterface $selector, string $name, array $arguments = []) |
|
36 | + { |
|
37 | + $this->selector = $selector; |
|
38 | + $this->name = strtolower($name); |
|
39 | + $this->arguments = $arguments; |
|
40 | + } |
|
41 | 41 | |
42 | - public function getSelector(): NodeInterface |
|
43 | - { |
|
44 | - return $this->selector; |
|
45 | - } |
|
42 | + public function getSelector(): NodeInterface |
|
43 | + { |
|
44 | + return $this->selector; |
|
45 | + } |
|
46 | 46 | |
47 | - public function getName(): string |
|
48 | - { |
|
49 | - return $this->name; |
|
50 | - } |
|
47 | + public function getName(): string |
|
48 | + { |
|
49 | + return $this->name; |
|
50 | + } |
|
51 | 51 | |
52 | - /** |
|
53 | - * @return Token[] |
|
54 | - */ |
|
55 | - public function getArguments(): array |
|
56 | - { |
|
57 | - return $this->arguments; |
|
58 | - } |
|
52 | + /** |
|
53 | + * @return Token[] |
|
54 | + */ |
|
55 | + public function getArguments(): array |
|
56 | + { |
|
57 | + return $this->arguments; |
|
58 | + } |
|
59 | 59 | |
60 | - /** |
|
61 | - * {@inheritdoc} |
|
62 | - */ |
|
63 | - public function getSpecificity(): Specificity |
|
64 | - { |
|
65 | - return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0)); |
|
66 | - } |
|
60 | + /** |
|
61 | + * {@inheritdoc} |
|
62 | + */ |
|
63 | + public function getSpecificity(): Specificity |
|
64 | + { |
|
65 | + return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0)); |
|
66 | + } |
|
67 | 67 | |
68 | - public function __toString(): string |
|
69 | - { |
|
70 | - $arguments = implode(', ', array_map(function (Token $token) { |
|
71 | - return "'".$token->getValue()."'"; |
|
72 | - }, $this->arguments)); |
|
68 | + public function __toString(): string |
|
69 | + { |
|
70 | + $arguments = implode(', ', array_map(function (Token $token) { |
|
71 | + return "'".$token->getValue()."'"; |
|
72 | + }, $this->arguments)); |
|
73 | 73 | |
74 | - return sprintf('%s[%s:%s(%s)]', $this->getNodeName(), $this->selector, $this->name, $arguments ? '['.$arguments.']' : ''); |
|
75 | - } |
|
74 | + return sprintf('%s[%s:%s(%s)]', $this->getNodeName(), $this->selector, $this->name, $arguments ? '['.$arguments.']' : ''); |
|
75 | + } |
|
76 | 76 | } |