]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - modules/ModuleBuilder/MB/MBModule.php
Release 6.2.0
[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-2011 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     function getRelationships()
96     {
97         return $this->relationships;
98     }
99
100     /**
101      * Loads the module based on the module name
102      *
103      */
104     function load ()
105     {
106         if (file_exists ( $this->path . '/config.php' ))
107         {
108             include ($this->path . '/config.php') ;
109             $this->config = $config ;
110         }
111         $label = (! empty ( $this->config [ 'label' ] )) ? $this->config [ 'label' ] : $this->name ;
112         $this->mblanguage = new MBLanguage ( $this->name, $this->path, $label, $this->key_name ) ;
113         foreach ( $this->iTemplate as $temp )
114         {
115             if (! empty ( $this->config [ $temp ] ))
116             {
117                 $this->mbvardefs->iTemplates [ $temp ] = 1 ;
118                 $this->mblanguage->iTemplates [ $temp ] = $temp ;
119             }
120         }
121         $this->mbvardefs->templates = $this->config [ 'templates' ] ;
122         $this->mblanguage->templates = $this->config [ 'templates' ] ;
123         $this->mbvardefs->load () ;
124         $this->mblanguage->load () ;
125
126     }
127
128     function addTemplate ($template)
129     {
130         $this->config [ 'templates' ] [ $template ] = 1 ;
131     }
132
133     function getModuleDir ()
134     {
135         return $this->package_path . '/modules/' . $this->name ;
136     }
137
138     function removeTemplate ($template)
139     {
140         unset ( $this->config [ 'templates' ] [ $template ] ) ;
141     }
142
143     function getVardefs ($by_group = false)
144     {
145         $this->mbvardefs->updateVardefs ( $by_group ) ;
146         return $this->mbvardefs->getVardefs () ;
147     }
148
149     function addField ($vardef)
150     {
151         $this->mbvardefs->addFieldVardef ( $vardef ) ;
152     }
153
154     function addFieldObject ($field)
155     {
156         $vardef = $field->get_field_def () ;
157                 $this->mbvardefs->mergeVardefs();
158                 $existingVardefs = $this->mbvardefs->getVardefs () ;
159                 //Merge with the existing vardef if it already exists
160                 if(!empty($existingVardefs['fields'][$vardef['name']])){
161                         $vardef = array_merge( $existingVardefs['fields'][$vardef['name']], $vardef);
162                 }
163         if (! empty ( $vardef [ 'source' ] ) && $vardef [ 'source' ] == 'custom_fields')
164             unset ( $vardef [ 'source' ] ) ;
165
166             $this->mbvardefs->load();
167         $this->addField ( $vardef ) ;
168         $this->mbvardefs->save();
169     }
170
171     function deleteField ($name)
172     {
173         $this->mbvardefs->deleteField ( $name ) ;
174     }
175
176     function fieldExists ($name = '' , $type = '')
177     {
178         $vardefs = $this->mbvardefs->getVardef () ;
179         if (! empty ( $vardefs ))
180         {
181             if (empty ( $type ) && empty ( $name ))
182                 return false ; else if (empty ( $type ))
183                 return ! empty ( $vardefs [ 'fields' ] [ $name ] ) ; else if (empty ( $name ))
184             {
185                 foreach ( $vardefs [ 'fields' ] as $def )
186                 {
187                     if ($def [ 'type' ] == $type)
188                         return true ;
189                 }
190                 return false ;
191             } else
192                 return (! empty ( $vardefs [ 'fields' ] [ $name ] ) && ($vardefs [ 'fields' ] [ $name ] [ 'type' ] == $type)) ;
193         } else
194         {
195             return false ;
196         }
197     }
198
199     function getModStrings ($language = 'en_us')
200     {
201         return $this->mblanguage->getModStrings ( $language ) ;
202     }
203
204     function setModStrings ($language = 'en_us' , $mod_strings)
205     {
206         $language .= '.lang.php' ;
207         $this->mblanguage->strings [ $language ] = $mod_strings ;
208     }
209
210         function setLabel ($language = 'en_us' , $key , $value)
211     {
212         $language .= '.lang.php' ;
213         $this->mblanguage->strings [ $language ] [ $key ] = $value ;
214         //Ensure this key exists in all languages
215         foreach ($this->mblanguage->strings as $lang => $values) {
216                 if (empty($values[$key])) {
217                         $this->mblanguage->strings[$lang][$key] = $value;
218                 }
219         }
220     }
221
222     function deleteLabel ($language = 'en_us' , $key)
223     {
224                 foreach ($this->mblanguage->strings as $lang => $values) {
225                 if (!empty($values[$key])) {
226                         unset($this->mblanguage->strings[$lang][$key]);
227                 }
228         }
229     }
230
231     /**
232      * Required for an MB module to work with Dynamic fields
233      */
234         function addLabel ( $displayLabel)
235     {
236         $this->setLabel('en_us', $this->getDBName($displayLabel, false), translate($displayLabel));
237         $this->save();
238     }
239
240     function getLabel ($language = 'en_us' , $key)
241     {
242         $language .= '.lang.php' ;
243         if (empty ( $this->mblanguage->strings [ $language ] [ $key ] ))
244         {
245
246             return '' ;
247         }
248         return $this->mblanguage->strings [ $language ] [ $key ] ;
249
250     }
251
252     function getAppListStrings ($language = 'en_us')
253     {
254         return $this->mblanguage->getAppListStrings ( $language ) ;
255     }
256
257     function setAppListStrings ($language = 'en_us' , $app_list_strings)
258     {
259         $language .= '.lang.php' ;
260         $this->mblanguage->appListStrings [ $language ] = $app_list_strings ;
261     }
262
263     function setDropDown ($language = 'en_us' , $key , $value)
264     {
265         $language .= '.lang.php' ;
266         $this->mblanguage->appListStrings [ $language ] [ $key ] = $value ;
267     }
268
269     function deleteDropDown ($language = 'en_us' , $key)
270     {
271         $language .= '.lang.php' ;
272         unset ( $this->mblanguage->appListStrings [ $language ] [ $key ] ) ;
273     }
274
275     function save ()
276     {
277         $this->path = $this->getModuleDir () ;
278         if (mkdir_recursive ( $this->path ))
279         {
280
281             $this->setConfigMD5 () ;
282             $old_config_md5 = $this->config_md5 ;
283             $this->saveConfig () ;
284             $this->getVardefs () ;
285             $this->mbvardefs->save ( $this->key_name ) ;
286             //           $this->mbrelationship->save ( $this->key_name ) ;
287             $this->relationships->save () ;
288             $this->copyMetaData () ;
289             $this->copyDashlet () ;
290             $this->copyViews() ;
291             if (0 != strcmp ( $old_config_md5, $this->config_md5 ))
292             {
293                 $this->mblanguage->reload () ;
294             }
295             $this->mblanguage->label = $this->config [ 'label' ] ;
296             //pass in the key_name incase it has changed mblanguage will check if it is different and handle it accordingly
297             $this->mblanguage->save ( $this->key_name ) ;
298
299             if (! file_exists ( $this->package_path . "/icons/icon_" . ucfirst ( $this->key_name ) . ".gif" ))
300             {
301                 $this->createIcon () ;
302             }
303             $this->errors = array_merge ( $this->errors, $this->mbvardefs->errors ) ;
304
305         }
306     }
307
308     function copyDashlet() {
309         $templates = array_reverse ( $this->config [ 'templates' ], true ) ;
310         foreach ( $templates as $template => $a )
311         {
312             if (file_exists ( MB_TEMPLATES . '/' . $template . '/Dashlets/Dashlet' ))
313             {
314
315                 $this->copyMetaRecursive ( MB_TEMPLATES . '/' . $template . '/Dashlets/Dashlet', $this->path . '/Dashlets/' . $this->key_name . 'Dashlet/' ) ;
316
317             }
318         }
319     }
320
321     function copyViews() {
322         $templates = array_reverse ( $this->config [ 'templates' ], true ) ;
323         foreach ( $templates as $template => $a )
324         {
325             if (file_exists ( MB_TEMPLATES . '/' . $template . '/views' ))
326             {
327                 $this->copyMetaRecursive ( MB_TEMPLATES . '/' . $template . '/views', $this->path . '/views/' ) ;
328             }
329         }
330     }
331
332     function copyCustomFiles ( $from , $to )
333     {
334         $d = dir ( $from ) ;
335         while ( $filename = $d->read () )
336         {
337                 if (substr ( $filename, 0, 1 ) == '.')
338                 continue ;
339                 if ( $filename != 'metadata' && $filename != 'Dashlets' && $filename != 'relationships' && $filename != 'language' && $filename != 'config.php' && $filename != 'relationships.php' && $filename != 'vardefs.php' )
340                         copy_recursive ( "$from/$filename" , "$to/$filename" ) ;
341         }
342     }
343
344     function copyMetaData ()
345     {
346         $templates = array_reverse ( $this->config [ 'templates' ], true ) ;
347         foreach ( $templates as $template => $a )
348         {
349             if (file_exists ( MB_TEMPLATES . '/' . $template . '/metadata' ))
350             {
351                 $this->copyMetaRecursive ( MB_TEMPLATES . '/' . $template . '/metadata', $this->path . '/metadata/' ) ;
352
353             }
354         }
355     }
356
357     function copyMetaRecursive ($from , $to , $overwrite = false)
358     {
359         if (! file_exists ( $from ))
360             return ;
361         if (is_dir ( $from ))
362         {
363             $findArray = array ( '<module_name>' , '<_module_name>' , '<MODULE_NAME>' , '<object_name>' , '<_object_name>' , '<OBJECT_NAME>' );
364             $replaceArray = array ( $this->key_name , strtolower ( $this->key_name ) , strtoupper ( $this->key_name ) ,
365                                                         $this->key_name , strtolower ( $this->key_name ) , strtoupper ( $this->key_name ) );
366                 mkdir_recursive ( $to ) ;
367             $d = dir ( $from ) ;
368             while ( $e = $d->read () )
369             {
370                 if (substr ( $e, 0, 1 ) == '.')
371                     continue ;
372                 $nfrom = $from . '/' . $e ;
373                 $nto = $to . '/' . str_replace ( 'm-n-', $this->key_name, $e ) ;
374                 if (is_dir ( $nfrom ))
375                 {
376                     $this->copyMetaRecursive ( $nfrom, $nto, $overwrite ) ;
377                 } else
378                 {
379                     if ($overwrite || ! file_exists ( $nto ))
380                     {
381                         $contents = file_get_contents ( $nfrom ) ;
382                         $contents = str_replace ( $findArray, $replaceArray, $contents ) ;
383                         $fw = sugar_fopen ( $nto, 'w' ) ;
384                         fwrite ( $fw, $contents ) ;
385                         fclose ( $fw ) ;
386                     }
387                 }
388             }
389
390         }
391     }
392
393     function saveConfig ()
394     {
395         $header = file_get_contents ( 'modules/ModuleBuilder/MB/header.php' ) ;
396         if (! write_array_to_file ( 'config', $this->config, $this->path . '/config.php', 'w', $header ))
397         {
398             $this->errors [] = 'Could not save config to ' . $this->path . '/config.php' ;
399         }
400         $this->setConfigMD5 () ;
401     }
402
403     function setConfigMD5 ()
404     {
405         if (file_exists ( $this->path . '/config.php' ))
406             $this->config_md5 = md5 ( base64_encode ( serialize ( $this->config ) ) ) ;
407     }
408
409     function build ($basepath)
410     {
411         $path = $basepath . '/modules/' . $this->key_name ;
412         if (mkdir_recursive ( $path ))
413         {
414             $this->createClasses ( $path ) ;
415             if( $this->config['importable'] || in_array ( 'person', array_keys($this->config[ 'templates' ]) ) )
416                 $this->createMenu ( $path ) ;
417             $this->copyCustomFiles ( $this->path , $path ) ;
418             $this->copyMetaRecursive ( $this->path . '/metadata/', $path . '/metadata/', true ) ;
419             $this->copyMetaRecursive ( $this->path . '/Dashlets/' . $this->key_name . 'Dashlet/',
420                                                            $path . '/Dashlets/' . $this->key_name . 'Dashlet/', true ) ;
421             $this->relationships->build ( $basepath ) ;
422             $this->mblanguage->build ( $path ) ;
423         }
424     }
425
426     function createClasses ($path)
427     {
428         $class = array ( ) ;
429         $class [ 'name' ] = $this->key_name ;
430         $class [ 'table_name' ] = strtolower ( $class [ 'name' ] ) ;
431         $class [ 'extends' ] = 'Basic' ;
432         $class [ 'requires' ] [] = MB_TEMPLATES . '/basic/Basic.php' ;
433         $class [ 'requires' ] = array ( ) ;
434         $class [ 'audited' ] = (! empty ( $this->config [ 'audit' ] )) ? 'true' : 'false' ;
435         $class [ 'acl' ] = ! empty ( $this->config [ 'acl' ] ) ;
436         $class [ 'templates' ] = "'basic'" ;
437         foreach ( $this->iTemplate as $template )
438         {
439             if (! empty ( $this->config [ $template ] ))
440             {
441                 $class [ 'templates' ] .= ",'$template'" ;
442             }
443         }
444         foreach ( $this->config [ 'templates' ] as $template => $a )
445         {
446             if ($template == 'basic')
447                 continue ;
448             $class [ 'templates' ] .= ",'$template'" ;
449             $class [ 'extends' ] = ucFirst ( $template ) ;
450             $class [ 'requires' ] [] = MB_TEMPLATES . '/' . $template . '/' . ucfirst ( $template ) . '.php' ;
451         }
452         $class [ 'importable' ] = $this->config [ 'importable' ] ;
453         $this->mbvardefs->updateVardefs () ;
454         $class [ 'fields' ] = $this->mbvardefs->vardefs [ 'fields' ] ;
455         $class [ 'fields_string' ] = var_export_helper ( $this->mbvardefs->vardef [ 'fields' ] ) ;
456         $relationship = array ( ) ;
457         $class [ 'relationships' ] = var_export_helper ( $this->mbvardefs->vardef [ 'relationships' ] ) ;
458         $smarty = new Sugar_Smarty ( ) ;
459         $smarty->left_delimiter = '{{' ;
460         $smarty->right_delimiter = '}}' ;
461         $smarty->assign ( 'class', $class ) ;
462         //write sugar generated class
463         $fp = sugar_fopen ( $path . '/' . $class [ 'name' ] . '_sugar.php', 'w' ) ;
464         fwrite ( $fp, $smarty->fetch ( 'modules/ModuleBuilder/tpls/MBModule/Class.tpl' ) ) ;
465         fclose ( $fp ) ;
466         //write vardefs
467         $fp = sugar_fopen ( $path . '/vardefs.php', 'w' ) ;
468         fwrite ( $fp, $smarty->fetch ( 'modules/ModuleBuilder/tpls/MBModule/vardef.tpl' ) ) ;
469         fclose ( $fp ) ;
470
471         if (! file_exists ( $path . '/' . $class [ 'name' ] . '.php' ))
472         {
473             $fp = sugar_fopen ( $path . '/' . $class [ 'name' ] . '.php', 'w' ) ;
474             fwrite ( $fp, $smarty->fetch ( 'modules/ModuleBuilder/tpls/MBModule/DeveloperClass.tpl' ) ) ;
475             fclose ( $fp ) ;
476         }
477         if (! file_exists ( $path . '/metadata' ))
478             mkdir_recursive ( $path . '/metadata' ) ;
479         if (! empty ( $this->config [ 'studio' ] ))
480         {
481             $fp = sugar_fopen ( $path . '/metadata/studio.php', 'w' ) ;
482             fwrite ( $fp, $smarty->fetch ( 'modules/ModuleBuilder/tpls/MBModule/Studio.tpl' ) ) ;
483             fclose ( $fp ) ;
484         } else
485         {
486             if (file_exists ( $path . '/metadata/studio.php' ))
487                 unlink ( $path . '/metadata/studio.php' ) ;
488         }
489     }
490
491     function createMenu ($path)
492     {
493         $smarty = new Sugar_Smarty ( ) ;
494         $smarty->assign ( 'moduleName', $this->key_name ) ;
495         $smarty->assign ( 'showvCard', in_array ( 'person', array_keys($this->config[ 'templates' ]) ) ) ;
496         $smarty->assign ( 'showimport', $this->config['importable'] );
497         //write sugar generated class
498         $fp = sugar_fopen ( $path . '/' . 'Menu.php', 'w' ) ;
499         fwrite ( $fp, $smarty->fetch ( 'modules/ModuleBuilder/tpls/MBModule/Menu.tpl' ) ) ;
500         fclose ( $fp ) ;
501     }
502
503     function addInstallDefs (&$installDefs)
504     {
505         $name = $this->key_name ;
506         $installDefs [ 'copy' ] [] = array ( 'from' => '<basepath>/SugarModules/modules/' . $name , 'to' => 'modules/' . $name ) ;
507         $installDefs [ 'beans' ] [] = array ( 'module' => $name , 'class' => $name , 'path' => 'modules/' . $name . '/' . $name . '.php' , 'tab' => $this->config [ 'has_tab' ] ) ;
508         $this->relationships->addInstallDefs ( $installDefs ) ;
509     }
510
511     function getNodes ()
512     {
513
514         $lSubs = array ( ) ;
515         $psubs = $this->getProvidedSubpanels () ;
516         foreach ( $psubs as $sub )
517         {
518             $subLabel = $sub ;
519             if ($subLabel == 'default')
520             {
521                 $subLabel = $GLOBALS [ 'mod_strings' ] [ 'LBL_DEFAULT' ] ;
522             }
523             $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' ) ;
524         }
525
526         $searchSubs = array ( ) ;
527         $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}"  ) ;
528         $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  ) ;
529         $dashlets = array( );
530         $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 );
531                 $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 );
532
533                 $popups = array( );
534         $popups [] = array('name' => translate('LBL_POPUPLISTVIEW') , 'type' => 'popuplistview' , 'action' => 'module=ModuleBuilder&action=editLayout&view=popuplist&view_module=' . $this->name . '&view_package=' . $this->package );
535                 $popups [] = array('name' => translate('LBL_POPUPSEARCH') , 'type' => 'popupsearch' , 'action' => 'module=ModuleBuilder&action=editLayout&view=popupsearch&view_module=' . $this->name . '&view_package=' . $this->package );
536                 
537         $layouts = array (
538                 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 ) ,
539                 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 ) ,
540                 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 ) ,
541                 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 ) ,
542                 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  ),
543                 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  ),
544                 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 )
545                 ) ;
546
547         $children = array (
548                 array ( 'name' => translate('LBL_FIELDS') , 'action' => 'module=ModuleBuilder&action=modulefields&view_module=' . $this->name . '&view_package=' . $this->package ) ,
549                 array ( 'name' => translate('LBL_LABELS') , 'action' => 'module=ModuleBuilder&action=modulelabels&view_module=' . $this->name . '&view_package=' . $this->package ) ,
550                 array ( 'name' => translate('LBL_RELATIONSHIPS') , 'action' => 'module=ModuleBuilder&action=relationships&view_module=' . $this->name . '&view_package=' . $this->package ) ,
551                 array ( 'name' => translate('LBL_LAYOUTS') , 'type' => 'Folder' , 'action' => "module=ModuleBuilder&action=wizard&view_module={$this->name}&view_package={$this->package}&MB=1" , 'children' => $layouts ) ,
552                 ) ;
553
554         if (count ( $lSubs ) > 0)
555         {
556             $children [] = array ( 'name' => translate('LBL_AVAILABLE_SUBPANELS') , 'type' => 'folder' , 'children' => $lSubs ) ;
557         }
558
559         $nodes = array ( 'name' => $this->name , 'children' => $children , 'action' => 'module=ModuleBuilder&action=module&view_module=' . $this->name . '&view_package=' . $this->package ) ;
560
561         return $nodes ;
562     }
563
564
565     function getProvidedSubpanels ()
566     {
567         $this->providedSubpanels = array () ;
568
569         $subpanelDir = $this->getModuleDir () . '/metadata/subpanels/' ;
570         if (file_exists ( $subpanelDir ))
571         {
572             $f = dir ( $subpanelDir ) ;
573             require_once 'modules/ModuleBuilder/parsers/relationships/AbstractRelationships.php' ;
574
575             while ( $g = $f->read () )
576             {
577                 // sanity check to confirm that this is a usable subpanel...
578                 if (substr ( $g, 0, 1 ) != '.' && AbstractRelationships::validSubpanel ( $subpanelDir . $g ))
579                 {
580                     $subname = str_replace ( '.php', '', $g ) ;
581                     $this->providedSubpanels [ $subname ] = $subname ;
582                 }
583             }
584         }
585
586         return $this->providedSubpanels;
587     }
588
589     function getTypes ()
590     {
591         $types = array ( ) ;
592         $d = dir ( MB_TEMPLATES ) ;
593         while ( $e = $d->read () )
594         {
595             if (substr ( $e, 0, 1 ) != '.')
596             {
597                 $types [ $e ] = $e ;
598             }
599         }
600
601         return $types ;
602     }
603
604     function rename ($new_name)
605     {
606         $old = $this->getModuleDir () ;
607         $old_name = $this->key_name;
608         $this->name = $new_name ;
609         $this->key_name = $this->package_key . '_' . $this->name ;
610         $new = $this->getModuleDir () ;
611         if (file_exists ( $new ))
612         {
613             return false ;
614         }
615         $renamed = rename ( $old, $new ) ;
616         if ($renamed)
617         {
618             $this->renameMetaData ( $new , $old_name) ;
619             $this->renameLanguageFiles ( $new ) ;
620
621         }
622         return $renamed ;
623     }
624
625         function renameLanguageFiles ($new_dir , $duplicate = false)
626     {
627
628         $this->mblanguage->name = $this->name ;
629         $this->mblanguage->path = $new_dir ;
630         $this->mblanguage->generateAppStrings () ;
631         $this->mblanguage->save ( $this->key_name, $duplicate, true) ;
632     }
633
634     function renameMetaData ($new_dir, $old_name)
635     {
636         $GLOBALS [ 'log' ]->debug ( 'MBModule.php->renameMetaData: new_dir=' . $new_dir ) ;
637         if (! file_exists ( $new_dir ))
638             return ;
639         $dir = dir ( $new_dir ) ;
640         while ( $e = $dir->read () )
641         {
642             if (substr ( $e, 0, 1 ) != '.')
643             {
644                 if (is_dir ( $new_dir . '/' . $e ))
645                 {
646                     $this->renameMetaData ( $new_dir . '/' . $e,  $old_name) ;
647                 }
648                 if (is_file ( $new_dir . '/' . $e ))
649                 {
650                     $contents = file_get_contents ( $new_dir . '/' . $e ) ;
651                     $contents = preg_replace ( '/(\$module_name[ ]*=[ ]*\')(.*)(\'[ ]*;)/', '$1' . $this->key_name . '$3', $contents ) ;
652                     $contents = preg_replace ( '/(\$_module_name[ ]*=[ ]*\')(.*)(\'[ ]*;)/', '$1' . strtolower ( $this->key_name ) . '$3', $contents ) ;
653                     $contents = preg_replace ( '/(\$MODULE_NAME[ ]*=[ ]*\')(.*)(\'[ ]*;)/', '$1' . strtoupper ( $this->key_name ) . '$3', $contents ) ;
654                     $contents = preg_replace ( '/(\$object_name[ ]*=[ ]*\')(.*)(\'[ ]*;)/', '$1' . $this->key_name . '$3', $contents ) ;
655                     $contents = preg_replace ( '/(\$_object_name[ ]*=[ ]*\')(.*)(\'[ ]*;)/', '$1' . strtolower ( $this->key_name ) . '$3', $contents ) ;
656                     $contents = preg_replace ( '/(\$OBJECT_NAME[ ]*=[ ]*\')(.*)(\'[ ]*;)/', '$1' . strtoupper ( $this->key_name ) . '$3', $contents ) ;
657                     $contents = str_replace  ( "{$old_name}_", $this->key_name . "_", $contents ) ;
658                     $fp = sugar_fopen ( $new_dir . '/' . $e, 'w' ) ;
659                     fwrite ( $fp, $contents ) ;
660                     fclose ( $fp ) ;
661                 }
662             }
663         }
664
665     }
666
667     function copy ($new_name)
668     {
669         $old = $this->getModuleDir () ;
670
671         $count = 0 ;
672         $old_name = $this->key_name;
673         $this->name = $new_name ;
674         $this->key_name = $this->package_key . '_' . $this->name ;
675         $new = $this->getModuleDir () ;
676         while ( file_exists ( $new ) )
677         {
678             $count ++ ;
679             $this->name = $new_name . $count ;
680             $this->key_name = $this->package_key . '_' . $this->name ;
681             $new = $this->getModuleDir () ;
682         }
683
684         $new = $this->getModuleDir () ;
685         $copied = copy_recursive ( $old, $new ) ;
686
687         if ($copied)
688         {
689             $this->renameMetaData ( $new , $old_name) ;
690             $this->renameLanguageFiles ( $new, true ) ;
691         }
692         return $copied ;
693
694     }
695
696     function delete ()
697     {
698         return rmdir_recursive ( $this->getModuleDir () ) ;
699     }
700
701     function populateFromPost ()
702     {
703         foreach ( $this->implementable as $key => $value )
704         {
705             $this->config [ $key ] = ! empty ( $_REQUEST [ $key ] ) ;
706         }
707         foreach ( $this->always_implement as $key => $value )
708         {
709             $this->config [ $key ] = true ;
710         }
711         if (! empty ( $_REQUEST [ 'type' ] ))
712         {
713             $this->addTemplate ( $_REQUEST [ 'type' ] ) ;
714         }
715
716         if (! empty ( $_REQUEST [ 'label' ] ))
717         {
718             $this->config [ 'label' ] = $_REQUEST [ 'label' ] ;
719         }
720
721         $this->config [ 'importable' ] = ! empty( $_REQUEST[ 'importable' ] ) ;
722
723     }
724
725     function getAvailibleSubpanelDef ($panelName)
726     {
727         $filepath = $this->getModuleDir () . "/metadata/subpanels/{$panelName}.php" ;
728         if (file_exists ( $filepath ))
729         {
730             include ($filepath) ;
731             return $subpanel_layout ;
732         }
733         return array ( ) ;
734
735     }
736
737     function saveAvailibleSubpanelDef ($panelName , $layout)
738     {
739         $dir = $this->getModuleDir () . "/metadata/subpanels" ;
740         $filepath = "$dir/{$panelName}.php" ;
741         if (mkdir_recursive ( $dir ))
742         {
743             // preserve any $module_name entry if one exists
744             if (file_exists ( $filepath ))
745             {
746                 include ($filepath) ;
747             }
748             $module_name = (isset ( $module_name )) ? $module_name : $this->key_name ;
749             $layout = "<?php\n" . '$module_name=\'' . $module_name . "';\n" . '$subpanel_layout = ' . var_export_helper ( $layout ) . ";" ;
750             $GLOBALS [ 'log' ]->debug ( "About to save this file to $filepath" ) ;
751             $GLOBALS [ 'log' ]->debug ( $layout ) ;
752             $fw = sugar_fopen ( $filepath, 'w' ) ;
753             fwrite ( $fw, $layout ) ;
754             fclose ( $fw ) ;
755         }
756     }
757
758     function getLocalSubpanelDef ($panelName)
759     {
760
761     }
762
763     function createIcon ()
764     {
765         $icondir = $this->package_path . "/icons" ;
766         mkdir_recursive ( $icondir ) ;
767         $template = "" ;
768         foreach ( $this->config [ 'templates' ] as $temp => $val )
769             $template = $temp ;
770         copy ( "themes/default/images/icon_$template.gif", "$icondir/icon_" . ucfirst ( $this->key_name ) . ".gif" ) ;
771         copy ( "include/SugarObjects/templates/$template/icons/$template.gif", "$icondir/" . $this->key_name . ".gif" ) ;
772         if (file_exists("include/SugarObjects/templates/$template/icons/Create$template.gif"))
773                 copy ( "include/SugarObjects/templates/$template/icons/Create$template.gif", "$icondir/Create" . $this->key_name . ".gif" ) ;
774         if (file_exists("include/SugarObjects/templates/$template/icons/{$template}_32.gif"))
775                 copy ( "include/SugarObjects/templates/$template/icons/{$template}_32.gif", "$icondir/icon_" . $this->key_name . "_32.gif" ) ;
776     }
777
778     function removeFieldFromLayouts ( $fieldName )
779     {
780         // hardcoded list of types for now, as also hardcoded in a different form in getNodes
781         // TODO: replace by similar mechanism to StudioModule to determine the list of available views for this module
782         $views = array ( 'editview' , 'detailview' , 'listview' , 'basic_search' , 'advanced_search' , 'dashlet' , 'popuplist');
783         
784         foreach ($views as $type )
785         {
786             $parser = ParserFactory::getParser( $type , $this->name , $this->package ) ;
787             if ($parser->removeField ( $fieldName ) )
788                 $parser->handleSave(false) ; // don't populate from $_REQUEST, just save as is...
789         }
790                 //Remove the fields in subpanel
791         $psubs = $this->getProvidedSubpanels() ; 
792         foreach ( $psubs as $sub )
793         {
794                         $parser = ParserFactory::getParser( MB_LISTVIEW , $this->name, $this->package ,  $sub) ;
795                         if ($parser->removeField ( $fieldName ) )
796                     $parser->handleSave(false) ; 
797         }
798     }
799
800 }
801 ?>