Development

sfExtjs2Plugin: sfExtjs2Helper.php

You must first sign up to be able to contribute.

sfExtjs2Plugin: sfExtjs2Helper.php

File sfExtjs2Helper.php, 28.2 kB (added by swagner, 6 months ago)
Line 
1 <?php
2
3 /**
4  * @plugin           sfExtjs2Plugin
5  * @description      sfExtjs2Plugin is a symfony plugin that provides an easy to use wrapper for the Ext javascript library
6  * @author           Benjamin Runnels<benjamin.r.runnels [at] citi [dot] com>, Leon van der Ree, Wolfgang Kubens<wolfgang.kubens [at] gmx [dot] net>, Jerome Macias
7  * @version          0.0.58
8  * @last modified   
9  *                   18.02.2008 swagner
10  *                    - Fixed harmless bug (a simple empty array resulted in "['']" insted of"[]")
11  *                   12.02.2008 swagner
12  *                    - added two help-functions (isAssoc() and isSimpleArray())
13  *                    - Fixed _quote() and added check for simple Array
14  *                   04.02.2008 swagner
15  *                    - Fixed handling of arrays in getExtObjectComponent
16  *                   12.28.2007 Jerome
17  *                    - Fixed method getExtObject
18  *                    - Added constants
19  *                    - Fixed method _build_datas (return empty string if array is empty)
20  *                   12.27.2007 Jerome
21  *                    - Added handling of null values
22  *                   12.26.2007 Jerome
23  *                    - Fixed method getExtObject when we want to assign a name attribute and we don't specify "attributes" key in $attributes param
24  *                    - Fixed order for display private attributes in method beginApplication
25  *                    - Added datas parameter for method getExtObjectComponent
26  *                    - Added method _build_datas
27  *                    - Replaced all call_user_func and sfExtjs2Plugin:: by self::
28  *                    - Added possibility to load js or/and css addons/plugins
29  *                    - Added possibility to set name for a function in method asMethod
30  *                    - Replaced some ',' by self::LBR_CM
31  *                    - Added method initApplication
32  *                   12.20.2007 Wolfgang
33  *                                      - Added method asListener
34  *                                      - Renamed method customClass into asCustomClass
35  *                                      - Renamed method anonymousClass into asAnonymousClass
36  *                                   12.19.2007 Wolfgang
37  *                    - Added method asVar
38  *                    - Added logic for anonymousClass
39  *                    - Changed parameters handling
40  *                   12.18.2007 Wolfgang
41  *                    - Added sf_extjs2_comment
42  *                   12.17.2007 Leon:
43  *                    - handling of inner (recursive) arrays (see items => array(array(...), array(...))
44  *                   12.17.2007 Kubens:
45  *                    - Added handling of boolean values
46  *                    - Fixed quoting logic for beginClass
47  *                    - Fixed quoting logic for beginApplication
48  *                   12.15.2007 Kubens:
49  *                     - Overworked quoting logic
50  *                   11.22.2007 Kubens:
51  *                     - Added features to create application
52  *                     - Added parameters support for Ext.object constructors
53  *                    11.17.2007 Kubens:
54  *                     - Added features to create custom classes and custom methods
55  *                    11.12.2007  Kubens:
56  *                     - Fixed loading order of adapters. If adapters are used then it is important to load
57  *                       adapters and coresponding files before ext-all.js
58  *                     - Overworked: load method. Adapters and themes are setuped in config.php
59  *                     - Overworked: constructor. If no adapter or theme is passed then default
60  *                       settings from config.php will used
61  *                    11.07.2007 Benjamin:
62  *                     - Fixed the adapter includes to load all required files in the correct order
63  *                       moved ext-base into adapters, pass ext as adapter for standalone
64  *                       changed all javascript to load first so they will come before files specified in view.yml
65  *                   07.15.2007 Kubens:
66  *                     - created
67  */
68 class sfExtjs2Plugin {
69
70   const
71     LBR      = "\n",
72     LBR_CM   = ",\n",
73     LBR_SM   = ";\n",
74     LBR_CB_L = "{\n",
75     LBR_CB_R = "\n}",
76     LBR_SB_L = "[\n",
77     LBR_SB_R = "\n]";
78  
79   private
80     $items     = array(),
81     $namespace = '', // current namespace
82     $options   = array('theme' => '', // current theme
83                        'adapter' => ''), // current adapter
84     $addons    = array('css' => array(), // current js plugins
85                        'js' => array()); // current css addons
86  
87   static public function isAssoc($arr){
88     foreach ( $arr as $key => $skip ) {
89       if ( !is_integer( $key ) ) {
90             return true;
91       }
92     }
93     return false;
94   }
95  
96   /**
97    * Creates an instance of sfExtjs2Plugin.
98    *
99    * Usage:
100    *
101    *   $sfExtjs2Plugin = new sfExtjs2Plugin(
102    *                           array
103    *                           (
104    *                             'adapter' => 'jquery', // config.sf_extjs2_adapters
105    *                             'theme'   => 'gray'    // config.sf_extjs2_themes
106    *                           ),
107    *                           array
108    *                           (
109    *                             'js' => '/js/myExtjsPlugin.js',
110    *                             'css' => '/css/symfony-extjs.css'
111    *                           )
112    *                         );
113    *
114    * @param array options
115    */
116   public function __construct($options = array(), $addons = array())
117   {
118     if ($options)
119     {
120       $this->setOptions($options);
121     }
122     
123     if ($addons)
124     {
125       $this->setAddons($addons);
126     }
127   }
128  
129   /**
130    * set theme and adapter
131    *
132    */
133   private function setOptions($options)
134   {
135     foreach ($this->options as $optName => $v)
136     {
137       $this->options[$optName] = isset($options[$optName]) && array_key_exists($options[$optName], sfConfig::get('sf_extjs2_'.$optName.'s', array())) ? $options[$optName] : sfConfig::get('sf_extjs2_default_'.$optName);
138     }
139   }
140  
141   /**
142    * set js and/or css addons
143    *
144    */ 
145   private function setAddons($addons)
146   {
147     foreach ($this->addons as $type => $v)
148     {
149       if (array_key_exists($type, $addons))
150       {
151         $this->addons[$type] = is_array($addons[$type]) ? $addons[$type] : array($addons[$type]);
152       }
153     }
154   }
155
156   /**
157    * If method does not exists and method is listed in
158    * config.sf_extjs2_classes then Extjs2.class.constructor will rendered.
159    *
160    * Usage:
161    *
162    *   $sfExtjs2Plugin = new sfExtjs2Plugin(
163    *                           array
164    *                           (
165    *                             'adapter' => 'jquery',
166    *                             'theme'   => 'gray'
167    *                           ),
168    *                           array
169    *                           (
170    *                             'js' => '/js/myExtjsPlugin.js',
171    *                             'css' => '/css/symfony-extjs.css'
172    *                           )
173    *                         );
174    *   $sfExtjs2Plugin->Window(
175    *                      array
176    *                      (
177    *                        'title'  => 'Window Title',
178    *                        'border' => false,
179    *                        'width'  => 600,
180    *                        'height' => 500
181    *                      )
182    *                    );
183    *
184    * @param string class
185    * @param array attributes
186    * @return string Javascript source of Extjs2.class
187    */
188   public static function __call ($class, $attributes)
189   {
190     $classes = sfConfig::get('sf_extjs2_classes');
191     if (is_array($classes) && array_key_exists($class, $classes))
192     {
193       $object = sfConfig::get($classes[$class]);
194       return self::getExtObject($object['class'], $attributes[0]);
195     }
196   }
197
198   /**
199    * Creates Javascript source for Extjs2.class
200    *
201    * Usage:
202    *
203    *   Syntax A = short form without any options
204    *   $sfExtjs2Plugin->Object(array
205    *   (
206    *     'id'       => 'id',
207    *     'renderTo' => $sfExtjs2Plugin->asVar('document.body'),
208    *     'items'    => array
209    *     (
210    *       $sfExtjs2Plugin->Object(array('title'=>'Object A')),
211    *       $sfExtjs2Plugin->Object(array('title'=>'Object B'))
212    *     )
213    *   ));
214    *
215    *   => new Object({id: 'id', renderTo: document.body, items: [new Object(title: 'Object A'), new Object(title: 'Object B')]})   
216    *
217    *
218    *   Syntax B = long form with additional options
219    *   $sfExtjs2Plugin->Object(array
220    *   (
221    *     'name'       => 'string',      // option to render Javascript variable
222    *     'parameters' => array
223    *      (
224    *        'parameter1',
225    *        'parameter2'
226    *      ),
227    *     'attributes' => array          // attributes for Ext constructor
228    *     (
229    *       'id'       => 'id',
230    *       'renderTo' => 'document.body',
231    *       'items'    => array
232    *       (
233    *         $sfExtjs2Plugin->Object(array('title' => 'Object A')),
234    *         $sfExtjs2Plugin->Object(array('title' => 'Object B'))
235    *       )
236    *     )
237    *   ));
238    *   
239    *   => new Object(parameter1, parameter2, {id: 'id', renderTo: document.body, items: [new Object(title: 'Object A'), new Object(title: 'Object B')]})   
240    *
241    * @param string class
242    * @param array attributes
243    * @return string source
244    */
245   public static function getExtObject($class, $params = array())
246   {
247     $name = $lbr = null;
248     $attributes = $parameters = $datas = array();
249     
250     # syntax A is a shortform of syntax B
251     # if syntax A is used then convert syntax A to syntax B
252     if (is_array($params) && !array_key_exists('attributes', $params) && !array_key_exists('parameters', $params) && !array_key_exists('datas', $params))
253     {
254       $attributes = $params;
255     }
256     else
257     {
258       $attributes = array_key_exists('attributes', $params) ? $params['attributes'] : array();
259       
260       // name for var     
261       if (is_array($params) && array_key_exists('name', $params))
262       {
263         $name = $params['name'];
264         unset($params['name']);
265       }
266       
267       // 'lbr' for a line break
268       if (is_array($params) && array_key_exists('lbr', $params))
269       {
270         $lbr = $params['lbr'];
271         unset($params['name']);
272       }
273       
274       // parameters for constructor
275       if (is_array($params) && array_key_exists('parameters', $params))
276       {
277         $parameters = $params['parameters'];
278         unset($params['parameters']);
279       }
280       
281       // datas for constructor
282       if (is_array($params) && array_key_exists('datas', $params))
283       {
284         $datas = $params['datas'];
285         unset($params['datas']);
286       }
287     }
288  
289     # list attributes must defined as an Javascript array
290     # therefore all list attributes must be rendered as [attributeA, attributeB, attributeC]
291     foreach (sfConfig::get('sf_extjs2_list_attributes') as $attribute)
292     {
293       if (array_key_exists($attribute, $attributes) && !$attributes[$attribute] instanceof sfExtjs2Var)
294       {
295         $attributes[$attribute] = sprintf
296         (
297           self::LBR_SB_L.'%s'.self::LBR_SB_R,
298           self::_build_attributes($attributes[$attribute])
299         );
300       }
301     }
302
303     // get source of component
304     $source = self::getExtObjectComponent($attributes, sfConfig::get($class), $parameters, $datas);
305
306     // if 'name' is assigned then we must render
307     // either a Javascript variable or an attribute of this
308     if ($name)
309     {
310       $source = sprintf
311       (
312         '%s%s = %s',
313         strpos($name, 'this.') === false ? 'var ' : '',
314         $name,
315         $source
316       );
317     }
318  
319     // if 'lbr' assigned then we must render a line break
320     if ($lbr)
321     {
322       $source .= $lbr;
323     }
324  
325     return $source;
326   }
327
328   /**
329    * Creates Javascript source for Extjs2.class
330    *
331    * @param array attributes
332    * @param array config
333    * @param array parameters
334    * @return string source
335    */
336   public static function getExtObjectComponent($attributes = array(), $config = array(), $parameters = array(), $datas = array())
337   {
338
339     $isAssoc = self::isAssoc($attributes);
340     $LBR_B_L = $isAssoc ? self::LBR_CB_L : self::LBR_SB_L;
341     $LBR_B_R = $isAssoc ? self::LBR_CB_R : self::LBR_SB_R;
342         
343     $attributes = self::_build_attributes($attributes, $config['attributes']);
344     $attributes = sprintf('%s', $attributes != '' ? $LBR_B_L.$attributes.$LBR_B_R : '');
345
346     $parameters = implode(self::LBR_CM, $parameters);
347     $datas = $config['class'] == 'anonymousClass' ? self::_build_datas($datas) : (!empty($datas) ? "'".implode("'".self::LBR_CM."'", $datas)."'" : '');
348     
349     switch ($config['class'])
350     {
351       case 'anonymousClass':
352         $source = sprintf(
353           '%s%s%s%s%s',
354           $parameters,
355           $parameters != '' && $datas != '' ? self::LBR_CM : '',
356           $datas,
357           $datas != '' && $attributes != '' ? self::LBR_CM : '',
358           $attributes
359         );
360         return $source;
361
362       case 'customClass':
363         $source = sprintf(
364           '{ %s }',
365           $attributes
366         );
367         return $source;
368
369       default:
370         $source = sprintf(
371           'new %s (%s%s%s%s%s)',
372           $config['class'],
373           $parameters != '' ? self::LBR_SB_L.$parameters.self::LBR_SB_R : '',
374           $parameters != '' && $datas != '' ? self::LBR_CM : '',
375           $datas,
376           $datas != '' && $attributes != '' ? self::LBR_CM : '',
377           $attributes
378         );
379         return $source;
380     }
381  
382   }
383
384   /**
385    * add sources for css and js to html head
386    *
387    */
388   public function load()
389   {
390     $response = sfContext::getInstance()->getResponse();
391
392     // add javascript sources for adapter
393     $adapters = sfConfig::get('sf_extjs2_adapters', array());
394     
395     if ($this->options['adapter']) {
396         foreach ($adapters[$this->options['adapter']] as $file)
397         {
398             $response->addJavascript(sfConfig::get('sf_extjs2_js_dir').$file, 'first');
399         }
400     }
401
402     // add javascript sources for ext all
403     //$response->addJavascript(sfConfig::get('sf_extjs2_js_dir').'ext-all.js', 'first');
404     
405     if (array_key_exists('js', $this->addons))
406     {
407       foreach ($this->addons['js'] as $jsAddon)
408       {
409         $response->addJavascript($jsAddon, 'first');
410       }
411     }
412
413     // add css sources for ext all
414     //$response->addStylesheet(sfConfig::get('sf_extjs2_css_dir').'ext-all.css', 'first');
415
416     // add css sources for theme
417     $themes = sfConfig::get('sf_extjs2_themes', array());
418
419     if ($this->options['theme']) {
420         foreach ($themes[$this->options['theme']] as $file)
421         {
422             $response->addStylesheet(sfConfig::get('sf_extjs2_css_dir').$file, 'first');
423         }
424     }
425     
426     if (array_key_exists('css', $this->addons))
427     {
428       foreach ($this->addons['css'] as $cssAddon)
429       {
430         $response->addStylesheet($cssAddon, 'first');
431       }
432     }
433   }
434
435   /**
436    * writes opening tag for javascript
437    *
438    * @return string source
439    */
440   public function begin()
441   {
442     $source  = self::LBR;
443     $source .= sprintf("<script type='text/javascript'>%s", self::LBR);
444     $source .= self::_comment(sprintf("%s// sfExtjs2Helper: %s%s", self::LBR, sfConfig::get('sf_extjs2_version'), self::LBR));
445     $source .= sprintf("Ext.BLANK_IMAGE_URL = '%s'%s", sfConfig::get('sf_extjs2_spacer'), self::LBR_SM);
446  
447     echo $source;
448   }
449
450   /**
451    * writes closing tag for javascript
452    *   *
453    * @param  string source
454    * @return Javascript source
455    */
456   public function end($source = '')
457   {
458     $source  = sprintf("%s%s%s", self::LBR, $source, $source != '' ? self::LBR : '');
459     $source .= sprintf("</script>%s", self::LBR);
460
461     echo $source;
462   }
463
464   /**
465    * writes opening class tag
466    *
467    * @param string namespace
468    * @param string classname
469    * @param string extend
470    * @param array attributes
471    * @return string source
472    */
473   public function beginClass($namespace = null, $classname = null, $extend = null, $attributes = array())
474   {
475     $source = '';
476  
477     // write namespace directive
478     // prevent double output of namespace directive
479     if ($this->namespace !== $namespace)
480     {
481       $this->namespace = $namespace;
482       $source .= self::_comment(sprintf("%s// namespace: %s%s", self::LBR, $namespace, self::LBR));
483       $source .= sprintf("Ext.namespace('%s')%s", $namespace, self::LBR_SM);
484     }
485  
486     // write class tag
487     $source .= self::_comment(sprintf("%s// class: %s.%s%s", self::LBR, $namespace, $classname, self::LBR));
488     $source .= sprintf("%s.%s = Ext.extend(%s, { %s", $namespace, $classname, $extend, self::LBR);
489  
490     // write attributes
491     $source .= self::_build_attributes($attributes);
492  
493     echo $source;
494   }
495
496   /**
497    * writes closing class tag
498    *
499    * @return Javascript source
500    */
501   public function endClass()
502   {
503     $source  = '';
504     $source .= sprintf("})%s%s", self::LBR_SM, self::LBR_SM);
505
506     echo $source;
507   }
508
509   /**
510    * writes begining application tag
511    *
512    * @param attributes['name']
513    * @param attributes['private']
514    * @param attributes['public']
515    * @return string source
516    */
517    public function beginApplication($attributes = array())
518    {
519      // private attributes
520      $sourcePrivate = '';
521      if (array_key_exists('private', $attributes))
522      {
523        foreach ($attributes['private'] as $key => $value)
524        {
525          $sourcePrivate .= sprintf("%svar %s = %s;", self::LBR, $key, self::_quote($key, $value));
526        }
527      }
528
529      // public attributes
530      $sourcePublic = '';
531      if (array_key_exists('public', $attributes))
532      {
533        // write attributes
534        $sourcePublic .= self::_build_attributes($attributes['public']);
535      }
536
537      // write application syntax
538      $source  = '';
539      $source .= self::_comment(sprintf("%s// application: %s%s", self::LBR, $attributes['name'], self::LBR));
540      $source .= sprintf(
541        'var %s = function () { %s%sreturn {%s %s %s',
542        $attributes['name'],
543        $sourcePrivate,
544        $sourcePrivate != '' ? self::LBR : '',
545        self::LBR,
546        $sourcePublic,
547        $sourcePublic != '' ? self::LBR : ''
548      );
549
550      echo $source;
551    }
552
553   /**
554    * writes closing application tag
555    *
556    * @return source
557    */
558   public function endApplication()
559   {
560     $source  = '';
561     $source .= sprintf("%s}}()%s", self::LBR, self::LBR_SM);
562