File indexing completed on 2024-12-22 05:36:37
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Dojo 0017 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0018 * @license http://framework.zend.com/license/new-bsd New BSD License 0019 * @version $Id$ 0020 */ 0021 0022 /** 0023 * Dojo module layer and custom build profile generation support 0024 * 0025 * @package Zend_Dojo 0026 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0027 * @license http://framework.zend.com/license/new-bsd New BSD License 0028 */ 0029 class Zend_Dojo_BuildLayer 0030 { 0031 /** 0032 * Flag: whether or not to consume JS aggregated in the dojo() view 0033 * helper when generate the module layer contents 0034 * @var bool 0035 */ 0036 protected $_consumeJavascript = false; 0037 0038 /** 0039 * Flag: whether or not to consume dojo.addOnLoad events registered 0040 * with the dojo() view helper when generating the module layer file 0041 * contents 0042 * @var bool 0043 */ 0044 protected $_consumeOnLoad = false; 0045 0046 /** 0047 * Dojo view helper reference 0048 * @var Zend_Dojo_View_Helper_Dojo_Container 0049 */ 0050 protected $_dojo; 0051 0052 /** 0053 * Name of the custom layer to generate 0054 * @var string 0055 */ 0056 protected $_layerName; 0057 0058 /** 0059 * Path to the custom layer script relative to dojo.js (used when 0060 * creating the build profile) 0061 * @var string 0062 */ 0063 protected $_layerScriptPath; 0064 0065 /** 0066 * Build profile options 0067 * @var array 0068 */ 0069 protected $_profileOptions = array( 0070 'action' => 'release', 0071 'optimize' => 'shrinksafe', 0072 'layerOptimize' => 'shrinksafe', 0073 'copyTests' => false, 0074 'loader' => 'default', 0075 'cssOptimize' => 'comments', 0076 ); 0077 0078 /** 0079 * Associative array of module/path pairs for the build profile 0080 * @var array 0081 */ 0082 protected $_profilePrefixes = array(); 0083 0084 /** 0085 * Zend_View reference 0086 * @var Zend_View_Interface 0087 */ 0088 protected $_view; 0089 0090 /** 0091 * Constructor 0092 * 0093 * @param array|Zend_Config $options 0094 * @return void 0095 * @throws Zend_Dojo_Exception for invalid option argument 0096 */ 0097 public function __construct($options = null) 0098 { 0099 if (null !== $options) { 0100 if ($options instanceof Zend_Config) { 0101 $options = $options->toArray(); 0102 } elseif (!is_array($options)) { 0103 // require_once 'Zend/Dojo/Exception.php'; 0104 throw new Zend_Dojo_Exception('Invalid options provided to constructor'); 0105 } 0106 $this->setOptions($options); 0107 } 0108 } 0109 0110 /** 0111 * Set options 0112 * 0113 * Proxies to any setter that matches an option key. 0114 * 0115 * @param array $options 0116 * @return Zend_Dojo_BuildLayer 0117 */ 0118 public function setOptions(array $options) 0119 { 0120 $methods = get_class_methods($this); 0121 foreach ($options as $key => $value) { 0122 $method = 'set' . ucfirst($key); 0123 if (in_array($method, $methods)) { 0124 $this->$method($value); 0125 } 0126 } 0127 return $this; 0128 } 0129 0130 /** 0131 * Set View object 0132 * 0133 * @param Zend_View_Interface $view 0134 * @return Zend_Dojo_BuildLayer 0135 */ 0136 public function setView(Zend_View_Interface $view) 0137 { 0138 $this->_view = $view; 0139 return $this; 0140 } 0141 0142 /** 0143 * Retrieve view object 0144 * 0145 * @return Zend_View_Interface|null 0146 */ 0147 public function getView() 0148 { 0149 return $this->_view; 0150 } 0151 0152 /** 0153 * Set dojo() view helper instance 0154 * 0155 * @param Zend_Dojo_View_Helper_Dojo_Container $helper 0156 * @return Zend_Dojo_BuildLayer 0157 */ 0158 public function setDojoHelper(Zend_Dojo_View_Helper_Dojo_Container $helper) 0159 { 0160 $this->_dojo = $helper; 0161 return $this; 0162 } 0163 0164 /** 0165 * Retrieve dojo() view helper instance 0166 * 0167 * Will retrieve it from the view object if not registered. 0168 * 0169 * @return Zend_Dojo_View_Helper_Dojo_Container 0170 * @throws Zend_Dojo_Exception if not registered and no view object found 0171 */ 0172 public function getDojoHelper() 0173 { 0174 if (null === $this->_dojo) { 0175 if (null === ($view = $this->getView())) { 0176 // require_once 'Zend/Dojo/Exception.php'; 0177 throw new Zend_Dojo_Exception('View object not registered; cannot retrieve dojo helper'); 0178 } 0179 $helper = $view->getHelper('dojo'); 0180 $this->setDojoHelper($view->dojo()); 0181 } 0182 return $this->_dojo; 0183 } 0184 0185 /** 0186 * Set custom layer name; e.g. "custom.main" 0187 * 0188 * @param string $name 0189 * @return Zend_Dojo_BuildLayer 0190 */ 0191 public function setLayerName($name) 0192 { 0193 if (!preg_match('/^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/i', $name)) { 0194 // require_once 'Zend/Dojo/Exception.php'; 0195 throw new Zend_Dojo_Exception('Invalid layer name provided; must be of form[a-z][a-z0-9_](\.[a-z][a-z0-9_])+'); 0196 } 0197 $this->_layerName = $name; 0198 return $this; 0199 } 0200 0201 /** 0202 * Retrieve custom layer name 0203 * 0204 * @return string|null 0205 */ 0206 public function getLayerName() 0207 { 0208 return $this->_layerName; 0209 } 0210 0211 /** 0212 * Set the path to the custom layer script 0213 * 0214 * Should be a path relative to dojo.js 0215 * 0216 * @param string $path 0217 * @return Zend_Dojo_BuildLayer 0218 */ 0219 public function setLayerScriptPath($path) 0220 { 0221 $this->_layerScriptPath = (string) $path; 0222 return $this; 0223 } 0224 0225 /** 0226 * Get custom layer script path 0227 * 0228 * @return string|null 0229 */ 0230 public function getLayerScriptPath() 0231 { 0232 return $this->_layerScriptPath; 0233 } 0234 0235 /** 0236 * Set flag indicating whether or not to consume JS aggregated in dojo() 0237 * view helper 0238 * 0239 * @param bool $flag 0240 * @return Zend_Dojo_BuildLayer 0241 */ 0242 public function setConsumeJavascript($flag) 0243 { 0244 $this->_consumeJavascript = (bool) $flag; 0245 return $this; 0246 } 0247 0248 /** 0249 * Get flag indicating whether or not to consume JS aggregated in dojo() 0250 * view helper 0251 * 0252 * @return bool 0253 */ 0254 public function consumeJavascript() 0255 { 0256 return $this->_consumeJavascript; 0257 } 0258 0259 /** 0260 * Set flag indicating whether or not to consume dojo.addOnLoad events 0261 * aggregated in dojo() view helper 0262 * 0263 * @param bool $flag 0264 * @return Zend_Dojo_BuildLayer 0265 */ 0266 public function setConsumeOnLoad($flag) 0267 { 0268 $this->_consumeOnLoad = (bool) $flag; 0269 return $this; 0270 } 0271 0272 /** 0273 * Get flag indicating whether or not to consume dojo.addOnLoad events aggregated in dojo() view helper 0274 * 0275 * @return bool 0276 */ 0277 public function consumeOnLoad() 0278 { 0279 return $this->_consumeOnLoad; 0280 } 0281 0282 /** 0283 * Set many build profile options at once 0284 * 0285 * @param array $options 0286 * @return Zend_Dojo_BuildLayer 0287 */ 0288 public function setProfileOptions(array $options) 0289 { 0290 $this->_profileOptions += $options; 0291 return $this; 0292 } 0293 0294 /** 0295 * Add many build profile options at once 0296 * 0297 * @param array $options 0298 * @return Zend_Dojo_BuildLayer 0299 */ 0300 public function addProfileOptions(array $options) 0301 { 0302 $this->_profileOptions = $this->_profileOptions + $options; 0303 return $this; 0304 } 0305 0306 /** 0307 * Add a single build profile option 0308 * 0309 * @param string $key 0310 * @param value $value 0311 * @return Zend_Dojo_BuildLayer 0312 */ 0313 public function addProfileOption($key, $value) 0314 { 0315 $this->_profileOptions[(string) $key] = $value; 0316 return $this; 0317 } 0318 0319 /** 0320 * Is a given build profile option set? 0321 * 0322 * @param string $key 0323 * @return bool 0324 */ 0325 public function hasProfileOption($key) 0326 { 0327 return array_key_exists((string) $key, $this->_profileOptions); 0328 } 0329 0330 /** 0331 * Retrieve a single build profile option 0332 * 0333 * Returns null if profile option does not exist. 0334 * 0335 * @param string $key 0336 * @return mixed 0337 */ 0338 public function getProfileOption($key) 0339 { 0340 if ($this->hasProfileOption($key)) { 0341 return $this->_profileOptions[(string) $key]; 0342 } 0343 return null; 0344 } 0345 0346 /** 0347 * Get all build profile options 0348 * 0349 * @return array 0350 */ 0351 public function getProfileOptions() 0352 { 0353 return $this->_profileOptions; 0354 } 0355 0356 /** 0357 * Remove a build profile option 0358 * 0359 * @param string $name 0360 * @return Zend_Dojo_BuildLayer 0361 */ 0362 public function removeProfileOption($name) 0363 { 0364 if ($this->hasProfileOption($name)) { 0365 unset($this->_profileOptions[(string) $name]); 0366 } 0367 return $this; 0368 } 0369 0370 /** 0371 * Remove all build profile options 0372 * 0373 * @return Zend_Dojo_BuildLayer 0374 */ 0375 public function clearProfileOptions() 0376 { 0377 $this->_profileOptions = array(); 0378 return $this; 0379 } 0380 0381 /** 0382 * Add a build profile dependency prefix 0383 * 0384 * If just the prefix is passed, sets path to "../$prefix". 0385 * 0386 * @param string $prefix 0387 * @param null|string $path 0388 * @return Zend_Dojo_BuildLayer 0389 */ 0390 public function addProfilePrefix($prefix, $path = null) 0391 { 0392 if (null === $path) { 0393 $path = '../' . $prefix; 0394 } 0395 $this->_profilePrefixes[$prefix] = array($prefix, $path); 0396 return $this; 0397 } 0398 0399 /** 0400 * Set multiple dependency prefixes for bulid profile 0401 * 0402 * @param array $prefixes 0403 * @return Zend_Dojo_BuildLayer 0404 */ 0405 public function setProfilePrefixes(array $prefixes) 0406 { 0407 foreach ($prefixes as $prefix => $path) { 0408 $this->addProfilePrefix($prefix, $path); 0409 } 0410 return $this; 0411 } 0412 0413 /** 0414 * Get build profile dependency prefixes 0415 * 0416 * @return array 0417 */ 0418 public function getProfilePrefixes() 0419 { 0420 $layerName = $this->getLayerName(); 0421 if (null !== $layerName) { 0422 $prefix = $this->_getPrefix($layerName); 0423 if (!array_key_exists($prefix, $this->_profilePrefixes)) { 0424 $this->addProfilePrefix($prefix); 0425 } 0426 } 0427 $view = $this->getView(); 0428 if (!empty($view)) { 0429 $helper = $this->getDojoHelper(); 0430 if ($helper) { 0431 $modules = $helper->getModules(); 0432 foreach ($modules as $module) { 0433 $prefix = $this->_getPrefix($module); 0434 if (!array_key_exists($prefix, $this->_profilePrefixes)) { 0435 $this->addProfilePrefix($prefix); 0436 } 0437 } 0438 } 0439 } 0440 return $this->_profilePrefixes; 0441 } 0442 0443 /** 0444 * Generate module layer script 0445 * 0446 * @return string 0447 */ 0448 public function generateLayerScript() 0449 { 0450 $helper = $this->getDojoHelper(); 0451 $layerName = $this->getLayerName(); 0452 $modulePaths = $helper->getModulePaths(); 0453 $modules = $helper->getModules(); 0454 $onLoadActions = $helper->getOnLoadActions(); 0455 $javascript = $helper->getJavascript(); 0456 0457 $content = 'dojo.provide("' . $layerName . '");' . "\n\n(function(){\n"; 0458 0459 foreach ($modulePaths as $module => $path) { 0460 $content .= sprintf("dojo.registerModulePath(\"%s\", \"%s\");\n", $module, $path); 0461 } 0462 foreach ($modules as $module) { 0463 $content .= sprintf("dojo.require(\"%s\");\n", $module); 0464 } 0465 0466 if ($this->consumeOnLoad()) { 0467 foreach ($helper->getOnLoadActions() as $callback) { 0468 $content .= sprintf("dojo.addOnLoad(%s);\n", $callback); 0469 } 0470 } 0471 if ($this->consumeJavascript()) { 0472 $javascript = implode("\n", $helper->getJavascript()); 0473 if (!empty($javascript)) { 0474 $content .= "\n" . $javascript . "\n"; 0475 } 0476 } 0477 0478 $content .= "})();"; 0479 0480 return $content; 0481 } 0482 0483 /** 0484 * Generate build profile 0485 * 0486 * @return string 0487 */ 0488 public function generateBuildProfile() 0489 { 0490 $profileOptions = $this->getProfileOptions(); 0491 $layerName = $this->getLayerName(); 0492 $layerScriptPath = $this->getLayerScriptPath(); 0493 $profilePrefixes = $this->getProfilePrefixes(); 0494 0495 if (!array_key_exists('releaseName', $profileOptions)) { 0496 $profileOptions['releaseName'] = substr($layerName, 0, strpos($layerName, '.')); 0497 } 0498 0499 $profile = $profileOptions; 0500 $profile['layers'] = array(array( 0501 'name' => $layerScriptPath, 0502 'layerDependencies' => array(), 0503 'dependencies' => array($layerName), 0504 )); 0505 $profile['prefixes'] = array_values($profilePrefixes); 0506 0507 return 'dependencies = ' . $this->_filterJsonProfileToJavascript($profile) . ';'; 0508 } 0509 0510 /** 0511 * Retrieve module prefix 0512 * 0513 * @param string $module 0514 * @return void 0515 */ 0516 protected function _getPrefix($module) 0517 { 0518 $segments = explode('.', $module, 2); 0519 return $segments[0]; 0520 } 0521 0522 /** 0523 * Filter a JSON build profile to JavaScript 0524 * 0525 * @param string $profile 0526 * @return string 0527 */ 0528 protected function _filterJsonProfileToJavascript($profile) 0529 { 0530 // require_once 'Zend/Json.php'; 0531 $profile = Zend_Json::encode($profile); 0532 $profile = trim($profile, '"'); 0533 $profile = preg_replace('/' . preg_quote('\\') . '/', '', $profile); 0534 return $profile; 0535 } 0536 }