]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/connectors/utils/ConnectorUtils.php
Release 6.1.4
[Github/sugarcrm.git] / include / connectors / utils / ConnectorUtils.php
1 <?php
2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4  * SugarCRM is a customer relationship management program developed by
5  * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
6  * 
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU Affero General Public License version 3 as published by the
9  * Free Software Foundation with the addition of the following permission added
10  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13  * 
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
17  * details.
18  * 
19  * You should have received a copy of the GNU Affero General Public License along with
20  * this program; if not, see http://www.gnu.org/licenses or write to the Free
21  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301 USA.
23  * 
24  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26  * 
27  * The interactive user interfaces in modified source and object code versions
28  * of this program must display Appropriate Legal Notices, as required under
29  * Section 5 of the GNU Affero General Public License version 3.
30  * 
31  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32  * these Appropriate Legal Notices must retain the display of the "Powered by
33  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34  * technical reasons, the Appropriate Legal Notices must display the words
35  * "Powered by SugarCRM".
36  ********************************************************************************/
37
38 define('CONNECTOR_DISPLAY_CONFIG_FILE', 'custom/modules/Connectors/metadata/display_config.php');
39 require_once('include/connectors/ConnectorFactory.php');
40
41 function sources_sort_function($a, $b) {
42         if(isset($a['order']) && isset($b['order'])) {
43            if($a['order'] == $b['order']) {
44                   return 0;
45            }
46            
47            return ($a['order'] < $b['order']) ? -1 : 1;
48         }
49         
50         return 0;
51 }
52
53 class ConnectorUtils 
54 {
55     public static function getConnector(
56         $id, 
57         $refresh = false
58         ) 
59     {
60         $s = self::getConnectors($refresh);
61         return !empty($s[$id]) ? $s[$id] : null;
62     }
63
64
65     /**
66      * getSearchDefs
67      * Returns an Array of the search field defintions Connector module to
68      * search entries from the connector.  If the searchdefs.php file in the custom 
69      * directory is not found, it defaults to using the mapping.php file entries to
70      * create a default version of the file.
71      * 
72      * @param boolean $refresh boolean value to manually refresh the search definitions
73      * @return mixed $searchdefs Array of the search definitions
74      */
75     public static function getSearchDefs(
76         $refresh = false
77         ) 
78     {
79         if($refresh || !file_exists('custom/modules/Connectors/metadata/searchdefs.php')) {
80             
81             require('modules/Connectors/metadata/searchdefs.php');
82             
83             if(!file_exists('custom/modules/Connectors/metadata')) {
84                mkdir_recursive('custom/modules/Connectors/metadata');
85             }
86             
87             if(!write_array_to_file('searchdefs', $searchdefs, 'custom/modules/Connectors/metadata/searchdefs.php')) {
88                $GLOBALS['log']->fatal("Cannot write file custom/modules/Connectors/metadata/searchdefs.php");
89                return array();  
90             }   
91         }
92         
93         require('custom/modules/Connectors/metadata/searchdefs.php');
94         return $searchdefs;     
95     }
96
97     
98     /**
99      * getViewDefs
100      * Returns an Array of the merge definitions used by the Connector module to
101      * merge values into the bean instance
102      * 
103      * @param mixed $filter_sources Array optional Array value of sources to only use
104      * @return mixed $mergedefs Array of the merge definitions
105      */
106     public static function getViewDefs(
107         $filter_sources = array()
108         ) 
109     {
110         //Go through all connectors and get their mapping keys and merge them across each module
111         $connectors = self::getConnectors();
112         $modules_sources = self::getDisplayConfig();
113         $view_defs = array();
114         foreach($connectors as $id=>$ds) {
115         
116            if(!empty($filter_sources) && !isset($filter_sources[$id])) {
117               continue;
118            }
119             
120            if(file_exists('custom/' . $ds['directory'] . '/mapping.php')) {
121              require('custom/' . $ds['directory'] . '/mapping.php');
122            } else if(file_exists($ds['directory'] . '/mapping.php')) {
123              require($ds['directory'] . '/mapping.php');
124            }
125             
126            if(!empty($mapping['beans'])) {
127               foreach($mapping['beans'] as $module=>$map) {
128                  if(!empty($modules_sources[$module][$id])) {
129                      if(!empty($view_defs['Connector']['MergeView'][$module])) {
130                         $view_defs['Connector']['MergeView'][$module] = array_merge($view_defs['Connector']['MergeView'][$module], array_flip($map));
131                      } else {
132                         $view_defs['Connector']['MergeView'][$module] = array_flip($map);
133                      }
134                  }
135               }
136            }
137         }
138         
139         if(!empty($view_defs['Connector']['MergeView'])) {
140             foreach($view_defs['Connector']['MergeView'] as $module=>$map) {
141                 $view_defs['Connector']['MergeView'][$module] = array_keys($view_defs['Connector']['MergeView'][$module]);
142             }
143         }
144         
145         return $view_defs;
146     }
147     
148     
149     /**
150      * getMergeViewDefs
151      * Returns an Array of the merge definitions used by the Connector module to
152      * merge values into the bean instance
153      * 
154      * @deprecated This method has been replaced by getViewDefs
155      * @param boolean $refresh boolean value to manually refresh the mergeview definitions
156      * @return mixed $mergedefs Array of the merge definitions
157      */
158     public static function getMergeViewDefs(
159         $refresh = false
160         ) 
161     {
162         if($refresh || !file_exists('custom/modules/Connectors/metadata/mergeviewdefs.php')) {
163             
164             //Go through all connectors and get their mapping keys and merge them across each module
165             $connectors = self::getConnectors($refresh);
166             $modules_sources = self::getDisplayConfig();
167             $view_defs = array();
168             foreach($connectors as $id=>$ds) {
169                 
170                if(file_exists('custom/' . $ds['directory'] . '/mapping.php')) {
171                  require('custom/' . $ds['directory'] . '/mapping.php');
172                } else if(file_exists($ds['directory'] . '/mapping.php')) {
173                  require($ds['directory'] . '/mapping.php');
174                }
175                 
176                if(!empty($mapping['beans'])) {
177                   foreach($mapping['beans'] as $module=>$map) {
178                      if(!empty($modules_sources[$module][$id])) {
179                          if(!empty($view_defs['Connector']['MergeView'][$module])) {
180                             $view_defs['Connector']['MergeView'][$module] = array_merge($view_defs['Connector']['MergeView'][$module], array_flip($map));
181                          } else {
182                             $view_defs['Connector']['MergeView'][$module] = array_flip($map);
183                          }
184                      }
185                   }
186                }
187             }
188             
189             if(!empty($view_defs['Connector']['MergeView'])) {
190                 foreach($view_defs['Connector']['MergeView'] as $module=>$map) {
191                     $view_defs['Connector']['MergeView'][$module] = array_keys($view_defs['Connector']['MergeView'][$module]);
192                 }
193             }
194             
195             if(!file_exists('custom/modules/Connectors/metadata')) {
196                mkdir_recursive('custom/modules/Connectors/metadata');
197             }
198             
199             if(!write_array_to_file('viewdefs', $view_defs, 'custom/modules/Connectors/metadata/mergeviewdefs.php')) {
200                $GLOBALS['log']->fatal("Cannot write file custom/modules/Connectors/metadata/mergeviewdefs.php");
201                return array();  
202             }   
203         }
204         
205         require('custom/modules/Connectors/metadata/mergeviewdefs.php');
206         return $viewdefs;
207     
208     }
209     
210     
211     /**
212      * getConnectors
213      * Returns an Array of the connectors that have been loaded into the system
214      * along with attributes pertaining to each connector.
215      * 
216      * @param boolean $refresh boolean flag indicating whether or not to force rewriting the file; defaults to false
217      * @returns mixed $connectors Array of the connector entries found
218      */
219     public static function getConnectors(
220         $refresh = false
221         ) 
222     {    
223         //define paths
224         $src1 = 'modules/Connectors/connectors/sources';
225         $src2 = 'custom/modules/Connectors/connectors/sources';
226         $src3 = 'custom/modules/Connectors/metadata';
227         $src4 = 'custom/modules/Connectors/metadata/connectors.php';
228         
229         //if this is a templated environment, then use utilities to get the proper paths
230         if(defined('TEMPLATE_URL')){
231             $src1 = SugarTemplateUtilities::getFilePath($src1);
232             $src2 = SugarTemplateUtilities::getFilePath($src2);
233             $src3 = SugarTemplateUtilities::getFilePath($src3);
234             $src4 = SugarTemplateUtilities::getFilePath($src4);         
235         }
236         
237         if($refresh || !file_exists($src4)) {
238           
239           $sources = array_merge(self::getSources($src1), self::getSources($src2));
240           if(!file_exists($src3)) {
241              mkdir_recursive($src3);
242           }
243     
244           if(!write_array_to_file('connectors', $sources, $src4)) {
245              //Log error and return empty array
246              $GLOBALS['log']->fatal("Cannot write sources to file");
247              return array();    
248           }
249         } //if
250     
251         require($src4);
252         return $connectors;
253     }
254     
255     
256     /**
257      * getSources
258      * Returns an Array of source entries found under the given directory
259      * @param String $directory The directory to search
260      * @return mixed $sources An Array of source entries
261      */
262     private static function getSources(
263         $directory = 'modules/Connectors/connectors/sources'
264         ) 
265     {
266           if(file_exists($directory)) {
267               
268               $files = array();
269               $files = findAllFiles($directory, $files, false, 'config\.php');
270               $start = strrpos($directory, '/') == strlen($directory)-1 ? strlen($directory) : strlen($directory) + 1;
271               $sources = array();
272               $sources_ordering = array();
273               foreach($files as $file) {
274                       require($file);
275                       $end = strrpos($file, '/') - $start;
276                       $source = array();
277                       $source['id'] = str_replace('/', '_', substr($file, $start, $end));
278                       $source['name'] = !empty($config['name']) ? $config['name'] : $source['id'];
279                       $source['enabled'] = true;
280                       $source['directory'] = $directory . '/' . str_replace('_', '/', $source['id']);
281                       $order = isset($config['order']) ? $config['order'] : 99; //default to end using 99 if no order set
282                       
283                       $instance = ConnectorFactory::getInstance($source['id']);
284                       $mapping = $instance->getMapping();
285                       $modules = array();
286                       if(!empty($mapping['beans'])) {
287                          foreach($mapping['beans'] as $module=>$mapping_entry) {
288                              $modules[]=$module;
289                          }
290                       }               
291                       $source['modules'] = $modules;
292                       $sources_ordering[$source['id']] = array('order'=>$order, 'source'=>$source);
293               }
294               
295               usort($sources_ordering, 'sources_sort_function');
296               foreach($sources_ordering as $entry) {
297                  $sources[$entry['source']['id']] = $entry['source'];
298               }
299               return $sources;
300           }
301           return array();
302     }
303     
304     
305     /**
306      * getDisplayConfig
307      * 
308      */
309     public static function getDisplayConfig(
310         $refresh = false
311         )
312     {    
313         if(!file_exists(CONNECTOR_DISPLAY_CONFIG_FILE) || $refresh) {
314             $sources = self::getConnectors();
315             $modules_sources = array();
316             
317             //Make the directory for the config file
318             if(!file_exists('custom/modules/Connectors/metadata')) {
319                 mkdir_recursive('custom/modules/Connectors/metadata');
320             }
321                 
322             if(!write_array_to_file('modules_sources', $modules_sources, CONNECTOR_DISPLAY_CONFIG_FILE)) {
323                 //Log error and return empty array
324                 $GLOBALS['log']->fatal("Cannot write \$modules_sources to " . CONNECTOR_DISPLAY_CONFIG_FILE);
325             }           
326                 
327         }
328         
329         require(CONNECTOR_DISPLAY_CONFIG_FILE);
330         return $modules_sources;
331     }
332     
333     
334     /**
335      * getModuleConnectors
336      *
337      * @param String $module the module to get the connectors for
338      * @param mixed $connectors Array of connectors mapped to the module or empty if none
339      * @return unknown
340      */
341     public static function getModuleConnectors(
342         $module
343         )
344     {
345         $modules_sources = self::getDisplayConfig();
346         if(!empty($modules_sources) && !empty($modules_sources[$module])){
347             $sources = array();
348             foreach($modules_sources[$module] as $index => $id){
349                 $sources[$id] = self::getConnector($id);
350             }
351             return $sources;
352         }else{
353             return array();
354         }
355     }
356     
357     /**
358      * isModuleEnabled
359      * Given a module name, checks to see if the module is enabled to be serviced by the connector module
360      * @param String $module String name of the module
361      * @return boolean $enabled boolean value indicating whether or not the module is enabled to be serviced by the connector module
362      */
363     public static function isModuleEnabled(
364         $module
365         ) 
366     {
367         $modules_sources = self::getDisplayConfig();
368         return !empty($modules_sources) && !empty($modules_sources[$module]) ? true : false;
369     }
370     
371     
372     /**
373      * isSourceEnabled
374      * Given a source id, checks to see if the source is enabled for at least one module
375      * @param String $source String name of the source
376      * @return boolean $enabled boolean value indicating whether or not the source is displayed in at least one module
377      */
378     public static function isSourceEnabled(
379         $source
380         ) 
381     {
382         $modules_sources = self::getDisplayConfig();
383         foreach($modules_sources as $module=>$mapping) {
384                 foreach($mapping as $s) {
385                         if($s == $source) {
386                            return true;         
387                         }
388                 }
389         }
390         return false;
391     }
392     
393     /**
394      * When a module has all of the sources removed from it we do not properly remove it from the viewdefs. This function
395      * will handle that.
396      *
397      * @param String $module     - the module in question
398      */
399     public static function cleanMetaDataFile(
400         $module
401         )
402     {
403         $metadata_file = file_exists("custom/modules/{$module}/metadata/detailviewdefs.php") ? "custom/modules/{$module}/metadata/detailviewdefs.php" : "modules/{$module}/metadata/detailviewdefs.php"; 
404         require($metadata_file);
405     
406         $insertConnectorButton = true;
407                      
408     
409     
410     
411        self::removeHoverField($viewdefs, $module);
412        
413         //Make the directory for the metadata file
414         if(!file_exists("custom/modules/{$module}/metadata")) {
415             mkdir_recursive("custom/modules/{$module}/metadata");
416         }                        
417              
418         if(!write_array_to_file('viewdefs', $viewdefs,  "custom/modules/{$module}/metadata/detailviewdefs.php")) {
419             $GLOBALS['log']->fatal("Cannot update file custom/modules/{$module}/metadata/detailviewdefs.php");
420             return false;
421         }
422                      
423         if(file_exists("{$GLOBALS['sugar_config']['cache_dir']}modules/{$module}/DetailView.tpl") && !unlink("{$GLOBALS['sugar_config']['cache_dir']}modules/{$module}/DetailView.tpl")) {
424             $GLOBALS['log']->fatal("Cannot delete file {$GLOBALS['sugar_config']['cache_dir']}modules/{$module}/DetailView.tpl");
425             return false;
426         }
427     }
428     
429     
430     /**
431      * updateMetaDataFiles
432      * This method updates the metadata files (detailviewdefs.php) according to the settings in display_config.php
433      * @return $result boolean value indicating whether or not the method successfully completed.
434      */
435     public static function updateMetaDataFiles() 
436     {
437         if(file_exists(CONNECTOR_DISPLAY_CONFIG_FILE)) {
438            $modules_sources = array();
439         
440            require(CONNECTOR_DISPLAY_CONFIG_FILE);
441            
442            $GLOBALS['log']->debug(var_export($modules_sources, true));
443            if(!empty($modules_sources)) {
444               foreach($modules_sources as $module=>$mapping) {
445                      $metadata_file = file_exists("custom/modules/{$module}/metadata/detailviewdefs.php") ? "custom/modules/{$module}/metadata/detailviewdefs.php" : "modules/{$module}/metadata/detailviewdefs.php"; 
446     
447                                      
448                      $viewdefs = array();
449                      if( !file_exists($metadata_file) )
450                      {
451                         $GLOBALS['log']->info("Unable to update metadata file for module: {$module}");
452                          continue;
453                      }
454                      else 
455                         require($metadata_file);
456                         
457                      $insertConnectorButton = true;
458                      
459     
460     
461     
462                      self::removeHoverField($viewdefs, $module);
463                     
464                      //Insert the hover field if available
465                      if(!empty($mapping)) {
466     
467                         require_once('include/connectors/sources/SourceFactory.php');
468                         require_once('include/connectors/formatters/FormatterFactory.php');
469                         $shown_formatters = array();
470                         foreach($mapping as $id) {
471                                 $source = SourceFactory::getSource($id, false);
472                                 if($source->isEnabledInHover() && $source->isRequiredConfigFieldsForButtonSet()) {
473                                    $shown_formatters[$id] = FormatterFactory::getInstance($id);
474                                 }   
475                         }
476     
477                         //Now we have to decide which field to put it on... use the first one for now
478                         if(!empty($shown_formatters)) {
479                             
480                            foreach($shown_formatters as $id=>$formatter) {
481                                $added_field = false;   
482                                $formatter_mapping = $formatter->getSourceMapping();
483                                
484                                $source = $formatter->getComponent()->getSource();
485                                //go through the mapping and add the hover to every field define in the mapping
486                                //1) check for hover fields
487                                $hover_fields = $source->getFieldsWithParams('hover', true);
488                                
489                                foreach($hover_fields as $key => $def){
490                                     if(!empty($formatter_mapping['beans'][$module][$key])){
491                                         $added_field = self::setHoverField($viewdefs, $module, $formatter_mapping['beans'][$module][$key], $id);
492                                     }
493                                }
494                                
495                                //2) check for first mapping field
496                                if(!$added_field && !empty($formatter_mapping['beans'][$module])) {
497                                     foreach($formatter_mapping['beans'][$module] as $key => $val){
498                                         $added_field = self::setHoverField($viewdefs, $module, $val, $id);
499                                         if($added_field){
500                                             break;
501                                         }
502                                     }
503                                }
504                            } //foreach
505                            
506                             
507     
508                            //Log an error message
509                            if(!$added_field) {
510                               $GLOBALS['log']->fatal("Unable to place hover field link on metadata for module {$module}");
511                            }
512                         }
513                         
514                      }
515                      
516                      
517                      //Make the directory for the metadata file
518                      if(!file_exists("custom/modules/{$module}/metadata")) {
519                         mkdir_recursive("custom/modules/{$module}/metadata");
520                      }                           
521              
522                      if(!write_array_to_file('viewdefs', $viewdefs,  "custom/modules/{$module}/metadata/detailviewdefs.php")) {
523                         $GLOBALS['log']->fatal("Cannot update file custom/modules/{$module}/metadata/detailviewdefs.php");
524                         return false;
525                      }
526                      
527                      if(file_exists("{$GLOBALS['sugar_config']['cache_dir']}modules/{$module}/DetailView.tpl") && !unlink("{$GLOBALS['sugar_config']['cache_dir']}modules/{$module}/DetailView.tpl")) {
528                         $GLOBALS['log']->fatal("Cannot delete file {$GLOBALS['sugar_config']['cache_dir']}modules/{$module}/DetailView.tpl");
529                         return false;
530                      }
531               }
532            }
533         }
534         return true;
535     }
536     
537     public function removeHoverField(
538         &$viewdefs, 
539         $module
540         ) 
541     {    
542         require_once('include/SugarFields/Parsers/MetaParser.php');
543         $metaParser = new MetaParser(); 
544         if(!$metaParser->hasMultiplePanels($viewdefs[$module]['DetailView']['panels'])) {
545             $keys = array_keys($viewdefs[$module]['DetailView']['panels']);
546             if(!empty($keys) && count($keys) != 1) {
547                $viewdefs[$module]['DetailView']['panels'] = array('default'=>$viewdefs[$module]['DetailView']['panels']);
548             }
549         }
550         
551         foreach($viewdefs[$module]['DetailView']['panels'] as $panel_id=>$panel) {
552           foreach($panel as $row_id=>$row) { 
553               foreach($row as $field_id=>$field) {
554                   if(is_array($field) && !empty($field['displayParams']['enableConnectors'])) {
555                     
556                      unset($field['displayParams']['enableConnectors']);
557                      unset($field['displayParams']['module']);
558                      unset($field['displayParams']['connectors']);
559                      $viewdefs[$module]['DetailView']['panels'][$panel_id][$row_id][$field_id] = $field;
560                   }
561               } //foreach
562           } //foreach
563         } //foreach
564         return false;           
565     }
566     
567     public function setHoverField(
568         &$viewdefs, 
569         $module, 
570         $hover_field, 
571         $source_id
572         ) 
573     {
574        //Check for metadata files that aren't correctly created
575        require_once('include/SugarFields/Parsers/MetaParser.php');
576        $metaParser = new MetaParser();
577        if(!$metaParser->hasMultiplePanels($viewdefs[$module]['DetailView']['panels'])) {
578             $keys = array_keys($viewdefs[$module]['DetailView']['panels']);
579             if(!empty($keys) && count($keys) != 1) {
580                $viewdefs[$module]['DetailView']['panels'] = array('default'=>$viewdefs[$module]['DetailView']['panels']);
581             }
582        }
583        
584        foreach($viewdefs[$module]['DetailView']['panels'] as $panel_id=>$panel) {
585           foreach($panel as $row_id=>$row) {
586               foreach($row as $field_id=>$field) {
587                   $name = is_array($field) ? $field['name'] : $field;
588                   if($name == $hover_field) {
589                       if(is_array($field)) {
590                          if(!empty($viewdefs[$module]['DetailView']['panels'][$panel_id][$row_id][$field_id]['displayParams'])) {
591                             $newDisplayParam = $viewdefs[$module]['DetailView']['panels'][$panel_id][$row_id][$field_id]['displayParams'];
592                             $newDisplayParam['module'] = $module;
593                             $newDisplayParam['enableConnectors'] = true;
594                             if(!is_null($source_id) && !in_array($source_id, $newDisplayParam['connectors'])){
595                                 $newDisplayParam['connectors'][] = $source_id;
596                             }
597                             $viewdefs[$module]['DetailView']['panels'][$panel_id][$row_id][$field_id]['displayParams'] = $newDisplayParam;
598                          } else {
599                             $field['displayParams'] = array('enableConnectors'=>true, 'module'=>$module, 'connectors' => array(0 => $source_id));
600                             $viewdefs[$module]['DetailView']['panels'][$panel_id][$row_id][$field_id] = $field;
601                          }
602                         
603                       } else {
604                          $viewdefs[$module]['DetailView']['panels'][$panel_id][$row_id][$field_id] = array ('name'=>$field, 'displayParams'=>array('enableConnectors'=>true, 'module'=>$module, 'connectors' => array(0 => $source_id)));
605                       }
606                       return true;
607                   }
608               }
609           }
610        }
611        return false;    
612     }
613     
614     /**
615      * setDefaultHoverField
616      * Sets the hover field to the first element in the detailview screen
617      *
618      * @param Array $viewdefs the metadata of the detailview
619      * @param String $module the Module to which the hover field should be added to
620      * @return boolean True if field was added; false otherwise
621      */
622     private function setDefaultHoverField(
623         &$viewdefs, 
624         $module, 
625         $source_id
626         ) 
627     {
628       foreach($viewdefs[$module]['DetailView']['panels'] as $panel_id=>$panel) {
629           foreach($panel as $row_id=>$row) {
630               foreach($row as $field_id=>$field) {
631                   if(is_array($field)) {
632                      if(!empty($viewdefs[$module]['DetailView']['panels'][$panel_id][$row_id][$field_id]['displayParams'])) {
633                         $viewdefs[$module]['DetailView']['panels'][$panel_id][$row_id][$field_id]['displayParams']['enableConnectors'] = true;
634                         $viewdefs[$module]['DetailView']['panels'][$panel_id][$row_id][$field_id]['displayParams']['module'] = $module;
635                         if(!is_null($source_id) && !in_array($source_id, $viewdefs[$module]['DetailView']['panels'][$panel_id][$row_id][$field_id]['displayParams']['connectors'])){
636                                 $viewdefs[$module]['DetailView']['panels'][$panel_id][$row_id][$field_id]['displayParams']['connectors'][] = $source_id;
637                         }
638                      } else {
639                         $field['displayParams'] = array('enableConnectors'=>true, 'module'=>$module, 'connectors' => array(0 => $source_id));
640                         $viewdefs[$module]['DetailView']['panels'][$panel_id][$row_id][$field_id] = $field;
641                      }
642                   } else {
643                      $viewdefs[$module]['DetailView']['panels'][$panel_id][$row_id][$field_id] = array ('name'=>$field, 'displayParams'=>array('enableConnectors'=>true, 'module'=>$module, 'connectors' => array(0 => $source_id)));
644                   }
645                   return true;
646               } //foreach
647           } //foreach
648       } //foreach
649       return false;     
650     }
651     
652     
653     /**
654      * getConnectorButtonScript
655      * This method builds the HTML code for the hover link field
656      * 
657      * @param mixed $displayParams Array value of display parameters passed from the SugarField code
658      * @param mixed $smarty The Smarty object from the calling smarty code
659      * @return String $code The HTML code for the hover link
660      */
661     public static function getConnectorButtonScript(
662         $displayParams, 
663         $smarty
664         ) 
665     {     
666         $module = $displayParams['module'];
667         require_once('include/connectors/utils/ConnectorUtils.php');
668         $modules_sources = self::getDisplayConfig();
669         global $current_language, $app_strings;
670         $mod_strings = return_module_language($current_language, 'Connectors');
671         $menuParams = 'var menuParams = "';
672         $shown_sources = array();
673         if(!empty($module) && !empty($displayParams['connectors'])) {
674             foreach($displayParams['connectors'] as $id) {
675                 if(!empty($modules_sources[$module]) && in_array($id, $modules_sources[$module])){
676                     $shown_sources[] = $id;
677                 }                         
678               }
679               
680               if(empty($shown_sources)) {
681                     return '';
682               }
683               
684               require_once('include/connectors/formatters/FormatterFactory.php'); 
685               $code = '';
686                           
687               //If there is only one source, just show the icon or some standalone view
688               if(count($shown_sources) == 1) {
689                   $formatter = FormatterFactory::getInstance($shown_sources[0]);
690                   $formatter->setModule($module);
691                   $formatter->setSmarty($smarty);
692                   $formatter_code = $formatter->getDetailViewFormat();
693                   if(!empty($formatter_code)) {
694                       $iconFilePath = $formatter->getIconFilePath();
695                       $iconFilePath = empty($iconFilePath) ? 'themes/default/images/MoreDetail.png' : $iconFilePath;
696             
697                       $code = '<img id="dswidget_img" border="0" src="' . $iconFilePath .'" alt="' . $shown_sources[0] .'" onmouseover="show_' . $shown_sources[0] . '(event);">';
698                       $code .= "<script type='text/javascript' src='{sugar_getjspath file='include/connectors/formatters/default/company_detail.js'}'></script>";
699                       $code .= $formatter->getDetailViewFormat();
700                       $code .= $formatter_code;
701                   }
702                   return $code;         
703               } else {
704      
705                   $formatterCode = '';  
706                   $sourcesDisplayed = 0;
707                   $singleIcon = '';               
708                   foreach($shown_sources as $id) {
709                       $formatter = FormatterFactory::getInstance($id);
710                       $formatter->setModule($module);
711                       $formatter->setSmarty($smarty);
712                       $buttonCode = $formatter->getDetailViewFormat();
713                       if(!empty($buttonCode)) {
714                           $sourcesDisplayed++;
715                           $singleIcon = $formatter->getIconFilePath();
716                           $source = SourceFactory::getSource($id);                            
717                           $config = $source->getConfig();
718                           $name = !empty($config['name']) ? $config['name'] : $id;
719                           //Create the menu item to call show_[source id] method in javascript
720                           $menuParams .= '<a href=\'#\' style=\'width:150px\' class=\'menuItem\' onmouseover=\'hiliteItem(this,\"yes\");\' onmouseout=\'unhiliteItem(this);\' onclick=\'show_' . $id . '(event);\'>' . $name . '</a>'; 
721                           $formatterCode .= $buttonCode;                          
722                       }   
723                   } //for
724     
725                   if(!empty($formatterCode)) {
726                       if($sourcesDisplayed > 1) {
727                         $dswidget_img = SugarThemeRegistry::current()->getImageURL('MoreDetail.png');
728                         $code = '<img id="dswidget_img" src="'.$dswidget_img.'" width="11" height="7" border="0" alt="connectors_popups" onmouseover="return showConnectorMenu2();" onmouseout="return nd(1000);">';
729                       } else {
730                           $dswidget_img = SugarThemeRegistry::current()->getImageURL('MoreDetail.png');
731                           $singleIcon = empty($singleIcon) ? $dswidget_img : $singleIcon;
732                           $code = '<img id="dswidget_img" border="0" src="' . $singleIcon . '" alt="connectors_popups" onmouseover="return showConnectorMenu2();" onmouseout="return nd(1000);">';      
733                       }
734                       $code .= "{overlib_includes}\n";
735                       $code .= "<script type='text/javascript' src='{sugar_getjspath file='include/connectors/formatters/default/company_detail.js'}'></script>\n";
736                       $code .= "<script type='text/javascript'>\n";
737                       $code .= "function showConnectorMenu2() {literal} { {/literal}\n";                          
738                       
739                       $menuParams .= '";';
740                       $code .= $menuParams . "\n";
741                       $code .= "return overlib(menuParams, CENTER, STICKY, MOUSEOFF, 3000, WIDTH, 110, FGCLASS, 'olOptionsFgClass', CGCLASS, 'olOptionsCgClass', BGCLASS, 'olBgClass', TEXTFONTCLASS, 'olFontClass', CAPTIONFONTCLASS, 'olOptionsCapFontClass', CLOSEFONTCLASS, 'olOptionsCloseFontClass');\n"; 
742                       $code .= "{literal} } {/literal}\n";
743                       $code .= "</script>\n";
744                       $code .= $formatterCode;
745                   }
746                   return $code;                   
747               } //if-else 
748         } //if
749     }
750     
751     
752     /**
753      * getConnectorStrings
754      * This method returns the language Strings for a given connector instance
755      * 
756      * @param String $source_id String value of the connector id to retrive language strings for
757      * @param String $language optional String value for the language to use (defaults to $GLOBALS['current_language'])
758      */
759     public static function getConnectorStrings(
760         $source_id, 
761         $language = ''
762         ) 
763     {
764         $lang = empty($language) ? $GLOBALS['current_language'] : $language;
765         $lang .= '.lang.php';
766         $dir = str_replace('_', '/', $source_id);
767         if(file_exists("custom/modules/Connectors/connectors/sources/{$dir}/language/{$lang}")) {
768             require("custom/modules/Connectors/connectors/sources/{$dir}/language/{$lang}");
769             return !empty($connector_strings) ? $connector_strings : array();
770         } else if(file_exists("modules/Connectors/connectors/sources/{$dir}/language/{$lang}")){
771             require("modules/Connectors/connectors/sources/{$dir}/language/{$lang}");
772             return !empty($connector_strings) ? $connector_strings : array();
773         } else {
774             $GLOBALS['log']->error("Unable to locate language string file for source {$source_id}");
775             return array();
776         }
777     }
778     
779     
780     /**
781      * installSource
782      * Install the name of the source (called from ModuleInstaller.php).  Modifies the files in the custom
783      * directory to add the new source in.
784      * 
785      * @param String $source String value of the id of the connector to install
786      * @return boolean $result boolean value indicating whether or not connector was installed
787      */
788     public static function installSource(
789         $source
790         ) 
791     {
792         if(empty($source)) {
793            return false;        
794         }
795         //Add the source to the connectors.php file
796         self::getConnectors(true);
797         
798         //Get the display config file
799         self::getDisplayConfig();
800         //Update the display_config.php file to show this new source
801         $modules_sources = array();
802         require(CONNECTOR_DISPLAY_CONFIG_FILE);
803         foreach($modules_sources as $module=>$mapping) {
804     
805             foreach($mapping as $id=>$src) {
806               if($src == $source) {
807                  unset($modules_sources[$module][$id]);
808                  break;
809               }           
810             }
811         }
812         
813         //Make the directory for the config file
814         if(!file_exists('custom/modules/Connectors/metadata')) {
815            mkdir_recursive('custom/modules/Connectors/metadata');
816         }
817             
818         if(!write_array_to_file('modules_sources', $modules_sources, CONNECTOR_DISPLAY_CONFIG_FILE)) {
819            //Log error and return empty array
820            $GLOBALS['log']->fatal("Cannot write \$modules_sources to " . CONNECTOR_DISPLAY_CONFIG_FILE);
821         }
822         return true;
823     }
824     
825     
826     /**
827      * uninstallSource
828      * 
829      * @param String $source String value of the id of the connector to un-install
830      * @return boolean $result boolean value indicating whether or not connector was un-installed
831      */
832     public static function uninstallSource(
833         $source
834         ) 
835     {
836         if(empty($source)) {
837            return false;        
838         }       
839         
840         //Remove the source from the connectors.php file
841         self::getConnectors(true);
842         
843         //Update the display_config.php file to remove this source
844         $modules_sources = array();
845         require(CONNECTOR_DISPLAY_CONFIG_FILE);
846         foreach($modules_sources as $module=>$mapping) {
847             foreach($mapping as $id=>$src) {
848                 if($src == $source) {
849                    unset($modules_sources[$module][$id]);
850                 }
851             }   
852         } 
853         
854         //Make the directory for the config file
855         if(!file_exists('custom/modules/Connectors/metadata')) {
856            mkdir_recursive('custom/modules/Connectors/metadata');
857         }
858             
859         if(!write_array_to_file('modules_sources', $modules_sources, CONNECTOR_DISPLAY_CONFIG_FILE)) {
860            //Log error and return empty array
861            $GLOBALS['log']->fatal("Cannot write \$modules_sources to " . CONNECTOR_DISPLAY_CONFIG_FILE);
862            return false;
863         }    
864         
865     
866     
867         return true;
868     }
869     
870     /**
871      * hasWizardSourceEnabledForModule
872      * This is a private method that returns a boolean value indicating whether or not at least one
873      * source is enabled for a given module.  By enabled we mean that the source has the neccessary
874      * configuration properties set as determined by the isRequiredConfigFieldsForButtonSet method.  In
875      * addition, a check is made to ensure that it is a source that has been enabled for the wizard.
876      * 
877      * @param String $module String value of module to check
878      * @return boolean $enabled boolean value indicating whether or not module has at least one source enabled
879      */
880     private static function hasWizardSourceEnabledForModule(
881         $module = ''
882         ) 
883     {
884         if(file_exists(CONNECTOR_DISPLAY_CONFIG_FILE)) {
885            require_once('include/connectors/sources/SourceFactory.php');
886            require(CONNECTOR_DISPLAY_CONFIG_FILE);
887            if(!empty($modules_sources) && !empty($modules_sources[$module])) {
888               foreach($modules_sources[$module] as $id) {
889                    $source = SourceFactory::getSource($id, false);
890                    if(!is_null($source) && $source->isEnabledInWizard() && $source->isRequiredConfigFieldsForButtonSet()) {
891                       return true;
892                    }            
893               }
894            }
895            return false;
896         }
897         return false;
898     }
899 }