1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
26:
27: 28: 29: 30: 31: 32: 33:
34:
35: class Mage_Compiler_Model_Process
36: {
37: protected $_compileDir = null;
38: protected $_includeDir = null;
39: protected $_statDir = null;
40: protected $_compileConfig = null;
41: protected $_includePaths = array();
42: protected $_processedClasses= array();
43:
44: protected $_controllerFolders = array();
45:
46: public function __construct($options=array())
47: {
48: if (isset($options['compile_dir'])) {
49: $this->_compileDir = $options['compile_dir'];
50: } else {
51: $this->_compileDir = Mage::getBaseDir() . DS . 'includes';
52: }
53: $this->_includeDir = $this->_compileDir . DS . 'src';
54: $this->_statDir = $this->_compileDir . DS . 'stat';
55: }
56:
57: 58: 59: 60: 61:
62: public function getCompileConfig()
63: {
64: if ($this->_compileConfig === null) {
65: $this->_compileConfig = Mage::getConfig()->loadModulesConfiguration('compilation.xml');
66: }
67: return $this->_compileConfig;
68: }
69:
70: 71: 72: 73: 74:
75: protected function _getIncludePaths()
76: {
77: if (empty($this->_includePaths)) {
78: $originalPath = Mage::registry('original_include_path');
79: 80: 81:
82: if ($originalPath == '.') {
83: $path = get_include_path();
84: } else {
85: $path = str_replace($originalPath, '', get_include_path());
86: }
87:
88: $this->_includePaths = explode(PS, $path);
89: foreach ($this->_includePaths as $index => $path) {
90: if (empty($path) || $path == '.') {
91: unset($this->_includePaths[$index]);
92: }
93: }
94: }
95: return $this->_includePaths;
96: }
97:
98: 99: 100: 101: 102: 103: 104:
105: protected function _copy($source, $target, $firstIteration = true)
106: {
107: if (is_dir($source)) {
108: $dir = dir($source);
109: while (false !== ($file = $dir->read())) {
110: if (($file[0] == '.')) {
111: continue;
112: }
113: $sourceFile = $source . DS . $file;
114: if ($file == 'controllers') {
115: $this->_controllerFolders[] = $sourceFile;
116: continue;
117: }
118:
119: if ($firstIteration) {
120: $targetFile = $target . DS . $file;
121: } else {
122: $targetFile = $target . '_' . $file;
123: }
124: $this->_copy($sourceFile, $targetFile, false);
125: }
126: } else {
127: if (strpos(str_replace($this->_includeDir, '', $target), '-')
128: || !in_array(substr($source, strlen($source)-4, 4), array('.php'))) {
129: return $this;
130: }
131: copy($source, $target);
132: }
133: return $this;
134: }
135:
136: 137: 138: 139: 140: 141:
142: protected function _copyZendLocaleData($destDir)
143: {
144: $source = Mage::getBaseDir('lib').DS.'Zend'.DS.'Locale'.DS.'Data';
145: $dir = dir($source);
146: while (false !== ($file = $dir->read())) {
147: if (($file[0] == '.')) {
148: continue;
149: }
150: $sourceFile = $source . DS . $file;
151: $targetFile = $destDir . DS . $file;
152: copy($sourceFile, $targetFile);
153: }
154: return $this;
155: }
156:
157: 158: 159: 160: 161: 162:
163: protected function _copyControllers($basePath)
164: {
165: foreach ($this->_controllerFolders as $path) {
166: $relPath = str_replace($basePath, '', $path);
167: $relPath = trim($relPath, DS);
168: $arrDirs = explode(DS, $relPath);
169: $destPath = $this->_includeDir;
170: foreach ($arrDirs as $dir) {
171: $destPath.= DS.$dir;
172: $this->_mkdir($destPath);
173: }
174: $this->_copyAll($path, $destPath);
175: }
176: return $this;
177: }
178:
179: 180: 181: 182: 183: 184: 185:
186: protected function _copyAll($source, $target)
187: {
188: if (is_dir($source)) {
189: $this->_mkdir($target);
190: $dir = dir($source);
191: while (false !== ($file = $dir->read())) {
192: if (($file[0] == '.')) {
193: continue;
194: }
195: $sourceFile = $source . DS . $file;
196: $targetFile = $target . DS . $file;
197: $this->_copyAll($sourceFile, $targetFile);
198: }
199: } else {
200: if (!in_array(substr($source, strlen($source)-4, 4), array('.php'))) {
201: return $this;
202: }
203: copy($source, $target);
204: }
205: return $this;
206: }
207:
208: 209: 210: 211: 212: 213:
214: protected function _mkdir($dir)
215: {
216: if (!is_dir($dir)) {
217: mkdir($dir);
218: @chmod($dir, 0777);
219: }
220: return $dir;
221: }
222:
223: 224: 225: 226: 227: 228:
229: protected function _collectFiles()
230: {
231: $paths = $this->_getIncludePaths();
232: $paths = array_reverse($paths);
233: $destDir= $this->_includeDir;
234: $libDir = Mage::getBaseDir('lib');
235:
236: $this->_mkdir($destDir);
237: foreach ($paths as $path) {
238: $this->_controllerFolders = array();
239: $this->_copy($path, $destDir);
240: $this->_copyControllers($path);
241: if ($path == $libDir) {
242: $this->_copyAll($libDir, $destDir);
243: }
244: }
245:
246: $destDir.= DS.'Data';
247: $this->_mkdir($destDir);
248: $this->_copyZendLocaleData($destDir);
249: return $this;
250: }
251:
252: public function getCollectedFilesCount()
253: {
254: return count(glob($this->_includeDir.DS.'*'));
255: }
256:
257: public function getCompiledFilesCount()
258: {
259: return count(glob($this->_includeDir.DS.Varien_Autoload::SCOPE_FILE_PREFIX.'*'));
260: }
261:
262: public function getCompileClassList()
263: {
264: $arrFiles = array();
265: $statDir = $this->_statDir;
266: $statFiles= array();
267: if (is_dir($statDir)) {
268: $dir = dir($statDir);
269: while (false !== ($file = $dir->read())) {
270: if (($file[0] == '.')) {
271: continue;
272: }
273: $statFiles[str_replace('.csv', '', $file)] = $this->_statDir.DS.$file;
274: }
275: }
276:
277: foreach ($this->getCompileConfig()->getNode('includes')->children() as $code => $config) {
278: $classes = $config->asArray();
279: if (is_array($classes)) {
280: $arrFiles[$code] = array_keys($classes);
281: } else {
282: $arrFiles[$code] = array();
283: }
284:
285: $statClasses = array();
286: if (isset($statFiles[$code])) {
287: $statClasses = explode("\n", file_get_contents($statFiles[$code]));
288: $popularStatClasses = array();
289: foreach ($statClasses as $index => $classInfo) {
290: $classInfo = explode(':', $classInfo);
291: $popularStatClasses[$classInfo[1]][] = $classInfo[0];
292: }
293: ksort($popularStatClasses);
294: $statClasses = array_pop($popularStatClasses);
295: unset($statFiles[$code]);
296: }
297: $arrFiles[$code] = array_merge($arrFiles[$code], $statClasses);
298: $arrFiles[$code] = array_unique($arrFiles[$code]);
299: sort($arrFiles[$code]);
300: }
301:
302: foreach($statFiles as $code => $file) {
303: $classes = explode("\n", file_get_contents($file));
304: $popularStatClasses = array();
305: foreach ($classes as $index => $classInfo) {
306: $classInfo = explode(':', $classInfo);
307: $popularStatClasses[$classInfo[1]][] = $classInfo[0];
308: }
309: ksort($popularStatClasses);
310: $arrFiles[$code] = array_pop($popularStatClasses);
311: }
312: foreach ($arrFiles as $scope=>$classes) {
313: if ($scope != 'default') {
314: foreach ($classes as $index => $class) {
315: if (in_array($class, $arrFiles['default'])) {
316: unset($arrFiles[$scope][$index]);
317: }
318: }
319: }
320: }
321: return $arrFiles;
322: }
323:
324: 325: 326: 327: 328:
329: protected function _compileFiles()
330: {
331: $classesInfo = $this->getCompileClassList();
332:
333: foreach ($classesInfo as $code => $classes) {
334: $classesSorce = $this->_getClassesSourceCode($classes, $code);
335: file_put_contents($this->_includeDir.DS.Varien_Autoload::SCOPE_FILE_PREFIX.$code.'.php', $classesSorce);
336: }
337: return $this;
338: }
339:
340: protected function _getClassesSourceCode($classes, $scope)
341: {
342: $sortedClasses = array();
343: foreach ($classes as $className) {
344: $implements = array_reverse(class_implements($className));
345: foreach ($implements as $class) {
346: if (!in_array($class, $sortedClasses) && !in_array($class, $this->_processedClasses) && strstr($class, '_')) {
347: $sortedClasses[] = $class;
348: if ($scope == 'default') {
349: $this->_processedClasses[] = $class;
350: }
351: }
352: }
353: $extends = array_reverse(class_parents($className));
354: foreach ($extends as $class) {
355: if (!in_array($class, $sortedClasses) && !in_array($class, $this->_processedClasses) && strstr($class, '_')) {
356: $sortedClasses[] = $class;
357: if ($scope == 'default') {
358: $this->_processedClasses[] = $class;
359: }
360: }
361: }
362: if (!in_array($className, $sortedClasses) && !in_array($className, $this->_processedClasses)) {
363: $sortedClasses[] = $className;
364: if ($scope == 'default') {
365: $this->_processedClasses[] = $className;
366: }
367: }
368: }
369:
370: $classesSource = "<?php\n";
371: foreach ($sortedClasses as $className) {
372: $file = $this->_includeDir.DS.$className.'.php';
373: if (!file_exists($file)) {
374: continue;
375: }
376: $content = file_get_contents($file);
377: $content = ltrim($content, '<?php');
378: $content = rtrim($content, "\n\r\t?>");
379: $classesSource.= $content;
380: }
381: return $classesSource;
382: }
383:
384: public function clear()
385: {
386: $this->registerIncludePath(false);
387: if (is_dir($this->_includeDir)) {
388: mageDelTree($this->_includeDir);
389: }
390: return $this;
391: }
392:
393: 394: 395: 396: 397:
398: public function run()
399: {
400: $this->_collectFiles();
401: $this->_compileFiles();
402: $this->registerIncludePath();
403: return $this;
404:
405: }
406:
407: 408: 409: 410: 411: 412:
413: public function registerIncludePath($flag = true)
414: {
415: $file = $this->_compileDir.DS.'config.php';
416: if (is_writeable($file)) {
417: $content = file_get_contents($file);
418: $content = explode("\n", $content);
419: foreach ($content as $index => $line) {
420: if (strpos($line, 'COMPILER_INCLUDE_PATH')) {
421: if ($flag) {
422: $content[$index] = ltrim($line, '#');
423: } else {
424: $content[$index] = '#'.$line;
425: }
426: }
427: }
428: file_put_contents($file, implode("\n", $content));
429: }
430: return $this;
431: }
432:
433: 434: 435: 436: 437:
438: public function validate()
439: {
440: $result = array();
441: if (!is_writeable($this->_compileDir)) {
442: $result[] = Mage::helper('compiler')->__('Directory "%s" must be writeable', $this->_compileDir);
443: }
444: $file = $this->_compileDir.DS.'config.php';
445: if (!is_writeable($file)) {
446: $result[] = Mage::helper('compiler')->__('File "%s" must be writeable', $file);
447: }
448: return $result;
449: }
450:
451: }
452: