]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - modules/ModuleBuilder/MB/MBModule.php
Release 6.5.15
[Github/sugarcrm.git] / modules / ModuleBuilder / MB / MBModule.php
1 <?php
2 /*********************************************************************************
3  * SugarCRM Community Edition is a customer relationship management program developed by
4  * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
5  * 
6  * This program is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Affero General Public License version 3 as published by the
8  * Free Software Foundation with the addition of the following permission added
9  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
10  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
11  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
12  * 
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
16  * details.
17  * 
18  * You should have received a copy of the GNU Affero General Public License along with
19  * this program; if not, see http://www.gnu.org/licenses or write to the Free
20  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  * 02110-1301 USA.
22  * 
23  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
24  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
25  * 
26  * The interactive user interfaces in modified source and object code versions
27  * of this program must display Appropriate Legal Notices, as required under
28  * Section 5 of the GNU Affero General Public License version 3.
29  * 
30  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
31  * these Appropriate Legal Notices must retain the display of the "Powered by
32  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
33  * technical reasons, the Appropriate Legal Notices must display the words
34  * "Powered by SugarCRM".
35  ********************************************************************************/
36
37 define ( 'MB_TEMPLATES', 'include/SugarObjects/templates' ) ;
38 define ( 'MB_IMPLEMENTS', 'include/SugarObjects/implements' ) ;
39 require_once ('modules/ModuleBuilder/MB/MBVardefs.php') ;
40 require_once ('modules/ModuleBuilder/MB/MBRelationship.php') ;
41 require_once ('modules/ModuleBuilder/MB/MBLanguage.php') ;
42
43 class MBModule
44 {
45     public $name = '' ;
46     public $config = array (
47     'assignable' => 1 , 'acl' => 1 , 'has_tab' => 1 , 'studio' => 1 , 'audit' => 1 ) ;
48     public $mbpublicdefs ;
49     public $errors = array ( ) ;
50     public $path = '' ;
51     public $implementable = array (
52     'has_tab' => 'Navigation Tab' ) ;
53     public $always_implement = array ( 'assignable' => 'Assignable' , 'acl' => 'Access Controls' , 'studio' => 'Studio Support' , 'audit' => 'Audit Table' ) ;
54     public $iTemplate = array (
55     'assignable' ) ;
56
57     public $config_md5 = null ;
58
59     function __construct ($name , $path , $package , $package_key)
60     {
61         global $mod_strings;
62         $this->config [ 'templates' ] = array ( 'basic' => 1 ) ;
63
64         $this->name = MBModule::getDBName ( $name ) ;
65         $this->key_name = $package_key . '_' . $name ;
66         $this->package = $package ;
67         $this->package_key = $package_key ;
68         $this->package_path = $path ;
69
70         $this->implementable = array (
71         'has_tab' => !empty($mod_strings[ 'LBL_NAV_TAB' ]) ? $mod_strings[ 'LBL_NAV_TAB' ] : false) ;
72         $this->path = $this->getModuleDir () ;
73         //              $this->mbrelationship = new MBRelationship($this->name, $this->path, $this->key_name);
74         $this->relationships = new UndeployedRelationships ( $this->path ) ;
75         $this->mbvardefs = new MBVardefs ( $this->name, $this->path, $this->key_name ) ;
76
77         $this->load () ;
78     }
79
80     function getDBName ($name)
81     {
82         return preg_replace ( "/[^\w]+/", "_", $name ) ;
83     }
84
85     function getModuleName()
86     {
87         return $this->name;
88     }
89
90     function getPackageName()
91     {
92         return $this->package;
93     }
94
95     /**
96      * @return UndeployedRelationships
97      */
98     function getRelationships()
99     {
100         return $this->relationships;
101     }
102
103     /**
104      * Loads the module based on the module name
105      *
106      */
107     function load ()
108     {
109         if (file_exists ( $this->path . '/config.php' ))
110         {
111             include ($this->path . '/config.php') ;
112             $this->config = $config ;
113         }
114         $label = (! empty ( $this->config [ 'label' ] )) ? $this->config [ 'label' ] : $this->name ;
115         $this->mblanguage = new MBLanguage ( $this->name, $this->path, $label, $this->key_name ) ;
116         foreach ( $this->iTemplate as $temp )
117         {
118             if (! empty ( $this->config [ $temp ] ))
119             {
120                 $this->mbvardefs->iTemplates [ $temp ] = 1 ;
121                 $this->mblanguage->iTemplates [ $temp ] = $temp ;
122             }
123         }
124         $this->mbvardefs->templates = $this->config [ 'templates' ] ;
125         $this->mblanguage->templates = $this->config [ 'templates' ] ;
126         $this->mbvardefs->load () ;
127         $this->mblanguage->load () ;
128
129     }
130
131     function addTemplate ($template)
132     {
133         $this->config [ 'templates' ] [ $template ] = 1 ;
134     }
135
136     function getModuleDir ()
137     {
138         return $this->package_path . '/modules/' . $this->name ;
139     }
140
141     function removeTemplate ($template)
142     {
143         unset ( $this->config [ 'templates' ] [ $template ] ) ;
144     }
145
146     function getVardefs ($by_group = false)
147     {
148         $this->mbvardefs->updateVardefs ( $by_group ) ;
149         return $this->mbvardefs->getVardefs () ;
150     }
151
152     function addField ($vardef)
153     {
154         $this->mbvardefs->addFieldVardef ( $vardef ) ;
155     }
156
157     function addFieldObject ($field)
158     {
159         $vardef = $field->get_field_def () ;
160                 $this->mbvardefs->mergeVardefs();
161                 $existingVardefs = $this->mbvardefs->getVardefs () ;
162                 //Merge with the existing vardef if it already exists
163                 if(!empty($existingVardefs['fields'][$vardef['name']])){
164                         $vardef = array_merge( $existingVardefs['fields'][$vardef['name']], $vardef);
165                 }
166         if (! empty ( $vardef [ 'source' ] ) && $vardef [ 'source' ] == 'custom_fields')
167             unset ( $vardef [ 'source' ] ) ;
168
169             $this->mbvardefs->load();
170         $this->addField ( $vardef ) ;
171         $this->mbvardefs->save();
172     }
173
174     function deleteField ($name)
175     {
176         $this->mbvardefs->deleteField ( $name ) ;
177     }
178
179     function fieldExists ($name = '' , $type = '')
180     {
181         $vardefs = $this->getVardefs();
182         if (! empty ( $vardefs ))
183         {
184             if (empty ( $type ) && empty ( $name ))
185                 return false ; else if (empty ( $type ))
186                 return ! empty ( $vardefs [ 'fields' ] [ $name ] ) ; else if (empty ( $name ))
187             {
188                 foreach ( $vardefs [ 'fields' ] as $def )
189                 {
190                     if ($def [ 'type' ] == $type)
191                         return true ;
192                 }
193                 return false ;
194             } else
195                 return (! empty ( $vardefs [ 'fields' ] [ $name ] ) && ($vardefs [ 'fields' ] [ $name ] [ 'type' ] == $type)) ;
196         } else
197         {
198             return false ;
199         }
200     }
201
202     function getModStrings ($language = 'en_us')
203     {
204         return $this->mblanguage->getModStrings ( $language ) ;
205     }
206
207     function setModStrings ($language = 'en_us' , $mod_strings)
208     {
209         $language .= '.lang.php' ;
210         $this->mblanguage->strings [ $language ] = $mod_strings ;
211     }
212
213         function setLabel ($language = 'en_us' , $key , $value)
214     {
215         $language .= '.lang.php' ;
216         $this->mblanguage->strings [ $language ] [ $key ] = $value ;
217         //Ensure this key exists in all languages
218         foreach ($this->mblanguage->strings as $lang => $values) {
219                 if (empty($values[$key])) {
220                         $this->mblanguage->strings[$lang][$key] = $value;
221                 }
222         }
223     }
224
225     function deleteLabel ($language = 'en_us' , $key)
226     {
227                 foreach ($this->mblanguage->strings as $lang => $values) {
228                 if (!empty($values[$key])) {
229                         unset($this->mblanguage->strings[$lang][$key]);
230                 }
231         }
232     }
233
234     /**
235      * Required for an MB module to work with Dynamic fields
236      */
237         function addLabel ( $displayLabel)
238     {
239         $this->setLabel('en_us', $this->getDBName($displayLabel, false), translate($displayLabel));
240         $this->save();
241     }
242
243     function getLabel ($language = 'en_us' , $key)
244     {
245         $language .= '.lang.php' ;
246         if (empty ( $this->mblanguage->strings [ $language ] [ $key ] ))
247         {
248
249             return '' ;
250         }
251         return $this->mblanguage->strings [ $language ] [ $key ] ;
252
253     }
254
255     function getAppListStrings ($language = 'en_us')
256     {
257         return $this->mblanguage->getAppListStrings ( $language ) ;
258     }
259
260     function setAppListStrings ($language = 'en_us' , $app_list_strings)
261     {
262         $language .= '.lang.php' ;
263         $this->mblanguage->appListStrings [ $language ] = $app_list_strings ;
264     }
265
266     function setDropDown ($language = 'en_us' , $key , $value)
267     {
268         $language .= '.lang.php' ;
269         $this->mblanguage->appListStrings [ $language ] [ $key ] = $value ;
270     }
271
272     function deleteDropDown ($language = 'en_us' , $key)
273     {
274         $language .= '.lang.php' ;
275         unset ( $this->mblanguage->appListStrings [ $language ] [ $key ] ) ;
276     }
277
278     function save ()
279     {
280         $this->path = $this->getModuleDir () ;
281         if (mkdir_recursive ( $this->path ))
282         {
283
284             $this->setConfigMD5 () ;
285             $old_config_md5 = $this->config_md5 ;
286             $this->saveConfig () ;
287             $this->getVardefs () ;
288             $this->mbvardefs->save ( $this->key_name ) ;
289             //           $this->mbrelationship->save ( $this->key_name ) ;
290             $this->relationships->save () ;
291             $this->copyMetaData () ;
292             $this->copyDashlet () ;
293             $this->copyViews() ;
294             if (0 != strcmp ( $old_config_md5, $this->config_md5 ))
295             {
296                 $this->mblanguage->reload () ;
297             }
298             $this->mblanguage->label = $this->config [ 'label' ] ;
299             //pass in the key_name incase it has changed mblanguage will check if it is different and handle it accordingly
300             $this->mblanguage->save ( $this->key_name ) ;
301
302             if (! file_exists ( $this->package_path . "/icons/icon_" . ucfirst ( $this->key_name ) . ".gif" ))
303             {
304                 $this->createIcon () ;
305             }
306             $this->errors = array_merge ( $this->errors, $this->mbvardefs->errors ) ;
307
308         }
309     }
310
311     function copyDashlet() {
312         $templates = array_reverse ( $this->config [ 'templates' ], true ) ;
313         foreach ( $templates as $template => $a )
314         {
315             if (file_exists ( MB_TEMPLATES . '/' . $template . '/Dashlets/Dashlet' ))
316             {
317
318                 $this->copyMetaRecursive ( MB_TEMPLATES . '/' . $template . '/Dashlets/Dashlet', $this->path . '/Dashlets/' . $this->key_name . 'Dashlet/' ) ;
319
320             }
321         }
322     }
323
324     function copyViews() {
325         $templates = array_reverse ( $this->config [ 'templates' ], true ) ;
326         foreach ( $templates as $template => $a )
327         {
328             if (file_exists ( MB_TEMPLATES . '/' . $template . '/views' ))
329             {
330                 $this->copyMetaRecursive ( MB_TEMPLATES . '/' . $template . '/views', $this->path . '/views/' ) ;
331             }
332         }
333     }
334
335     function copyCustomFiles ( $from , $to )
336     {
337         $d = dir ( $from ) ;
338         while ( $filename = $d->read () )
339         {
340                 if (substr ( $filename, 0, 1 ) == '.')
341                 continue ;
342                 if ( $filename != 'metadata' && $filename != 'Dashlets' && $filename != 'relationships' && $filename != 'language' && $filename != 'config.php' && $filename != 'relationships.php' && $filename != 'vardefs.php' )
343                         copy_recursive ( "$from/$filename" , "$to/$filename" ) ;
344         }
345     }
346
347     function copyMetaData ()
348     {
349         $templates = array_reverse ( $this->config [ 'templates' ], true ) ;
350         foreach ( $templates as $template => $a )
351         {
352             if (file_exists ( MB_TEMPLATES . '/' . $template . '/metadata' ))
353             {
354                 $this->copyMetaRecursive ( MB_TEMPLATES . '/' . $template . '/metadata', $this->path . '/metadata/' ) ;
355
356             }
357         }
358     }
359
360     function copyMetaRecursive ($from , $to , $overwrite = false)
361     {
362         if (! file_exists ( $from ))
363             return ;
364         if (is_dir ( $from ))
365         {
366             $findArray = array ( '<module_name>' , '<_module_name>' , '<MODULE_NAME>' , '<object_name>' , '<_object_name>' , '<OBJECT_NAME>' );
367             $replaceArray = array ( $this->key_name , strtolower ( $this->key_name ) , strtoupper ( $this->key_name ) ,
368                                                         $this->key_name , strtolower ( $this->key_name ) , strtoupper ( $this->key_name ) );
369                 mkdir_recursive ( $to ) ;
370             $d = dir ( $from ) ;
371             while ( $e = $d->read () )
372             {
373                 if (substr ( $e, 0, 1 ) == '.')
374                     continue ;
375                 $nfrom = $from . '/' . $e ;
376                 $nto = $to . '/' . str_replace ( 'm-n-', $this->key_name, $e ) ;
377                 if (is_dir ( $nfrom ))
378                 {
379                     $this->copyMetaRecursive ( $nfrom, $nto, $overwrite ) ;
380                 } else
381                 {
382                     if ($overwrite || ! file_exists ( $nto ))
383                     {
384                         $contents = file_get_contents ( $nfrom ) ;
385                         $contents = str_replace ( $findArray, $replaceArray, $contents ) ;
386                         $fw = sugar_fopen ( $nto, 'w' ) ;
387                         fwrite ( $fw, $contents ) ;
388                         fclose ( $fw ) ;
389                     }
390                 }
391             }
392
393         }
394     }
395
396     function saveConfig ()
397     {
398         $header = file_get_contents ( 'modules/ModuleBuilder/MB/header.php' ) ;
399         if (! write_array_to_file ( 'config', $this->config, $this->path . '/config.php', 'w', $header ))
400         {
401             $this->errors [] = 'Could not save config to ' . $this->path . '/config.php' ;
402         }
403         $this->setConfigMD5 () ;
404     }
405
406     function setConfigMD5 ()
407     {
408         if (file_exists ( $this->path . '/config.php' ))
409             $this->config_md5 = md5 ( base64_encode ( serialize ( $this->config ) ) ) ;
410     }
411
412     function build ($basepath)
413     {
414         global $app_list_strings;
415         $path = $basepath . '/modules/' . $this->key_name ;
416         if (mkdir_recursive ( $path ))
417         {
418             $this->createClasses ( $path ) ;
419             if( $this->config['importable'] || in_array ( 'person', array_keys($this->config[ 'templates' ]) ) )
420                 $this->createMenu ( $path ) ;
421             $this->copyCustomFiles ( $this->path , $path ) ;
422             $this->copyMetaRecursive ( $this->path . '/metadata/', $path . '/metadata/', true ) ;
423             $this->copyMetaRecursive ( $this->path . '/Dashlets/' . $this->key_name . 'Dashlet/',
424                                                            $path . '/Dashlets/' . $this->key_name . 'Dashlet/', true ) ;
425             $app_list_strings['moduleList'][$this->key_name] = $this->mblanguage->label;
426             $this->relationships->build ( $basepath ) ;
427             $this->mblanguage->build ( $path ) ;
428         }
429     }
430
431     function createClasses ($path)
432     {
433         $class = array ( ) ;
434         $class [ 'name' ] = $this->key_name ;
435         $class [ 'table_name' ] = strtolower ( $class [ 'name' ] ) ;
436         $class [ 'extends' ] = 'Basic' ;
437         $class [ 'requires' ] [] = MB_TEMPLATES . '/basic/Basic.php' ;
438         $class [ 'requires' ] = array ( ) ;
439         $class [ 'audited' ] = (! empty ( $this->config [ 'audit' ] )) ? 'true' : 'false' ;
440         $class [ 'acl' ] = ! empty ( $this->config [ 'acl' ] ) ;
441         $class [ 'templates' ] = "'basic'" ;
442         foreach ( $this->iTemplate as $template )
443         {
444             if (! empty ( $this->config [ $template ] ))
445             {
446                 $class [ 'templates' ] .= ",'$template'" ;
447             }
448         }
449         foreach ( $this->config [ 'templates' ] as $template => $a )
450         {
451             if ($template == 'basic')
452                 continue ;
453             $class [ 'templates' ] .= ",'$template'" ;
454             $class [ 'extends' ] = ucFirst ( $template ) ;
455             $class [ 'requires' ] [] = MB_TEMPLATES . '/' . $template . '/' . ucfirst ( $template ) . '.php' ;
456         }
457         $class [ 'importable' ] = $this->config [ 'importable' ] ;
458         $this->mbvardefs->updateVardefs () ;
459         $class [ 'fields' ] = $this->mbvardefs->vardefs [ 'fields' ] ;
460         $class [ 'fields_string' ] = var_export_helper ( $this->mbvardefs->vardef [ 'fields' ] ) ;
461         $relationship = array ( ) ;
462         $class [ 'relationships' ] = var_export_helper ( $this->mbvardefs->vardef [ 'relationships' ] ) ;
463         $smarty = new Sugar_Smarty ( ) ;
464         $smarty->left_delimiter = '{{' ;
465         $smarty->right_delimiter = '}}' ;
466         $smarty->assign ( 'class', $class ) ;
467         //write sugar generated class
468         $fp = sugar_fopen ( $path . '/' . $class [ 'name' ] . '_sugar.php', 'w' ) ;
469         fwrite ( $fp, $smarty->fetch ( 'modules/ModuleBuilder/tpls/MBModule/Class.tpl' ) ) ;
470         fclose ( $fp ) ;
471         //write vardefs
472         $fp = sugar_fopen ( $path . '/vardefs.php', 'w' ) ;
473         fwrite ( $fp, $smarty->fetch ( 'modules/ModuleBuilder/tpls/MBModule/vardef.tpl' ) ) ;
474         fclose ( $fp ) ;
475
476         if (! file_exists ( $path . '/' . $class [ 'name' ] . '.php' ))
477         {
478             $fp = sugar_fopen ( $path . '/' . $class [ 'name' ] . '.php', 'w' ) ;
479             fwrite ( $fp, $smarty->fetch ( 'modules/ModuleBuilder/tpls/MBModule/DeveloperClass.tpl' ) ) ;
480             fclose ( $fp ) ;
481         }
482         if (! file_exists ( $path . '/metadata' ))
483             mkdir_recursive ( $path . '/metadata' ) ;
484         if (! empty ( $this->config [ 'studio' ] ))
485         {
486             $fp = sugar_fopen ( $path . '/metadata/studio.php', 'w' ) ;
487             fwrite ( $fp, $smarty->fetch ( 'modules/ModuleBuilder/tpls/MBModule/Studio.tpl' ) ) ;
488             fclose ( $fp ) ;
489         } else
490         {
491             if (file_exists ( $path . '/metadata/studio.php' ))
492                 unlink ( $path . '/metadata/studio.php' ) ;
493         }
494     }
495
496     function createMenu ($path)
497     {
498         $smarty = new Sugar_Smarty ( ) ;
499         $smarty->assign ( 'moduleName', $this->key_name ) ;
500         $smarty->assign ( 'showvCard', in_array ( 'person', array_keys($this->config[ 'templates' ]) ) ) ;
501         $smarty->assign ( 'showimport', $this->config['importable'] );
502         //write sugar generated class
503         $fp = sugar_fopen ( $path . '/' . 'Menu.php', 'w' ) ;
504         fwrite ( $fp, $smarty->fetch ( 'modules/ModuleBuilder/tpls/MBModule/Menu.tpl' ) ) ;
505         fclose ( $fp ) ;
506     }
507
508     function addInstallDefs (&$installDefs)
509     {
510         $name = $this->key_name ;
511         $installDefs [ 'copy' ] [] = array ( 'from' => '<basepath>/SugarModules/modules/' . $name , 'to' => 'modules/' . $name ) ;
512         $installDefs [ 'beans' ] [] = array ( 'module' => $name , 'class' => $name , 'path' => 'modules/' . $name . '/' . $name . '.php' , 'tab' => $this->config [ 'has_tab' ] ) ;
513         $this->relationships->addInstallDefs ( $installDefs ) ;
514     }
515
516     function getNodes ()
517     {
518
519         $lSubs = array ( ) ;
520         $psubs = $this->getProvidedSubpanels () ;
521         foreach ( $psubs as $sub )
522         {
523             $subLabel = $sub ;
524             if ($subLabel == 'default')
525             {
526                 $subLabel = $GLOBALS [ 'mod_strings' ] [ 'LBL_DEFAULT' ] ;
527             }
528             $lSubs [] = array ( 'name' => $subLabel , 'type' => 'list' , 'action' => 'module=ModuleBuilder&MB=true&action=editLayout&view=ListView&view_module=' . $this->name . '&view_package=' . $this->package . '&subpanel=' . $sub . '&subpanelLabel=' . $subLabel . '&local=1' ) ;
529         }
530
531         $searchSubs = array ( ) ;
532         $searchSubs [] = array ( 'name' => translate('LBL_BASIC_SEARCH') , 'type' => 'list' , 'action' => "module=ModuleBuilder&MB=true&action=editLayout&view=basic_search&view_module={$this->name}&view_package={$this->package}"  ) ;
533         $searchSubs [] = array ( 'name' => translate('LBL_ADVANCED_SEARCH') , 'type' => 'list' , 'action' => 'module=ModuleBuilder&MB=true&action=editLayout&view=advanced_search&view_module=' . $this->name . '&view_package=' . $this->package  ) ;
534         $dashlets = array( );
535         $dashlets [] = array('name' => translate('LBL_DASHLETLISTVIEW') , 'type' => 'dashlet' , 'action' => 'module=ModuleBuilder&MB=true&action=editLayout&view=dashlet&view_module=' . $this->name . '&view_package=' . $this->package );
536                 $dashlets [] = array('name' => translate('LBL_DASHLETSEARCHVIEW') , 'type' => 'dashletsearch' , 'action' => 'module=ModuleBuilder&MB=true&action=editLayout&view=dashletsearch&view_module=' . $this->name . '&view_package=' . $this->package );
537
538                 $popups = array( );
539         $popups [] = array('name' => translate('LBL_POPUPLISTVIEW') , 'type' => 'popuplistview' , 'action' => 'module=ModuleBuilder&action=editLayout&view=popuplist&view_module=' . $this->name . '&view_package=' . $this->package );
540                 $popups [] = array('name' => translate('LBL_POPUPSEARCH') , 'type' => 'popupsearch' , 'action' => 'module=ModuleBuilder&action=editLayout&view=popupsearch&view_module=' . $this->name . '&view_package=' . $this->package );
541                 
542         $layouts = array (
543                 array ( 'name' => translate('LBL_EDITVIEW') , 'type' => 'edit' , 'action' => 'module=ModuleBuilder&MB=true&action=editLayout&view='.MB_EDITVIEW.'&view_module=' . $this->name . '&view_package=' . $this->package ) ,
544                 array ( 'name' => translate('LBL_DETAILVIEW') , 'type' => 'detail' , 'action' => 'module=ModuleBuilder&MB=true&action=editLayout&view='.MB_DETAILVIEW.'&view_module=' . $this->name . '&view_package=' . $this->package ) ,
545                 array ( 'name' => translate('LBL_LISTVIEW') , 'type' => 'list' , 'action' => 'module=ModuleBuilder&MB=true&action=editLayout&view='.MB_LISTVIEW.'&view_module=' . $this->name . '&view_package=' . $this->package ) ,
546                 array ( 'name' => translate('LBL_QUICKCREATE') , 'type' => MB_QUICKCREATE,  'action' => 'module=ModuleBuilder&MB=true&action=editLayout&view='.MB_QUICKCREATE.'&view_module=' . $this->name . '&view_package=' . $this->package ) ,
547                 array ( 'name' => translate('LBL_DASHLET') , 'type' => 'Folder', 'children' => $dashlets, 'action' => 'module=ModuleBuilder&MB=true&action=wizard&view=dashlet&view_module=' . $this->name . '&view_package=' . $this->package  ),
548                 array ( 'name' => translate('LBL_POPUP') , 'type' => 'Folder', 'children' => $popups, 'action' => 'module=ModuleBuilder&MB=true&action=wizard&view=popup&view_module=' . $this->name . '&view_package=' . $this->package  ),
549                 array ( 'name' => translate('LBL_SEARCH_FORMS') , 'action' => 'module=ModuleBuilder&MB=true&action=wizard&view=search&view_module=' . $this->name . '&view_package=' . $this->package , 'type' => 'folder' , 'children' => $searchSubs )
550                 ) ;
551
552         $children = array (
553                 array ( 'name' => translate('LBL_FIELDS') , 'action' => 'module=ModuleBuilder&action=modulefields&view_module=' . $this->name . '&view_package=' . $this->package ) ,
554                 array ( 'name' => translate('LBL_LABELS') , 'action' => 'module=ModuleBuilder&action=modulelabels&view_module=' . $this->name . '&view_package=' . $this->package ) ,
555                 array ( 'name' => translate('LBL_RELATIONSHIPS') , 'action' => 'module=ModuleBuilder&action=relationships&view_module=' . $this->name . '&view_package=' . $this->package ) ,
556                 array ( 'name' => translate('LBL_LAYOUTS') , 'type' => 'Folder' , 'action' => "module=ModuleBuilder&action=wizard&view_module={$this->name}&view_package={$this->package}&MB=1" , 'children' => $layouts ) ,
557                 ) ;
558
559         if (count ( $lSubs ) > 0)
560         {
561             $children [] = array ( 'name' => translate('LBL_AVAILABLE_SUBPANELS') , 'type' => 'folder' , 'children' => $lSubs ) ;
562         }
563
564         $nodes = array ( 'name' => $this->name , 'children' => $children , 'action' => 'module=ModuleBuilder&action=module&view_module=' . $this->name . '&view_package=' . $this->package ) ;
565
566         return $nodes ;
567     }
568
569
570     function getProvidedSubpanels ()
571     {
572         $this->providedSubpanels = array () ;
573
574         $subpanelDir = $this->getModuleDir () . '/metadata/subpanels/' ;
575         if (file_exists ( $subpanelDir ))
576         {
577             $f = dir ( $subpanelDir ) ;
578             require_once 'modules/ModuleBuilder/parsers/relationships/AbstractRelationships.php' ;
579
580             while ( $g = $f->read () )
581             {
582                 // sanity check to confirm that this is a usable subpanel...
583                 if (substr ( $g, 0, 1 ) != '.' && AbstractRelationships::validSubpanel ( $subpanelDir . $g ))
584                 {
585                     $subname = str_replace ( '.php', '', $g ) ;
586                     $this->providedSubpanels [ $subname ] = $subname ;
587                 }
588             }
589         }
590
591         return $this->providedSubpanels;
592     }
593
594     function getTypes ()
595     {
596         $types = array ( ) ;
597         $d = dir ( MB_TEMPLATES ) ;
598         while ( $e = $d->read () )
599         {
600             if (substr ( $e, 0, 1 ) != '.')
601             {
602                 $types [ $e ] = $e ;
603             }
604         }
605
606         return $types ;
607     }
608
609     function rename ($new_name)
610     {
611         $old = $this->getModuleDir () ;
612         $old_name = $this->key_name;
613         $this->name = $new_name ;
614         $this->key_name = $this->package_key . '_' . $this->name ;
615         $new = $this->getModuleDir () ;
616         if (file_exists ( $new ))
617         {
618             return false ;
619         }
620         $renamed = rename ( $old, $new ) ;
621         if ($renamed)
622         {
623             $this->renameMetaData ( $new , $old_name) ;
624             $this->renameLanguageFiles ( $new ) ;
625
626         }
627         return $renamed ;
628     }
629
630         function renameLanguageFiles ($new_dir , $duplicate = false)
631     {
632
633         $this->mblanguage->name = $this->name ;
634         $this->mblanguage->path = $new_dir ;
635         $this->mblanguage->generateAppStrings () ;
636         $this->mblanguage->save ( $this->key_name, $duplicate, true) ;
637     }
638
639     /**
640      * Rename module name in metadata
641      * @param string $new_dir
642      * @param string $old_name
643      */
644     public function renameMetaData ($new_dir, $old_name)
645     {
646         $GLOBALS [ 'log' ]->debug ( 'MBModule.php->renameMetaData: new_dir=' . $new_dir ) ;
647         if (! file_exists ( $new_dir ))
648             return ;
649         $dir = dir ( $new_dir ) ;
650         while ( $e = $dir->read () )
651         {
652             if (substr ( $e, 0, 1 ) != '.')
653             {
654                 if (is_dir ( $new_dir . '/' . $e ))
655                 {
656                     $this->renameMetaData ( $new_dir . '/' . $e,  $old_name) ;
657                 }
658                 if (is_file ( $new_dir . '/' . $e ))
659                 {
660                     $contents = file_get_contents ( $new_dir . '/' . $e ) ;
661                     $search_array = array(
662                         '/(\$module_name[ ]*=[ ]*\').*(\'[ ]*;)/',
663                         '/(\$_module_name[ ]*=[ ]*\').*(\'[ ]*;)/',
664                         '/(\$MODULE_NAME[ ]*=[ ]*\').*(\'[ ]*;)/',
665                         '/(\$object_name[ ]*=[ ]*\').*(\'[ ]*;)/',
666                         '/(\$_object_name[ ]*=[ ]*\').*(\'[ ]*;)/',
667                         '/(\$OBJECT_NAME[ ]*=[ ]*\').*(\'[ ]*;)/'
668                     );
669                     $replace_array = array(
670                         '$1' . $this->key_name . '$2',
671                         '$1' . strtolower ( $this->key_name ) . '$2',
672                         '$1' . strtoupper ( $this->key_name ) . '$2',
673                         '$1' . $this->key_name . '$2',
674                         '$1' . strtolower ( $this->key_name ) . '$2',
675                         '$1' . strtoupper ( $this->key_name ) . '$2',
676                     );
677                     $contents = preg_replace($search_array, $replace_array, $contents);
678                     $search_array = array(
679                         "{$old_name}_",
680                         "{$old_name}Dashlet"
681                     );
682                     $replace_array = array(
683                         $this->key_name . '_',
684                         $this->key_name . 'Dashlet'
685                     );
686                     $contents = str_replace($search_array, $replace_array, $contents );
687                     
688                     
689                     if ("relationships.php" == $e) 
690                     {
691                         //bug 39598 Relationship Name Is Not Updated If Module Name Is Changed In Module Builder
692                         $contents = str_replace  ( "'{$old_name}'", "'{$this->key_name}'" , $contents ) ;
693                     }
694                     
695                     $fp = sugar_fopen ( $new_dir . '/' . $e, 'w' ) ;
696                     fwrite ( $fp, $contents ) ;
697                     fclose ( $fp ) ;
698                 }
699             }
700         }
701     }
702
703     function copy ($new_name)
704     {
705         $old = $this->getModuleDir () ;
706
707         $count = 0 ;
708         $old_name = $this->key_name;
709         $this->name = $new_name ;
710         $this->key_name = $this->package_key . '_' . $this->name ;
711         $new = $this->getModuleDir () ;
712         while ( file_exists ( $new ) )
713         {
714             $count ++ ;
715             $this->name = $new_name . $count ;
716             $this->key_name = $this->package_key . '_' . $this->name ;
717             $new = $this->getModuleDir () ;
718         }
719
720         $new = $this->getModuleDir () ;
721         $copied = copy_recursive ( $old, $new ) ;
722
723         if ($copied)
724         {
725             $this->renameMetaData ( $new , $old_name) ;
726             $this->renameLanguageFiles ( $new, true ) ;
727         }
728         return $copied ;
729
730     }
731
732     function delete ()
733     {
734         return rmdir_recursive ( $this->getModuleDir () ) ;
735     }
736
737     function populateFromPost ()
738     {
739         foreach ( $this->implementable as $key => $value )
740         {
741             $this->config [ $key ] = ! empty ( $_REQUEST [ $key ] ) ;
742         }
743         foreach ( $this->always_implement as $key => $value )
744         {
745             $this->config [ $key ] = true ;
746         }
747         if (! empty ( $_REQUEST [ 'type' ] ))
748         {
749             $this->addTemplate ( $_REQUEST [ 'type' ] ) ;
750         }
751
752         if (! empty ( $_REQUEST [ 'label' ] ))
753         {
754             $this->config [ 'label' ] = $_REQUEST [ 'label' ] ;
755         }
756
757         $this->config [ 'importable' ] = ! empty( $_REQUEST[ 'importable' ] ) ;
758
759     }
760
761     function getAvailibleSubpanelDef ($panelName)
762     {
763         $filepath = $this->getModuleDir () . "/metadata/subpanels/{$panelName}.php" ;
764         if (file_exists ( $filepath ))
765         {
766             include ($filepath) ;
767             return $subpanel_layout ;
768         }
769         return array ( ) ;
770
771     }
772
773     function saveAvailibleSubpanelDef ($panelName , $layout)
774     {
775         $dir = $this->getModuleDir () . "/metadata/subpanels" ;
776         $filepath = "$dir/{$panelName}.php" ;
777         if (mkdir_recursive ( $dir ))
778         {
779             // preserve any $module_name entry if one exists
780             if (file_exists ( $filepath ))
781             {
782                 include ($filepath) ;
783             }
784             $module_name = (isset ( $module_name )) ? $module_name : $this->key_name ;
785             $layout = "<?php\n" . '$module_name=\'' . $module_name . "';\n" . '$subpanel_layout = ' . var_export_helper ( $layout ) . ";" ;
786             $GLOBALS [ 'log' ]->debug ( "About to save this file to $filepath" ) ;
787             $GLOBALS [ 'log' ]->debug ( $layout ) ;
788             $fw = sugar_fopen ( $filepath, 'w' ) ;
789             fwrite ( $fw, $layout ) ;
790             fclose ( $fw ) ;
791         }
792     }
793
794     function getLocalSubpanelDef ($panelName)
795     {
796
797     }
798
799     function createIcon ()
800     {
801         $icondir = $this->package_path . "/icons" ;
802         mkdir_recursive ( $icondir ) ;
803         $template = "" ;
804         foreach ( $this->config [ 'templates' ] as $temp => $val )
805             $template = $temp ;
806         copy ( "themes/default/images/icon_$template.gif", "$icondir/icon_" . ucfirst ( $this->key_name ) . ".gif" ) ;
807         copy ( "include/SugarObjects/templates/$template/icons/$template.gif", "$icondir/" . $this->key_name . ".gif" ) ;
808         if (file_exists("include/SugarObjects/templates/$template/icons/Create$template.gif"))
809                 copy ( "include/SugarObjects/templates/$template/icons/Create$template.gif", "$icondir/Create" . $this->key_name . ".gif" ) ;
810         if (file_exists("include/SugarObjects/templates/$template/icons/{$template}_32.gif"))
811                 copy ( "include/SugarObjects/templates/$template/icons/{$template}_32.gif", "$icondir/icon_" . $this->key_name . "_32.gif" ) ;
812     }
813
814     function removeFieldFromLayouts ( $fieldName )
815     {
816         // hardcoded list of types for now, as also hardcoded in a different form in getNodes
817         // TODO: replace by similar mechanism to StudioModule to determine the list of available views for this module
818         $views = array ( 'editview' , 'detailview' , 'listview' , 'basic_search' , 'advanced_search' , 'dashlet' , 'popuplist');
819         
820         foreach ($views as $type )
821         {
822             $parser = ParserFactory::getParser( $type , $this->name , $this->package ) ;
823             if ($parser->removeField ( $fieldName ) )
824                 $parser->handleSave(false) ; // don't populate from $_REQUEST, just save as is...
825         }
826                 //Remove the fields in subpanel
827         $psubs = $this->getProvidedSubpanels() ; 
828         foreach ( $psubs as $sub )
829         {
830                         $parser = ParserFactory::getParser( MB_LISTVIEW , $this->name, $this->package ,  $sub) ;
831                         if ($parser->removeField ( $fieldName ) )
832                     $parser->handleSave(false) ; 
833         }
834     }
835
836     /**
837      * Returns an array of fields defs with all the link fields for this module.
838      * @return array
839      */
840     public function getLinkFields(){
841         $list = $this->relationships->getRelationshipList();
842         $field_defs = array();
843         foreach($list as $name){
844             $rel = $this->relationships->get($name);
845             $relFields = $rel->buildVardefs();
846             $relDef = $rel->getDefinition();
847             $relLabels = $rel->getLabels();
848             $relatedModule = $this->key_name == $relDef['rhs_module'] ? $relDef['lhs_module'] : $relDef['rhs_module'];
849             if (!empty($relFields[$this->key_name]))
850             {
851                 //Massage the result of getVardefs to look like field_defs
852                 foreach($relFields[$this->key_name] as $def) {
853                     $def['module'] = $relatedModule;
854                     $def['translated_label'] = empty($relLabels[$this->key_name][$def['vname']]) ?
855                         $name : $relLabels[$this->key_name][$def['vname']];
856                     $field_defs[$def['name']] = $def;
857                 }
858             }
859         }
860         
861         return $field_defs;
862     }
863
864     /**
865      * Returns a TemplateField object by name
866      * Returns a TemplateField object by name or null if field not exists. If type not set use text type as default
867      *
868      * @param string $name
869      * @return TemplateField|null
870      *
871      */
872     public function getField($name)
873     {
874         $field = null;
875         $varDefs = $this->getVardefs();
876         if (isset($varDefs['fields'][$name])){
877             $fieldVarDefs = $varDefs['fields'][$name];
878             if (!isset($fieldVarDefs['type'])){
879                 $fieldVarDefs['type'] = 'varchar';
880             }
881             $field = get_widget($fieldVarDefs['type']);
882             foreach($fieldVarDefs AS $key => $opt){
883                 $field->$key = $opt;
884             }
885         }
886         return $field;
887     }
888
889 }
890 ?>