Created
January 10, 2013 15:40
-
-
Save piotrbelina/4502949 to your computer and use it in GitHub Desktop.
Bootstrap generator for Magento
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
* This file is part of the Symfony package. | |
* | |
* (c) Fabien Potencier <[email protected]> | |
* | |
* For the full copyright and license information, please view the LICENSE | |
* file that was distributed with this source code. | |
*/ | |
/** | |
* ClassCollectionLoader. | |
* | |
* @author Fabien Potencier <[email protected]> | |
*/ | |
class ClassCollectionLoader | |
{ | |
private static $loaded; | |
private static $seen; | |
private static $useTokenizer = true; | |
/** | |
* Loads a list of classes and caches them in one big file. | |
* | |
* @param array $classes An array of classes to load | |
* @param string $cacheDir A cache directory | |
* @param string $name The cache name prefix | |
* @param Boolean $autoReload Whether to flush the cache when the cache is stale or not | |
* @param Boolean $adaptive Whether to remove already declared classes or not | |
* @param string $extension File extension of the resulting file | |
* | |
* @throws \InvalidArgumentException When class can't be loaded | |
*/ | |
public static function load($classes, $cacheDir, $name, $autoReload, $adaptive = false, $extension = '.php') | |
{ | |
// each $name can only be loaded once per PHP process | |
if (isset(self::$loaded[$name])) { | |
return; | |
} | |
self::$loaded[$name] = true; | |
$declared = array_merge(get_declared_classes(), get_declared_interfaces()); | |
if (function_exists('get_declared_traits')) { | |
$declared = array_merge($declared, get_declared_traits()); | |
} | |
if ($adaptive) { | |
// don't include already declared classes | |
$classes = array_diff($classes, $declared); | |
// the cache is different depending on which classes are already declared | |
$name = $name.'-'.substr(md5(implode('|', $classes)), 0, 5); | |
} | |
$classes = array_unique($classes); | |
$cache = $cacheDir.'/'.$name.$extension; | |
// auto-reload | |
$reload = false; | |
if ($autoReload) { | |
$metadata = $cacheDir.'/'.$name.$extension.'.meta'; | |
if (!is_file($metadata) || !is_file($cache)) { | |
$reload = true; | |
} else { | |
$time = filemtime($cache); | |
$meta = unserialize(file_get_contents($metadata)); | |
sort($meta[1]); | |
sort($classes); | |
if ($meta[1] != $classes) { | |
$reload = true; | |
} else { | |
foreach ($meta[0] as $resource) { | |
if (!is_file($resource) || filemtime($resource) > $time) { | |
$reload = true; | |
break; | |
} | |
} | |
} | |
} | |
} | |
if (!$reload && is_file($cache)) { | |
require_once $cache; | |
return; | |
} | |
$files = array(); | |
$content = ''; | |
foreach (self::getOrderedClasses($classes) as $class) { | |
if (in_array($class->getName(), $declared)) { | |
continue; | |
} | |
$files[] = $class->getFileName(); | |
$c = preg_replace(array('/^\s*<\?php/', '/\?>\s*$/'), '', file_get_contents($class->getFileName())); | |
// add namespace declaration for global code | |
if (!$class->inNamespace()) { | |
$c = "\nnamespace\n{\n".self::stripComments($c)."\n}\n"; | |
} else { | |
$c = self::fixNamespaceDeclarations('<?php '.$c); | |
$c = preg_replace('/^\s*<\?php/', '', $c); | |
} | |
$content .= $c; | |
} | |
// cache the core classes | |
if (!is_dir(dirname($cache))) { | |
mkdir(dirname($cache), 0777, true); | |
} | |
self::writeCacheFile($cache, '<?php '.$content); | |
if ($autoReload) { | |
// save the resources | |
self::writeCacheFile($metadata, serialize(array($files, $classes))); | |
} | |
} | |
/** | |
* Adds brackets around each namespace if it's not already the case. | |
* | |
* @param string $source Namespace string | |
* | |
* @return string Namespaces with brackets | |
*/ | |
public static function fixNamespaceDeclarations($source) | |
{ | |
if (!function_exists('token_get_all') || !self::$useTokenizer) { | |
if (preg_match('/namespace(.*?)\s*;/', $source)) { | |
$source = preg_replace('/namespace(.*?)\s*;/', "namespace$1\n{", $source)."}\n"; | |
} | |
return $source; | |
} | |
$output = ''; | |
$inNamespace = false; | |
$tokens = token_get_all($source); | |
for ($i = 0, $max = count($tokens); $i < $max; $i++) { | |
$token = $tokens[$i]; | |
if (is_string($token)) { | |
$output .= $token; | |
} elseif (in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) { | |
// strip comments | |
continue; | |
} elseif (T_NAMESPACE === $token[0]) { | |
if ($inNamespace) { | |
$output .= "}\n"; | |
} | |
$output .= $token[1]; | |
// namespace name and whitespaces | |
while (($t = $tokens[++$i]) && is_array($t) && in_array($t[0], array(T_WHITESPACE, T_NS_SEPARATOR, T_STRING))) { | |
$output .= $t[1]; | |
} | |
if (is_string($t) && '{' === $t) { | |
$inNamespace = false; | |
--$i; | |
} else { | |
$output = rtrim($output); | |
$output .= "\n{"; | |
$inNamespace = true; | |
} | |
} else { | |
$output .= $token[1]; | |
} | |
} | |
if ($inNamespace) { | |
$output .= "}\n"; | |
} | |
return $output; | |
} | |
/** | |
* Writes a cache file. | |
* | |
* @param string $file Filename | |
* @param string $content Temporary file content | |
* | |
* @throws \RuntimeException when a cache file cannot be written | |
*/ | |
private static function writeCacheFile($file, $content) | |
{ | |
$tmpFile = tempnam(dirname($file), basename($file)); | |
if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $file)) { | |
@chmod($file, 0666 & ~umask()); | |
return; | |
} | |
throw new RuntimeException(sprintf('Failed to write cache file "%s".', $file)); | |
} | |
/** | |
* Removes comments from a PHP source string. | |
* | |
* We don't use the PHP php_strip_whitespace() function | |
* as we want the content to be readable and well-formatted. | |
* | |
* @param string $source A PHP string | |
* | |
* @return string The PHP string with the comments removed | |
*/ | |
private static function stripComments($source) | |
{ | |
if (!function_exists('token_get_all')) { | |
return $source; | |
} | |
$output = ''; | |
foreach (token_get_all($source) as $token) { | |
if (is_string($token)) { | |
$output .= $token; | |
} elseif (!in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) { | |
$output .= $token[1]; | |
} | |
} | |
// replace multiple new lines with a single newline | |
$output = preg_replace(array('/\s+$/Sm', '/\n+/S'), "\n", $output); | |
return $output; | |
} | |
/** | |
* Gets an ordered array of passed classes including all their dependencies. | |
* | |
* @param array $classes | |
* | |
* @return array An array of sorted \ReflectionClass instances (dependencies added if needed) | |
* | |
* @throws \InvalidArgumentException When a class can't be loaded | |
*/ | |
private static function getOrderedClasses(array $classes) | |
{ | |
$map = array(); | |
self::$seen = array(); | |
foreach ($classes as $class) { | |
try { | |
$reflectionClass = new \ReflectionClass($class); | |
} catch (\ReflectionException $e) { | |
throw new \InvalidArgumentException(sprintf('Unable to load class "%s"', $class)); | |
} | |
$map = array_merge($map, self::getClassHierarchy($reflectionClass)); | |
} | |
return $map; | |
} | |
private static function getClassHierarchy(ReflectionClass $class) | |
{ | |
if (isset(self::$seen[$class->getName()])) { | |
return array(); | |
} | |
self::$seen[$class->getName()] = true; | |
$classes = array($class); | |
$parent = $class; | |
while (($parent = $parent->getParentClass()) && $parent->isUserDefined() && !isset(self::$seen[$parent->getName()])) { | |
self::$seen[$parent->getName()] = true; | |
array_unshift($classes, $parent); | |
} | |
if (function_exists('get_declared_traits')) { | |
foreach ($classes as $c) { | |
foreach (self::getTraits($c) as $trait) { | |
self::$seen[$trait->getName()] = true; | |
array_unshift($classes, $trait); | |
} | |
} | |
} | |
return array_merge(self::getInterfaces($class), $classes); | |
} | |
private static function getInterfaces(ReflectionClass $class) | |
{ | |
$classes = array(); | |
foreach ($class->getInterfaces() as $interface) { | |
$classes = array_merge($classes, self::getInterfaces($interface)); | |
} | |
if ($class->isUserDefined() && $class->isInterface() && !isset(self::$seen[$class->getName()])) { | |
self::$seen[$class->getName()] = true; | |
$classes[] = $class; | |
} | |
return $classes; | |
} | |
private static function getTraits(ReflectionClass $class) | |
{ | |
$traits = $class->getTraits(); | |
$classes = array(); | |
while ($trait = array_pop($traits)) { | |
if ($trait->isUserDefined() && !isset(self::$seen[$trait->getName()])) { | |
$classes[] = $trait; | |
$traits = array_merge($traits, $trait->getTraits()); | |
} | |
} | |
return $classes; | |
} | |
/** | |
* This method is only useful for testing. | |
*/ | |
public static function enableTokenizer($bool) | |
{ | |
self::$useTokenizer = (Boolean) $bool; | |
} | |
} | |
function doBuildBootstrap($appDir) | |
{ | |
$file = $appDir.'/bootstrap.php.cache'; | |
if (file_exists($file)) { | |
unlink($file); | |
} | |
ClassCollectionLoader::load(array( | |
164 => 'Varien_Profiler', | |
165 => 'Mage_Core_Model_App', | |
166 => 'Varien_Event_Collection', | |
167 => 'Varien_Event_Observer_Collection', | |
168 => 'Varien_Simplexml_Config', | |
169 => 'Mage_Core_Model_Config_Base', | |
170 => 'Mage_Core_Model_Config', | |
171 => 'Mage_Core_Model_Locale', | |
172 => 'Varien_Simplexml_Element', | |
173 => 'Mage_Core_Model_Config_Element', | |
174 => 'Mage_Core_Model_Cache', | |
175 => 'Zend_Cache', | |
176 => 'Zend_Cache_Backend', | |
177 => 'Zend_Cache_Core', | |
178 => 'Varien_Cache_Core', | |
179 => 'Mage_Core_Model_App_Area', | |
180 => 'Mage_Core_Model_Resource_Abstract', | |
181 => 'Mage_Core_Model_Mysql4_Abstract', | |
182 => 'Mage_Core_Model_Mysql4_Website', | |
183 => 'Mage_Core_Model_Resource', | |
184 => 'Mage_Core_Model_Resource_Type_Abstract', | |
185 => 'Mage_Core_Model_Resource_Type_Db', | |
186 => 'Mage_Core_Model_Resource_Type_Db_Pdo_Mysql', | |
187 => 'Zend_Db_Adapter_Abstract', | |
188 => 'Zend_Db_Adapter_Pdo_Abstract', | |
189 => 'Zend_Db_Adapter_Pdo_Mysql', | |
190 => 'Varien_Db_Adapter_Pdo_Mysql', | |
191 => 'Zend_Db', | |
192 => 'Zend_Db_Select', | |
193 => 'Varien_Db_Select', | |
194 => 'Varien_Object', | |
195 => 'Mage_Core_Model_Config_Options', | |
196 => 'Mage_Core_Model_Abstract', | |
197 => 'Mage_Core_Model_Website', | |
198 => 'Varien_Data_Collection', | |
199 => 'Varien_Data_Collection_Db', | |
200 => 'Mage_Core_Model_Mysql4_Collection_Abstract', | |
201 => 'Mage_Core_Model_Mysql4_Website_Collection', | |
202 => 'Zend_Db_Statement', | |
203 => 'Zend_Db_Statement_Pdo', | |
205 => 'Enterprise_PageCache_Model_Processor', | |
207 => 'Mage_Core_Model_Store_Group', | |
208 => 'Mage_Core_Model_Mysql4_Store_Group', | |
209 => 'Mage_Core_Model_Mysql4_Store_Group_Collection', | |
210 => 'Mage_Core_Model_Store', | |
211 => 'Mage_Core_Model_Mysql4_Store', | |
212 => 'Mage_Core_Model_Mysql4_Store_Collection', | |
213 => 'Zend_Db_Expr', | |
214 => 'Mage_Core_Model_Cookie', | |
216 => 'Zend_Controller_Request_Abstract', | |
217 => 'Zend_Controller_Request_Http', | |
218 => 'Mage_Core_Controller_Request_Http', | |
219 => 'Mage_Core_Model_Resource_Setup', | |
220 => 'Mage_Core_Controller_Varien_Front', | |
221 => 'Varien_Event', | |
222 => 'Varien_Event_Observer', | |
223 => 'Enterprise_Staging_Model_Observer', | |
224 => 'Magentix_RewritingFilters_Model_Observer', | |
225 => 'Mage_Core_Controller_Varien_Router_Abstract', | |
226 => 'Mage_Core_Controller_Varien_Router_Standard', | |
227 => 'Mage_Core_Controller_Varien_Router_Admin', | |
228 => 'Mage_Cms_Controller_Router', | |
229 => 'Magentix_RewritingFilters_Controller_Router', | |
230 => 'Mage_Core_Controller_Varien_Router_Default', | |
231 => 'Mage_Core_Model_Url_Rewrite', | |
232 => 'Zend_Controller_Response_Abstract', | |
233 => 'Zend_Controller_Response_Http', | |
234 => 'Mage_Core_Controller_Response_Http', | |
235 => 'Mage_Core_Model_Mysql4_Url_Rewrite', | |
236 => 'Mage_Core_Controller_Varien_Action', | |
237 => 'Mage_Core_Controller_Front_Action', | |
239 => 'Mage_Core_Model_Layout', | |
240 => 'Mage_Core_Model_Layout_Element', | |
241 => 'Mage_Core_Model_Layout_Update', | |
242 => 'Mage_Core_Model_Session_Abstract_Varien', | |
243 => 'Mage_Core_Model_Session_Abstract', | |
244 => 'Mage_Core_Model_Session', | |
245 => 'Mage_Core_Model_Message_Collection', | |
246 => 'Mage_Core_Helper_Abstract', | |
247 => 'Mage_Core_Helper_Http', | |
248 => 'Mage_Core_Model_Design_Package', | |
249 => 'Fooman_SpeedsterEnterprise_Model_Core_Design_Package', | |
250 => 'Mage_Core_Model_Design', | |
251 => 'Mage_Core_Model_Mysql4_Design', | |
252 => 'Varien_Exception', | |
253 => 'Mage_Core_Model_Translate', | |
254 => 'Mage_Core_Model_Translate_Inline', | |
256 => 'Mage_Log_Model_Visitor', | |
257 => 'Mage_Core_Helper_String', | |
258 => 'Mage_Log_Model_Mysql4_Visitor', | |
259 => 'Enterprise_WebsiteRestriction_Model_Observer', | |
261 => 'Enterprise_PageCache_Model_Observer', | |
263 => 'Enterprise_PageCache_Model_Config', | |
270 => 'Mage_Page_Helper_Layout', | |
271 => 'Mage_Page_Model_Config', | |
272 => 'Mage_Page_Helper_Data', | |
273 => 'Mage_Core_Model_Translate_Expr', | |
295 => 'Mage_Core_Block_Abstract', | |
296 => 'Mage_Core_Block_Template', | |
297 => 'Mage_Page_Block_Html', | |
298 => 'Mage_Page_Block_Html_Head', | |
), dirname($file), basename($file, '.php.cache'), false, false, '.php.cache'); | |
file_put_contents($file, sprintf("<?php | |
//namespace { \$loader = require_once __DIR__.'/autoload.php'; } | |
%s | |
//namespace { return \$loader; } | |
", substr(file_get_contents($file), 5))); | |
} | |
require_once __DIR__ . '/../lib/Varien/Autoload.php'; | |
define('DS', DIRECTORY_SEPARATOR); | |
define('PS', PATH_SEPARATOR); | |
define('BP', dirname(dirname(__FILE__))); | |
$paths[] = BP . DS . 'app' . DS . 'code' . DS . 'local'; | |
$paths[] = BP . DS . 'app' . DS . 'code' . DS . 'community'; | |
$paths[] = BP . DS . 'app' . DS . 'code' . DS . 'core'; | |
$paths[] = BP . DS . 'lib'; | |
$appPath = implode(PS, $paths); | |
set_include_path($appPath . PS . get_include_path()); | |
Varien_Autoload::register(); | |
doBuildBootstrap(__DIR__ . '/../app/'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment