1
|
|
|
<?php declare(strict_types=1); |
2
|
|
|
//////////////////////////////////////////////////////////////////////////////// |
3
|
|
|
// __________ __ ________ __________ |
4
|
|
|
// \______ \ |__ ______ / _____/ ____ _____ ______\______ \ _______ ___ |
5
|
|
|
// | ___/ | \\____ \/ \ ____/ __ \\__ \\_ __ \ | _// _ \ \/ / |
6
|
|
|
// | | | Y \ |_> > \_\ \ ___/ / __ \| | \/ | ( <_> > < |
7
|
|
|
// |____| |___| / __/ \______ /\___ >____ /__| |______ /\____/__/\_ \ |
8
|
|
|
// \/|__| \/ \/ \/ \/ \/ |
9
|
|
|
// ----------------------------------------------------------------------------- |
10
|
|
|
// Designed and Developed by Brad Jones <brad @="bjc.id.au" /> |
11
|
|
|
// ----------------------------------------------------------------------------- |
12
|
|
|
//////////////////////////////////////////////////////////////////////////////// |
13
|
|
|
|
14
|
|
|
namespace Gears\Asset\Compilers; |
15
|
|
|
|
16
|
|
|
use Autoprefixer; |
17
|
|
|
use Gears\String\Str; |
18
|
|
|
use Gears\Asset\Compilers\Base; |
19
|
|
|
use Symfony\Component\Filesystem\Filesystem; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* Normally css files will reference other assets, such as images and fonts. |
23
|
|
|
* |
24
|
|
|
* When we build a new asset from the source css and that asset is saved |
25
|
|
|
* else where in our project, the paths to these other "binary" assets |
26
|
|
|
* may no longer point to the correct place. |
27
|
|
|
* |
28
|
|
|
* This compiler takes care of this issues for us. |
29
|
|
|
* |
30
|
|
|
* > NOTE: We do make the assumption however that the fonts and images are |
31
|
|
|
* > indeed located in the public web accessible document root. If your assets |
32
|
|
|
* > are not it is on you to move / copy them at build time. |
33
|
|
|
*/ |
34
|
|
|
class Css extends Base |
35
|
|
|
{ |
36
|
|
|
public function compile(): string |
37
|
|
|
{ |
38
|
|
|
// Run the parent compiler first, so that we are dealing with the |
39
|
|
|
// final/minfied source. If were to perform our link replacing before |
40
|
|
|
// then the minfier might find a pre-minified asset and simply use that. |
41
|
|
|
$source = parent::compile(); |
42
|
|
|
|
43
|
|
|
// Grab the real paths to both the source file and the destination asset |
44
|
|
|
$css_asset_root = realpath($this->file->getPath()); |
45
|
|
|
$destination_root = realpath($this->destination->getPath()); |
46
|
|
|
|
47
|
|
|
// Lets find some urls in our css |
48
|
|
|
preg_match_all('/url\(([\'"]?.*?[\'"]?)\)/', $source, $matches); |
49
|
|
|
|
50
|
|
|
// Loop through the matches |
51
|
|
|
foreach ($matches[1] as $key => $match) |
52
|
|
|
{ |
53
|
|
|
// Split the match into an array of file path parts |
54
|
|
|
$fileinfo = pathinfo(str_replace(["'", '"'], '', $match)); |
55
|
|
|
|
56
|
|
|
// This is here really just to catter for font faces. |
57
|
|
|
$after_file_name = ''; |
58
|
|
|
|
59
|
|
|
// Fonts in css sometimes contain some funny charcters that are not |
60
|
|
|
// part of the file name but are just there to deal with, yep you |
61
|
|
|
// guessed it... IE :( |
62
|
|
View Code Duplication |
if (Str::s($fileinfo['extension'])->contains('?#')) |
|
|
|
|
63
|
|
|
{ |
64
|
|
|
$ext = '<START>'.$fileinfo['extension'].'<END>'; |
65
|
|
|
$fileinfo['extension'] = Str::s($ext)->between('<START>', '?'); |
66
|
|
|
$after_file_name = '?'.Str::s($ext)->between('?', '<END>'); |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
// SVG fonts can have some sort of ID, I am no expert on this but |
70
|
|
|
// for our purposes we can safely ignore the id.. |
71
|
|
View Code Duplication |
if (Str::s($fileinfo['extension'])->contains('svg#')) |
|
|
|
|
72
|
|
|
{ |
73
|
|
|
$ext = '<START>'.$fileinfo['extension'].'<END>'; |
74
|
|
|
$fileinfo['extension'] = 'svg'; |
75
|
|
|
$after_file_name = '#'.Str::s($ext)->between('#', '<END>'); |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
// Create the real path to the actual asset |
79
|
|
|
$css_asset_path = realpath |
80
|
|
|
( |
81
|
|
|
$css_asset_root.'/'. |
82
|
|
|
$fileinfo['dirname'].'/'. |
83
|
|
|
$fileinfo['filename'].'.'. |
84
|
|
|
$fileinfo['extension'] |
85
|
|
|
); |
86
|
|
|
|
87
|
|
|
// Sometimes we don't get it right. Perhaps the URL was pointing to |
88
|
|
|
// somewhere on the web. In any case if can't find the actual file |
89
|
|
|
// on the filesystem its time to move on. |
90
|
|
|
if ($css_asset_path === false) |
91
|
|
|
{ |
92
|
|
|
continue; |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
// Now lets calulate the relative path between the destination |
96
|
|
|
// location and the actual asset location. |
97
|
|
|
$css_asset_path = (new Filesystem())->makePathRelative |
98
|
|
|
( |
99
|
|
|
$css_asset_path, |
100
|
|
|
$destination_root |
101
|
|
|
); |
102
|
|
|
|
103
|
|
|
// Remove the last slash that is added |
104
|
|
|
// by the above relative path calulation |
105
|
|
|
if (Str::s($css_asset_path)->endsWith('/')) |
106
|
|
|
{ |
107
|
|
|
$css_asset_path = substr($css_asset_path, 0, -1); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
// Fix for windows enviroments |
111
|
|
|
$css_asset_path = Str::s($css_asset_path)->replace('\\', '/'); |
112
|
|
|
|
113
|
|
|
// Do some search and replacing |
114
|
|
|
$source = (string) Str::s($source)->replace |
115
|
|
|
( |
116
|
|
|
'url('.$match.')', |
117
|
|
|
'url('.$css_asset_path.$after_file_name.')' |
118
|
|
|
); |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
// Next run autoprefixer over the css |
122
|
|
|
if ($this->autoprefix !== false) |
123
|
|
|
{ |
124
|
|
|
$prefixer = new Autoprefixer(); |
125
|
|
|
|
126
|
|
|
if (is_string($this->autoprefix) || is_array($this->autoprefix)) |
127
|
|
|
{ |
128
|
|
|
$prefixer->setBrowsers($this->autoprefix); |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
$source = $prefixer->compile($source); |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
// Return the css source with correct paths. |
135
|
|
|
return $source; |
136
|
|
|
} |
137
|
|
|
} |
138
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.