1: <?php
2:
3: namespace WebLoader;
4:
5: 6: 7: 8: 9:
10: class Compiler
11: {
12:
13:
14: private $outputDir;
15:
16:
17: private $joinFiles = true;
18:
19:
20: private $filters = array();
21:
22:
23: private $fileFilters = array();
24:
25:
26: private $collection;
27:
28:
29: private $namingConvention;
30:
31:
32: private $checkLastModified = true;
33:
34: public function __construct(IFileCollection $files, IOutputNamingConvention $convention, $outputDir)
35: {
36: $this->collection = $files;
37: $this->namingConvention = $convention;
38: $this->setOutputDir($outputDir);
39: }
40:
41: 42: 43: 44: 45: 46:
47: public static function createCssCompiler(IFileCollection $files, $outputDir)
48: {
49: return new static($files, DefaultOutputNamingConvention::createCssConvention(), $outputDir);
50: }
51:
52: 53: 54: 55: 56: 57:
58: public static function createJsCompiler(IFileCollection $files, $outputDir)
59: {
60: return new static($files, DefaultOutputNamingConvention::createJsConvention(), $outputDir);
61: }
62:
63: 64: 65: 66:
67: public function getOutputDir()
68: {
69: return $this->outputDir;
70: }
71:
72: 73: 74: 75:
76: public function setOutputDir($tempPath)
77: {
78: $tempPath = Path::normalize($tempPath);
79:
80: if (!is_dir($tempPath)) {
81: throw new FileNotFoundException('Temp path does not exist.');
82: }
83:
84: if (!is_writable($tempPath)) {
85: throw new InvalidArgumentException("Directory '$tempPath' is not writeable.");
86: }
87:
88: $this->outputDir = $tempPath;
89: }
90:
91: 92: 93: 94:
95: public function getJoinFiles()
96: {
97: return $this->joinFiles;
98: }
99:
100: 101: 102: 103:
104: public function setJoinFiles($joinFiles)
105: {
106: $this->joinFiles = (bool) $joinFiles;
107: }
108:
109: 110: 111: 112:
113: public function setCheckLastModified($checkLastModified)
114: {
115: $this->checkLastModified = (bool) $checkLastModified;
116: }
117:
118: 119: 120: 121: 122:
123: public function getLastModified(array $files = null)
124: {
125: if ($files === null) {
126: $files = $this->collection->getFiles();
127: }
128:
129: $modified = 0;
130:
131: foreach ($files as $file) {
132: $modified = max($modified, filemtime($file));
133: }
134:
135: return $modified;
136: }
137:
138: 139: 140: 141: 142:
143: public function getContent(array $files = null)
144: {
145: if ($files === null) {
146: $files = $this->collection->getFiles();
147: }
148:
149:
150: $content = '';
151: foreach ($files as $file) {
152: $content .= PHP_EOL . $this->loadFile($file);
153: }
154:
155:
156: foreach ($this->filters as $filter) {
157: $content = call_user_func($filter, $content, $this);
158: }
159:
160: return $content;
161: }
162:
163: 164: 165: 166: 167:
168: public function generate($ifModified = TRUE)
169: {
170: if ($this->joinFiles) {
171: return array(
172: $this->generateFiles($this->collection->getFiles(), $ifModified)
173: );
174: } else {
175: $arr = array();
176:
177: foreach ($this->collection->getFiles() as $file) {
178: $arr[] = $this->generateFiles(array($file), $ifModified);
179: }
180:
181: return $arr;
182: }
183: }
184:
185: protected function generateFiles(array $files, $ifModified)
186: {
187: $name = $this->namingConvention->getFilename($files, $this);
188: $path = $this->outputDir . '/' . $name;
189: $lastModified = $this->checkLastModified ? $this->getLastModified($files) : 0;
190:
191: if (!$ifModified || !file_exists($path) || $lastModified > filemtime($path)) {
192: $outPath = in_array('safe', stream_get_wrappers()) ? 'safe://' . $path : $path;
193: file_put_contents($outPath, $this->getContent($files));
194: }
195:
196: return (object) array(
197: 'file' => $name,
198: 'lastModified' => $lastModified,
199: 'sourceFiles' => $files,
200: );
201: }
202:
203: 204: 205: 206: 207:
208: protected function loadFile($file)
209: {
210: $content = file_get_contents($file);
211:
212: foreach ($this->fileFilters as $filter) {
213: $content = call_user_func($filter, $content, $this, $file);
214: }
215:
216: return $content;
217: }
218:
219: 220: 221:
222: public function getFileCollection()
223: {
224: return $this->collection;
225: }
226:
227: 228: 229:
230: public function getOutputNamingConvention()
231: {
232: return $this->namingConvention;
233: }
234:
235: 236: 237:
238: public function setFileCollection(IFileCollection $collection)
239: {
240: $this->collection = $collection;
241: }
242:
243: 244: 245:
246: public function setOutputNamingConvention(IOutputNamingConvention $namingConvention)
247: {
248: $this->namingConvention = $namingConvention;
249: }
250:
251: 252: 253: 254:
255: public function addFilter($filter)
256: {
257: if (!is_callable($filter)) {
258: throw new InvalidArgumentException('Filter is not callable.');
259: }
260:
261: $this->filters[] = $filter;
262: }
263:
264: 265: 266:
267: public function getFilters()
268: {
269: return $this->filters;
270: }
271:
272: 273: 274: 275:
276: public function addFileFilter($filter)
277: {
278: if (!is_callable($filter)) {
279: throw new InvalidArgumentException('Filter is not callable.');
280: }
281:
282: $this->fileFilters[] = $filter;
283: }
284:
285: 286: 287:
288: public function getFileFilters()
289: {
290: return $this->fileFilters;
291: }
292:
293: }
294: