Skip to content

Commit 0d2819b

Browse files
committed
Reworked rules / document walking and more...
1 parent 46363ab commit 0d2819b

File tree

4 files changed

+127
-13
lines changed

4 files changed

+127
-13
lines changed

src/CssStore.php

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22

33
namespace PageSpecificCss;
44

5+
use TijsVerkoyen\CssToInlineStyles\Css\Property\Property;
6+
57
class CssStore
68
{
7-
/** @var string[] */
9+
/** @var array Property objects, grouped by selector */
810
private $styles = [];
911

10-
public function addCssStyle($cssRules)
12+
public function addCssStyles($cssRules)
1113
{
12-
$this->styles[] = $cssRules;
14+
$this->styles = array_merge($this->styles, $cssRules);
1315
return $this;
1416
}
1517

@@ -18,11 +20,6 @@ public function getStyles()
1820
return $this->styles;
1921
}
2022

21-
public function compileStyles()
22-
{
23-
return join(';', $this->styles);
24-
}
25-
2623
/**
2724
* @param string $path
2825
*
@@ -33,5 +30,27 @@ public function dumpStyles($path)
3330
return file_put_contents($path, $this->compileStyles()) === false;
3431
}
3532

33+
public function compileStyles()
34+
{
35+
return join('', array_map(function ($properties,$key) {
36+
return $this->parsePropertiesToString($key, $properties);
37+
}, $this->styles, array_keys($this->styles)));
38+
}
39+
40+
/**
41+
* @param string $selector
42+
* @param array $properties
43+
*
44+
* @return string
45+
*/
46+
private function parsePropertiesToString($selector, array $properties)
47+
{
48+
return "$selector { " .
49+
join('', array_map(function (Property $property) {
50+
return $property->getName() . ': ' . $property->getValue() . ';';
51+
}, $properties)
52+
) .
53+
"}";
54+
}
3655

3756
}

src/PageSpecificCss.php

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,53 @@
22

33
namespace PageSpecificCss;
44

5+
use Symfony\Component\CssSelector\CssSelectorConverter;
6+
use Symfony\Component\CssSelector\Exception\ExceptionInterface;
57
use TijsVerkoyen\CssToInlineStyles\Css\Processor;
8+
use TijsVerkoyen\CssToInlineStyles\Css\Rule\Processor as RuleProcessor;
9+
use TijsVerkoyen\CssToInlineStyles\Css\Rule\Rule;
610
use TijsVerkoyen\CssToInlineStyles\CssToInlineStyles;
711

812
class PageSpecificCss extends CssToInlineStyles
913
{
1014

15+
/** @var CssSelectorConverter */
16+
protected $cssConverter;
17+
1118
/** @var CssStore */
1219
private $cssStore;
1320

1421
/** @var Processor */
1522
private $processor;
1623

24+
/** @var Rule[] */
25+
private $rules;
26+
1727
/**
1828
* PageSpecificCss constructor.
29+
* @param string $sourceCss path to the source css
1930
*/
20-
public function __construct()
31+
public function __construct($sourceCss)
2132
{
2233
parent::__construct();
2334

2435
$this->cssStore = new CssStore();
25-
$this->processor = new Processor(true);
36+
$this->processor = new Processor();
37+
$this->rules = $this->processor->getRules(file_get_contents($sourceCss));
38+
$this->cssConverter = new CssSelectorConverter();
39+
40+
}
41+
42+
public function getStore(){
43+
return $this->cssStore;
2644
}
2745

2846
/**
2947
* @param string $html the raw html
3048
*/
3149
public function processHtmlToStore($html)
3250
{
33-
$this->cssStore->addCssStyle($this->extractCss($html));
51+
$this->cssStore->addCssStyles($this->extractCss($html));
3452
}
3553

3654
/**
@@ -40,6 +58,52 @@ public function processHtmlToStore($html)
4058
*/
4159
public function extractCss($html)
4260
{
43-
return $this->processor->getCssFromStyleTags($html);
61+
$document = $this->createDomDocumentFromHtml($html);
62+
63+
$xPath = new \DOMXPath($document);
64+
65+
usort($this->rules, [RuleProcessor::class, 'sortOnSpecificity']);
66+
67+
$applicable_rules = array_filter($this->rules, function (Rule $rule) use ($xPath) {
68+
try {
69+
$expression = $this->cssConverter->toXPath($rule->getSelector());
70+
} catch (ExceptionInterface $e) {
71+
return false;
72+
}
73+
74+
$elements = $xPath->query($expression);
75+
76+
if ($elements === false || $elements->length == 0) {
77+
return false;
78+
}
79+
80+
return true;
81+
});
82+
83+
$applicable_rules = $this->groupRulesBySelector($applicable_rules);
84+
return $applicable_rules;
85+
86+
87+
}
88+
89+
/**
90+
* @param Rule[] $applicable_rules
91+
*
92+
* @return array
93+
*/
94+
private function groupRulesBySelector($applicable_rules)
95+
{
96+
$grouped = [];
97+
98+
foreach ($applicable_rules as $applicable_rule) {
99+
/** @var Rule $applicable_rule */
100+
if (isset($grouped[$applicable_rule->getSelector()])) {
101+
$grouped[$applicable_rule->getSelector()] = array_merge($grouped[$applicable_rule->getSelector()], $applicable_rule->getProperties());
102+
} else {
103+
$grouped[$applicable_rule->getSelector()] = $applicable_rule->getProperties();
104+
}
105+
}
106+
107+
return $grouped;
44108
}
45109
}

src/Twig/Extension.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,42 @@
22

33
namespace PageSpecificCss\Twig;
44

5+
use PageSpecificCss\PageSpecificCss;
56
use PageSpecificCss\Twig\TokenParsers\FoldTokenParser;
67
use Twig_Extension;
78
use Twig_ExtensionInterface;
89

910
class Extension extends Twig_Extension implements Twig_ExtensionInterface
1011
{
1112

13+
/** @var PageSpecificCss */
14+
private $pageSpecificCssService;
15+
16+
/**
17+
* Extension constructor.
18+
*
19+
* @param string $sourceCss
20+
*/
21+
public function __construct($sourceCss)
22+
{
23+
$this->pageSpecificCssService = new PageSpecificCss($sourceCss);
24+
}
25+
1226
public function getTokenParsers()
1327
{
1428
return [
1529
new FoldTokenParser(),
1630
];
1731
}
1832

33+
public function addCssToExtract($rawHtml)
34+
{
35+
$this->pageSpecificCssService->processHtmlToStore($rawHtml);
36+
return $rawHtml;
37+
}
38+
39+
public function getCriticalCss()
40+
{
41+
return $this->pageSpecificCssService->getStore()->compileStyles();
42+
}
1943
}

src/Twig/TokenParsers/FoldNode.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PageSpecificCss\Twig\TokenParsers;
44

5+
use PageSpecificCss\Twig\Extension;
56
use Twig_Compiler;
67
use Twig_Node;
78

@@ -15,6 +16,12 @@ public function __construct(Twig_Node $body, array $attributes, $lineno, $tag)
1516

1617
public function compile(Twig_Compiler $compiler)
1718
{
18-
file_put_contents('test', $this->getNode('body'));
19+
$compiler
20+
->addDebugInfo($this)
21+
->write("ob_start();\n")
22+
->subcompile($this->getNode('body'))
23+
->write("echo \$this->env->getExtension('".Extension::class."')->addCssToExtract(")
24+
->raw('trim(ob_get_clean())')
25+
->raw(");\n");
1926
}
2027
}

0 commit comments

Comments
 (0)