|
1 <?php |
|
2 /** |
|
3 * Zend Framework |
|
4 * |
|
5 * LICENSE |
|
6 * |
|
7 * This source file is subject to the new BSD license that is bundled |
|
8 * with this package in the file LICENSE.txt. |
|
9 * It is also available through the world-wide-web at this URL: |
|
10 * http://framework.zend.com/license/new-bsd |
|
11 * If you did not receive a copy of the license and are unable to |
|
12 * obtain it through the world-wide-web, please send an email |
|
13 * to license@zend.com so we can send you a copy immediately. |
|
14 * |
|
15 * @category Zend |
|
16 * @package Zend_Dojo |
|
17 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
18 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
19 * @version $Id: BuildLayer.php 22280 2010-05-24 20:39:45Z matthew $ |
|
20 */ |
|
21 |
|
22 /** |
|
23 * Dojo module layer and custom build profile generation support |
|
24 * |
|
25 * @package Zend_Dojo |
|
26 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
27 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
28 */ |
|
29 class Zend_Dojo_BuildLayer |
|
30 { |
|
31 /** |
|
32 * Flag: whether or not to consume JS aggregated in the dojo() view |
|
33 * helper when generate the module layer contents |
|
34 * @var bool |
|
35 */ |
|
36 protected $_consumeJavascript = false; |
|
37 |
|
38 /** |
|
39 * Flag: whether or not to consume dojo.addOnLoad events registered |
|
40 * with the dojo() view helper when generating the module layer file |
|
41 * contents |
|
42 * @var bool |
|
43 */ |
|
44 protected $_consumeOnLoad = false; |
|
45 |
|
46 /** |
|
47 * Dojo view helper reference |
|
48 * @var Zend_Dojo_View_Helper_Dojo_Container |
|
49 */ |
|
50 protected $_dojo; |
|
51 |
|
52 /** |
|
53 * Name of the custom layer to generate |
|
54 * @var string |
|
55 */ |
|
56 protected $_layerName; |
|
57 |
|
58 /** |
|
59 * Path to the custom layer script relative to dojo.js (used when |
|
60 * creating the build profile) |
|
61 * @var string |
|
62 */ |
|
63 protected $_layerScriptPath; |
|
64 |
|
65 /** |
|
66 * Build profile options |
|
67 * @var array |
|
68 */ |
|
69 protected $_profileOptions = array( |
|
70 'action' => 'release', |
|
71 'optimize' => 'shrinksafe', |
|
72 'layerOptimize' => 'shrinksafe', |
|
73 'copyTests' => false, |
|
74 'loader' => 'default', |
|
75 'cssOptimize' => 'comments', |
|
76 ); |
|
77 |
|
78 /** |
|
79 * Associative array of module/path pairs for the build profile |
|
80 * @var array |
|
81 */ |
|
82 protected $_profilePrefixes = array(); |
|
83 |
|
84 /** |
|
85 * Zend_View reference |
|
86 * @var Zend_View_Interface |
|
87 */ |
|
88 protected $_view; |
|
89 |
|
90 /** |
|
91 * Constructor |
|
92 * |
|
93 * @param array|Zend_Config $options |
|
94 * @return void |
|
95 * @throws Zend_Dojo_Exception for invalid option argument |
|
96 */ |
|
97 public function __construct($options = null) |
|
98 { |
|
99 if (null !== $options) { |
|
100 if ($options instanceof Zend_Config) { |
|
101 $options = $options->toArray(); |
|
102 } elseif (!is_array($options)) { |
|
103 require_once 'Zend/Dojo/Exception.php'; |
|
104 throw new Zend_Dojo_Exception('Invalid options provided to constructor'); |
|
105 } |
|
106 $this->setOptions($options); |
|
107 } |
|
108 } |
|
109 |
|
110 /** |
|
111 * Set options |
|
112 * |
|
113 * Proxies to any setter that matches an option key. |
|
114 * |
|
115 * @param array $options |
|
116 * @return Zend_Dojo_BuildLayer |
|
117 */ |
|
118 public function setOptions(array $options) |
|
119 { |
|
120 $methods = get_class_methods($this); |
|
121 foreach ($options as $key => $value) { |
|
122 $method = 'set' . ucfirst($key); |
|
123 if (in_array($method, $methods)) { |
|
124 $this->$method($value); |
|
125 } |
|
126 } |
|
127 return $this; |
|
128 } |
|
129 |
|
130 /** |
|
131 * Set View object |
|
132 * |
|
133 * @param Zend_View_Interface $view |
|
134 * @return Zend_Dojo_BuildLayer |
|
135 */ |
|
136 public function setView(Zend_View_Interface $view) |
|
137 { |
|
138 $this->_view = $view; |
|
139 return $this; |
|
140 } |
|
141 |
|
142 /** |
|
143 * Retrieve view object |
|
144 * |
|
145 * @return Zend_View_Interface|null |
|
146 */ |
|
147 public function getView() |
|
148 { |
|
149 return $this->_view; |
|
150 } |
|
151 |
|
152 /** |
|
153 * Set dojo() view helper instance |
|
154 * |
|
155 * @param Zend_Dojo_View_Helper_Dojo_Container $helper |
|
156 * @return Zend_Dojo_BuildLayer |
|
157 */ |
|
158 public function setDojoHelper(Zend_Dojo_View_Helper_Dojo_Container $helper) |
|
159 { |
|
160 $this->_dojo = $helper; |
|
161 return $this; |
|
162 } |
|
163 |
|
164 /** |
|
165 * Retrieve dojo() view helper instance |
|
166 * |
|
167 * Will retrieve it from the view object if not registered. |
|
168 * |
|
169 * @return Zend_Dojo_View_Helper_Dojo_Container |
|
170 * @throws Zend_Dojo_Exception if not registered and no view object found |
|
171 */ |
|
172 public function getDojoHelper() |
|
173 { |
|
174 if (null === $this->_dojo) { |
|
175 if (null === ($view = $this->getView())) { |
|
176 require_once 'Zend/Dojo/Exception.php'; |
|
177 throw new Zend_Dojo_Exception('View object not registered; cannot retrieve dojo helper'); |
|
178 } |
|
179 $helper = $view->getHelper('dojo'); |
|
180 $this->setDojoHelper($view->dojo()); |
|
181 } |
|
182 return $this->_dojo; |
|
183 } |
|
184 |
|
185 /** |
|
186 * Set custom layer name; e.g. "custom.main" |
|
187 * |
|
188 * @param string $name |
|
189 * @return Zend_Dojo_BuildLayer |
|
190 */ |
|
191 public function setLayerName($name) |
|
192 { |
|
193 if (!preg_match('/^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/i', $name)) { |
|
194 require_once 'Zend/Dojo/Exception.php'; |
|
195 throw new Zend_Dojo_Exception('Invalid layer name provided; must be of form[a-z][a-z0-9_](\.[a-z][a-z0-9_])+'); |
|
196 } |
|
197 $this->_layerName = $name; |
|
198 return $this; |
|
199 } |
|
200 |
|
201 /** |
|
202 * Retrieve custom layer name |
|
203 * |
|
204 * @return string|null |
|
205 */ |
|
206 public function getLayerName() |
|
207 { |
|
208 return $this->_layerName; |
|
209 } |
|
210 |
|
211 /** |
|
212 * Set the path to the custom layer script |
|
213 * |
|
214 * Should be a path relative to dojo.js |
|
215 * |
|
216 * @param string $path |
|
217 * @return Zend_Dojo_BuildLayer |
|
218 */ |
|
219 public function setLayerScriptPath($path) |
|
220 { |
|
221 $this->_layerScriptPath = (string) $path; |
|
222 return $this; |
|
223 } |
|
224 |
|
225 /** |
|
226 * Get custom layer script path |
|
227 * |
|
228 * @return string|null |
|
229 */ |
|
230 public function getLayerScriptPath() |
|
231 { |
|
232 return $this->_layerScriptPath; |
|
233 } |
|
234 |
|
235 /** |
|
236 * Set flag indicating whether or not to consume JS aggregated in dojo() |
|
237 * view helper |
|
238 * |
|
239 * @param bool $flag |
|
240 * @return Zend_Dojo_BuildLayer |
|
241 */ |
|
242 public function setConsumeJavascript($flag) |
|
243 { |
|
244 $this->_consumeJavascript = (bool) $flag; |
|
245 return $this; |
|
246 } |
|
247 |
|
248 /** |
|
249 * Get flag indicating whether or not to consume JS aggregated in dojo() |
|
250 * view helper |
|
251 * |
|
252 * @return bool |
|
253 */ |
|
254 public function consumeJavascript() |
|
255 { |
|
256 return $this->_consumeJavascript; |
|
257 } |
|
258 |
|
259 /** |
|
260 * Set flag indicating whether or not to consume dojo.addOnLoad events |
|
261 * aggregated in dojo() view helper |
|
262 * |
|
263 * @param bool $flag |
|
264 * @return Zend_Dojo_BuildLayer |
|
265 */ |
|
266 public function setConsumeOnLoad($flag) |
|
267 { |
|
268 $this->_consumeOnLoad = (bool) $flag; |
|
269 return $this; |
|
270 } |
|
271 |
|
272 /** |
|
273 * Get flag indicating whether or not to consume dojo.addOnLoad events aggregated in dojo() view helper |
|
274 * |
|
275 * @return bool |
|
276 */ |
|
277 public function consumeOnLoad() |
|
278 { |
|
279 return $this->_consumeOnLoad; |
|
280 } |
|
281 |
|
282 /** |
|
283 * Set many build profile options at once |
|
284 * |
|
285 * @param array $options |
|
286 * @return Zend_Dojo_BuildLayer |
|
287 */ |
|
288 public function setProfileOptions(array $options) |
|
289 { |
|
290 $this->_profileOptions += $options; |
|
291 return $this; |
|
292 } |
|
293 |
|
294 /** |
|
295 * Add many build profile options at once |
|
296 * |
|
297 * @param array $options |
|
298 * @return Zend_Dojo_BuildLayer |
|
299 */ |
|
300 public function addProfileOptions(array $options) |
|
301 { |
|
302 $this->_profileOptions = $this->_profileOptions + $options; |
|
303 return $this; |
|
304 } |
|
305 |
|
306 /** |
|
307 * Add a single build profile option |
|
308 * |
|
309 * @param string $key |
|
310 * @param value $value |
|
311 * @return Zend_Dojo_BuildLayer |
|
312 */ |
|
313 public function addProfileOption($key, $value) |
|
314 { |
|
315 $this->_profileOptions[(string) $key] = $value; |
|
316 return $this; |
|
317 } |
|
318 |
|
319 /** |
|
320 * Is a given build profile option set? |
|
321 * |
|
322 * @param string $key |
|
323 * @return bool |
|
324 */ |
|
325 public function hasProfileOption($key) |
|
326 { |
|
327 return array_key_exists((string) $key, $this->_profileOptions); |
|
328 } |
|
329 |
|
330 /** |
|
331 * Retrieve a single build profile option |
|
332 * |
|
333 * Returns null if profile option does not exist. |
|
334 * |
|
335 * @param string $key |
|
336 * @return mixed |
|
337 */ |
|
338 public function getProfileOption($key) |
|
339 { |
|
340 if ($this->hasProfileOption($key)) { |
|
341 return $this->_profileOptions[(string) $key]; |
|
342 } |
|
343 return null; |
|
344 } |
|
345 |
|
346 /** |
|
347 * Get all build profile options |
|
348 * |
|
349 * @return array |
|
350 */ |
|
351 public function getProfileOptions() |
|
352 { |
|
353 return $this->_profileOptions; |
|
354 } |
|
355 |
|
356 /** |
|
357 * Remove a build profile option |
|
358 * |
|
359 * @param string $name |
|
360 * @return Zend_Dojo_BuildLayer |
|
361 */ |
|
362 public function removeProfileOption($name) |
|
363 { |
|
364 if ($this->hasProfileOption($name)) { |
|
365 unset($this->_profileOptions[(string) $name]); |
|
366 } |
|
367 return $this; |
|
368 } |
|
369 |
|
370 /** |
|
371 * Remove all build profile options |
|
372 * |
|
373 * @return Zend_Dojo_BuildLayer |
|
374 */ |
|
375 public function clearProfileOptions() |
|
376 { |
|
377 $this->_profileOptions = array(); |
|
378 return $this; |
|
379 } |
|
380 |
|
381 /** |
|
382 * Add a build profile dependency prefix |
|
383 * |
|
384 * If just the prefix is passed, sets path to "../$prefix". |
|
385 * |
|
386 * @param string $prefix |
|
387 * @param null|string $path |
|
388 * @return Zend_Dojo_BuildLayer |
|
389 */ |
|
390 public function addProfilePrefix($prefix, $path = null) |
|
391 { |
|
392 if (null === $path) { |
|
393 $path = '../' . $prefix; |
|
394 } |
|
395 $this->_profilePrefixes[$prefix] = array($prefix, $path); |
|
396 return $this; |
|
397 } |
|
398 |
|
399 /** |
|
400 * Set multiple dependency prefixes for bulid profile |
|
401 * |
|
402 * @param array $prefixes |
|
403 * @return Zend_Dojo_BuildLayer |
|
404 */ |
|
405 public function setProfilePrefixes(array $prefixes) |
|
406 { |
|
407 foreach ($prefixes as $prefix => $path) { |
|
408 $this->addProfilePrefix($prefix, $path); |
|
409 } |
|
410 return $this; |
|
411 } |
|
412 |
|
413 /** |
|
414 * Get build profile dependency prefixes |
|
415 * |
|
416 * @return array |
|
417 */ |
|
418 public function getProfilePrefixes() |
|
419 { |
|
420 $layerName = $this->getLayerName(); |
|
421 if (null !== $layerName) { |
|
422 $prefix = $this->_getPrefix($layerName); |
|
423 if (!array_key_exists($prefix, $this->_profilePrefixes)) { |
|
424 $this->addProfilePrefix($prefix); |
|
425 } |
|
426 } |
|
427 $view = $this->getView(); |
|
428 if (!empty($view)) { |
|
429 $helper = $this->getDojoHelper(); |
|
430 if ($helper) { |
|
431 $modules = $helper->getModules(); |
|
432 foreach ($modules as $module) { |
|
433 $prefix = $this->_getPrefix($module); |
|
434 if (!array_key_exists($prefix, $this->_profilePrefixes)) { |
|
435 $this->addProfilePrefix($prefix); |
|
436 } |
|
437 } |
|
438 } |
|
439 } |
|
440 return $this->_profilePrefixes; |
|
441 } |
|
442 |
|
443 /** |
|
444 * Generate module layer script |
|
445 * |
|
446 * @return string |
|
447 */ |
|
448 public function generateLayerScript() |
|
449 { |
|
450 $helper = $this->getDojoHelper(); |
|
451 $layerName = $this->getLayerName(); |
|
452 $modulePaths = $helper->getModulePaths(); |
|
453 $modules = $helper->getModules(); |
|
454 $onLoadActions = $helper->getOnLoadActions(); |
|
455 $javascript = $helper->getJavascript(); |
|
456 |
|
457 $content = 'dojo.provide("' . $layerName . '");' . "\n\n(function(){\n"; |
|
458 |
|
459 foreach ($modulePaths as $module => $path) { |
|
460 $content .= sprintf("dojo.registerModulePath(\"%s\", \"%s\");\n", $module, $path); |
|
461 } |
|
462 foreach ($modules as $module) { |
|
463 $content .= sprintf("dojo.require(\"%s\");\n", $module); |
|
464 } |
|
465 |
|
466 if ($this->consumeOnLoad()) { |
|
467 foreach ($helper->getOnLoadActions() as $callback) { |
|
468 $content .= sprintf("dojo.addOnLoad(%s);\n", $callback); |
|
469 } |
|
470 } |
|
471 if ($this->consumeJavascript()) { |
|
472 $javascript = implode("\n", $helper->getJavascript()); |
|
473 if (!empty($javascript)) { |
|
474 $content .= "\n" . $javascript . "\n"; |
|
475 } |
|
476 } |
|
477 |
|
478 $content .= "})();"; |
|
479 |
|
480 return $content; |
|
481 } |
|
482 |
|
483 /** |
|
484 * Generate build profile |
|
485 * |
|
486 * @return string |
|
487 */ |
|
488 public function generateBuildProfile() |
|
489 { |
|
490 $profileOptions = $this->getProfileOptions(); |
|
491 $layerName = $this->getLayerName(); |
|
492 $layerScriptPath = $this->getLayerScriptPath(); |
|
493 $profilePrefixes = $this->getProfilePrefixes(); |
|
494 |
|
495 if (!array_key_exists('releaseName', $profileOptions)) { |
|
496 $profileOptions['releaseName'] = substr($layerName, 0, strpos($layerName, '.')); |
|
497 } |
|
498 |
|
499 $profile = $profileOptions; |
|
500 $profile['layers'] = array(array( |
|
501 'name' => $layerScriptPath, |
|
502 'layerDependencies' => array(), |
|
503 'dependencies' => array($layerName), |
|
504 )); |
|
505 $profile['prefixes'] = array_values($profilePrefixes); |
|
506 |
|
507 return 'dependencies = ' . $this->_filterJsonProfileToJavascript($profile) . ';'; |
|
508 } |
|
509 |
|
510 /** |
|
511 * Retrieve module prefix |
|
512 * |
|
513 * @param string $module |
|
514 * @return void |
|
515 */ |
|
516 protected function _getPrefix($module) |
|
517 { |
|
518 $segments = explode('.', $module, 2); |
|
519 return $segments[0]; |
|
520 } |
|
521 |
|
522 /** |
|
523 * Filter a JSON build profile to JavaScript |
|
524 * |
|
525 * @param string $profile |
|
526 * @return string |
|
527 */ |
|
528 protected function _filterJsonProfileToJavascript($profile) |
|
529 { |
|
530 require_once 'Zend/Json.php'; |
|
531 $profile = Zend_Json::encode($profile); |
|
532 $profile = trim($profile, '"'); |
|
533 $profile = preg_replace('/' . preg_quote('\\') . '/', '', $profile); |
|
534 return $profile; |
|
535 } |
|
536 } |