]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - modules/UpgradeWizard/SugarMerge/EditViewMerge.php
Release 6.4.0
[Github/sugarcrm.git] / modules / UpgradeWizard / SugarMerge / EditViewMerge.php
1 <?php
2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4  * SugarCRM Community Edition 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 /*********************************************************************************
39
40  * Description:  Defines the English language pack for the base application.
41  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
42  * All Rights Reserved.
43  * Contributor(s): ______________________________________..
44  ********************************************************************************/
45  
46 /**
47  * This is the base class that all other SugarMerge objects extend 
48  *
49  */
50 class EditViewMerge{
51         /**
52          * The variable name that is used with the file for example in editviewdefs and detailviewdefs it is $viewdefs
53          *
54          * @var STRING
55          */
56         protected $varName = 'viewdefs';
57         /**
58          * Enter the name of the parameter used in the $varName for example in editviewdefs and detailviewdefs it is 'EditView' and 'DetailView' respectively - $viewdefs['EditView']
59          *
60          * @var STRING
61          */
62         protected $viewDefs = 'EditView';
63         /**
64          * this will store the meta data for the original file
65          *
66          * @var ARRAY
67          */
68         protected $originalData = array();
69         /**
70          * this will store the meta data for the new file
71          *
72          * @var ARRAY
73          */
74         protected $newData = array();
75         /**
76          * this will store the meta data for the custom file
77          *
78          * @var ARRAY
79          */
80         protected $customData = array();
81         /**
82          * this will store an associative array contianing all the fields that are used in the original meta data file
83          *
84          * @var ARRAY
85          */
86         protected $originalFields = array();
87         /**
88          * this will store an associative array contianing all the fields that are used in the new meta data file
89          *
90          * @var ARRAY
91          */
92         protected $newFields = array();
93         /**
94          * this will store an associative array contianing all the fields that are used in the custom meta data file
95          *
96          * @var ARRAY
97          */
98         protected $customFields = array();
99         /**
100          * this will store an associative array contianing all the merged fields 
101          *
102          * @var ARRAY
103          */
104         protected $mergedFields = array();
105         /**
106          * the name of the module to be merged
107          *
108          * @var STRING
109          */
110         protected $module = 'module';
111         /**
112          * the max number of columns for this view
113          *
114          * @var INT
115          */
116         protected $maxCols = 2;
117         /**
118          * If we should use the best match algorithim
119          *
120          * @var BOOLEAN
121          */
122         protected $bestMatch = true;
123         /**
124          * The default panel we place the fields in if we aren't using the best match algorithim
125          *
126          * @var STRING
127          */
128         protected $defaultPanel = 'default';
129         /**
130          * The name of the panels section in the meta data
131          *
132          * @var STRING
133          */
134         protected $panelName = 'panels';
135         /**
136          * The name of the templateMeta data secion in the meta data
137          */
138         protected $templateMetaName = 'templateMeta';
139         /**
140          * The file pointer to log to if set to NULL it will use the GLOBALS['log'] if available and log to debug
141          *
142          * @var FILEPOINTER
143          */
144         protected $fp = NULL;
145         
146         
147         /**
148          * Determines if getFields should analyze panels to determine if it is a MultiPanel
149          *
150          * @var unknown_type
151          */
152         protected $scanForMultiPanel = true;
153         
154         /**
155          * If true then it works as though it's a multipanel
156          *
157          * @var BOOLEAN
158          */
159         protected $isMultiPanel = true;
160         
161         
162         /**
163          * The ids of the panels found in custom metadata fuke
164          * 
165          */
166         protected $customPanelIds = array();
167         
168         
169         /**
170          * The ids of the panels found in original metadata fuke
171          * 
172          */
173         protected $originalPanelIds = array();
174
175
176         /**
177          * The ids of the panels found in original metadata fuke
178          * 
179          */
180         protected $newPanelIds = array();       
181         
182         
183         /**
184          * Special case conversion
185          * 
186          */
187         protected $fieldConversionMapping = array(
188                         'Campaigns' => array('created_by_name'=>'date_entered', 'modified_by_name'=>'date_modified'),
189             'Cases' => array('created_by_name'=>'date_entered', 'modified_by_name'=>'date_modified'),
190                         'Contracts' => array('created_by_name'=>'date_entered', 'modified_by_name'=>'date_modified'),
191                         'Leads' => array('created_by'=>'date_entered'),
192             'Meetings' => array('created_by_name'=>'date_entered', 'modified_by_name'=>'date_modified'),
193                         'ProspectLists' => array('created_by_name'=>'date_entered', 'modified_by_name'=>'date_modified'),
194             'Prospects' => array('created_by_name'=>'date_entered', 'modified_by_name'=>'date_modified'),
195             'Tasks' => array('created_by_name'=>'date_entered', 'modified_by_name'=>'date_modified'),
196         );
197         
198         /**
199          * Clears out the values of the arrays so that the same object can be utilized
200          *
201          */
202         protected function clear(){
203                 unset($this->newData);
204                 $this->newData = array();
205                 unset($this->customData);
206                 $this->customData = array();
207                 unset($this->originalData);
208                 $this->originalData = array();
209                 unset($this->newFields);
210                 $this->newFields = array();
211                 unset($this->customFields);
212                 $this->customFields = array();
213                 unset($this->originalFields);
214                 $this->originalFields = array();
215                 unset($this->mergedFields);
216                 $this->mergedFields = array();
217                 unset($this->mergeData);
218                 $this->mergeData = array();
219                 $this->defaultPanel = 'default';
220         }
221         
222         /**
223          * Allows the user to choose to use the best match algorithim or not
224          *
225          * @param BOOLEAN $on
226          */
227         public function setBestMatch($on=true){
228                 $this->bestMatch = $on;
229         }
230         
231         
232         /**
233          * Allows users to set the name to use as the default panel in the meta data
234          *
235          * @param STRING $name - name of the default panel
236          */
237         public function setDefaultPanel($name = 'default'){
238                 $this->defaultPanel = $name;
239         }
240         
241         /**
242          * Allows the user to set a filepointer that is already open to log to
243          *
244          * @param FILEPOINTER $fp
245          */
246         public function setLogFilePointer($fp){
247                 $this->fp = $fp;
248         }
249         
250         /**
251          * opens the file with the 'a' parameter and use it to log messages to
252          *
253          * @param STRING $file - path to file we wish to log to
254          */
255         public function setLogFile($file){
256                 $this->fp = fopen($file, 'a');
257         }
258         
259         /**
260          * 
261          */
262         /**
263          * returns true if $val1 and $val2 match otherwise it returns false
264          *
265          * @param MULTI $val1 - a value to compare to val2
266          * @param MULTI $val2 - a value to compare to val1
267          * @return BOOLEAN - if $val1 and $val2 match
268          */
269         protected function areMatchingValues($val1, $val2){
270                 if(!is_array($val1)){
271                         //if val2 is an array and val1 isn't then it isn't a match
272                         if(is_array($val2)){
273                                 return false;
274                         }
275                         //otherwise both are not arrays so we can return a comparison between them
276                         return $val1 == $val2;
277                 }else{
278                         //if val1 is an array and val2 isn't then it isn't a match
279                         if(!is_array($val2)){
280                                 return false;
281                         }
282                 }
283                 foreach($val1 as $k=>$v){
284                         if(!isset($val2[$k]))return false;
285                         if(!$this->areMatchingValues($val1[$k], $val2[$k])){
286                                 return false;
287                         }
288                         unset($val2[$k]);
289                         unset($val1[$k]);
290                 }
291                 //this implies that there are still values left  so the two must not match since we unset any matching values
292                 if(!empty($val2)){
293                         return false;
294                 }
295                 return true;
296         }
297         
298         /**
299          * Recursiveley merges two arrays
300          *
301          * @param ARRAY $gimp - if keys match this arrays values are overriden 
302          * @param ARRAY $dom - if keys match this arrays values will override the others
303          * @return ARRAY $merged - the merges array
304          */
305         function arrayMerge($gimp, $dom) {
306         if(is_array($gimp) && is_array($dom)) {
307                 foreach($dom as $domKey => $domVal) {
308                         if(isset($gimp[$domKey])) {
309                                 if(is_array($domVal)) {
310                                         $gimp[$domKey] = $this->arrayMerge($gimp[$domKey], $dom[$domKey]);
311                                 } else {
312                                         $gimp[$domKey] = $domVal;
313                                 }
314                         } else {
315                                 $gimp[$domKey] = $domVal;
316                         }
317                 }
318         }
319         return $gimp;
320 }
321         
322         /**
323          * Merges the meta data of a single field
324          *
325          * @param ARRAY $orig - the original meta-data for this field
326          * @param ARRAY $new - the new meta-data for this field
327          * @param ARRAY $custom - the custom meta-data for this field
328          * @return ARRAY $merged - the merged meta-data
329          */
330         protected function mergeField($orig, $new, $custom){
331                 $orig_custom = $this->areMatchingValues($orig, $custom);
332                 $new_custom = $this->areMatchingValues($new, $custom);
333                 // if both are true then there is nothing to merge since all three fields match
334                 if(!($orig_custom && $new_custom)){
335                         $this->log('merging field');
336                         $this->log('original meta-data');
337                         $this->log($orig);
338                         $this->log('new meta-data');
339                         $this->log($new);
340                         $this->log('custom meta-data');
341                         $this->log($custom);
342                         $this->log('merged meta-data');
343                         $log = true;
344                 }else{
345                         return $new;
346                 }
347                 //if orignal and custom match always take the new value or if new and custom match
348                 if($orig_custom || $new_custom){
349                         $this->log($new);
350                         return $new;
351                 }
352                 //if original and new match always take the custom
353                 if($this->areMatchingValues($orig, $new)){
354                         $this->log($custom);
355                         return $custom;
356                 }
357                 
358                 if(is_array($custom)) {
359                         //if both new and custom are arrays then at this point new != custom and orig != custom and orig != new  so let's merge the custom and the new and return that
360                         if(is_array($new)){
361                                 $new = $this->arrayMerge($custom, $new);
362                                 $this->log($new);
363                                 return $new;
364                         }else{
365                                 //otherwise we know that new is not an array and custom has been 'customized' so let's keep those customizations.
366                                 $this->log($custom);
367                                 return $custom;
368                         }
369                 }
370                 //default to returning the New version of the field 
371                 $this->log($new);
372                 return $new; 
373         }
374         
375         /**
376          * Merges the fields together and stores them in $this->mergedFields
377          *
378          */
379         protected function mergeFields() {
380                 foreach($this->customFields as $field=>$data) {
381                         //if we have this field in both the new fields and the original fields - it has existed since the last install/upgrade
382                         if(isset($this->newFields[$field]) && isset($this->originalFields[$field])){                            
383                                 //if both the custom field and the original match then we take the location of the custom field since it hasn't moved
384                                 $loc = $this->customFields[$field]['loc'];
385                                 $loc['source'] = 'custom';      
386
387                                 $do_merge = true;
388                                 
389                                 //Address fields present a special problem...
390                                 if(preg_match('/(alt_|primary_|billing_|shipping_)address_street/i', $field, $matches)) {
391                                    $prefix = $matches[1];
392                                    $city = $prefix . 'address_city';
393                                    $postal_code = $prefix . 'address_postalcode';
394                                    $state = $prefix . 'address_state';
395                                    $country = $prefix . 'address_country';
396                                    
397                                    if(isset($this->customFields[$city]) || 
398                                       isset($this->customFields[$postal_code]) || 
399                                       isset($this->customFields[$state]) || 
400                                       isset($this->customFields[$country])) {
401                             $do_merge = false;
402                             $this->mergedFields[$field] = array(
403                                                         'data'=>$this->customFields[$field]['data'], 
404                                                         'loc'=>$loc);
405                                       }
406                                 }                       
407                                 
408                                 if($do_merge) {
409                                         //but we still merge the meta data of the three
410                                         $this->mergedFields[$field] = array(
411                                                 'data'=>$this->mergeField($this->originalFields[$field]['data'], $this->newFields[$field]['data'], $this->customFields[$field]['data']), 
412                                                 'loc'=>$loc);
413                                 }
414                         //if it's not set in the new fields then it was a custom field or an original field so we take the custom fields data and set the location source to custom
415                         } else if(!isset($this->newFields[$field])){
416                                 $this->mergedFields[$field] = $data;
417                                 $this->mergedFields[$field]['loc']['source'] = 'custom';
418                         } else {        
419                                 //otherwise  the field is in both new and custom but not in the orignal so we merge the new and custom data together and take the location from the custom
420                                 $this->mergedFields[$field] = array(
421                                         'data'=>$this->mergeField('', $this->newFields[$field]['data'], $this->customFields[$field]['data']), 
422                                         'loc'=>$this->customFields[$field]['loc']);
423                                 
424                                 $this->mergedFields[$field]['loc']['source'] = 'custom';
425                                 //echo var_export($this->mergedFields[$field], true);
426                         }
427                         
428                         //then we clear out the field from 
429                         unset($this->originalFields[$field]);
430                         unset($this->customFields[$field]);
431                         unset($this->newFields[$field]);
432                 }
433                 
434                 
435                 /**
436                  * These are fields that were removed by the customer
437                  */
438                 foreach($this->originalFields as $field=>$data){
439                         unset($this->originalFields[$field]);
440                         unset($this->newFields[$field]);
441                 }
442                 
443                 /**
444                  * These are fields that were added by sugar
445                  */
446                 $new_field_panel = $this->defaultPanel;
447             foreach($this->customPanelIds as $custom_panel_ids=>$panels) {
448                                 $new_field_panel = $custom_panel_ids;
449                 }               
450                 
451                 foreach($this->newFields as $field=>$data){
452                         $data['loc']['source']= 'new';
453                         $data['loc']['panel'] = $new_field_panel;
454                         $this->mergedFields[$field] = array(
455                                         'data'=>$data['data'], 
456                                         'loc'=>$data['loc']);
457                         unset($this->newFields[$field]);
458                 }
459         }
460         
461         /**
462          * Walks through the merged fields and places them in the appropriate place based on their location parameter as well as the choosen algorithim
463          *
464          * @return ARRAY $panels - the new panels section for the merged file
465          */
466         protected function buildPanels(){
467                 $panels  = array();
468                 
469                 $panel_keys = array_keys($this->customPanelIds);
470                 $this->defaultPanel = end($panel_keys);
471                 
472                 foreach($this->mergedFields as $field_id=>$field){                      
473                         //If this field is in a panel not defined in the custom layout, set it to default panel
474                         if(!isset($this->customPanelIds[$field['loc']['panel']])) {
475                            $field['loc']['panel'] = $this->defaultPanel;
476                         }
477                         
478                         if($field['loc']['source'] == 'new') {
479                                 if($this->bestMatch){
480                                         //for best match as long as the column is filled let's keep walking down till we can fill it
481                                         $row = end(array_keys($this->customData[$this->module][$this->viewDefs][$this->panelName][$field['loc']['panel']]));
482                                         $col = 0;
483                                         while(!empty($panels[$field['loc']['panel']][$row][$col])){
484                                                 $col++;
485                                                 if($col == 2) {
486                                                    $row++;
487                                                    $col = 0;
488                                                 }
489                                         }
490                                         //row should be at a point that there is no field in this location
491                                         $panels[$field['loc']['panel']][$row][$col] = $field['data'];
492                                 }else{
493                                         //so for not best match we place it in the default panel at the first available column for the row
494                                         $row = 0;
495                                         while(!empty($panels[$this->defaultPanel][$row][$field['loc']['col']])){
496                                                 $row++;
497                                         }
498                                         $panels[$field['loc']['panel']][$row][$field['loc']['col']] = $field['data'];
499                                 }                               
500                         } else {
501                                 $panels[$field['loc']['panel']][$field['loc']['row']][$field['loc']['col']] = $field['data'];
502                         }
503                         
504
505                 }
506                 
507                 foreach($panels as $k=>$panel){
508                         foreach($panel as $r=>$row){
509                                         ksort($panels[$k][$r]);
510                         }
511                         ksort($panels[$k]);
512                 }
513                 
514                 return $panels;
515         }
516         
517         /**
518          * Merge the templateMeta entry for the view defs.  Also assume that any changes made in the custom files should
519          * have precedence since they must be changed manually, even over new files that may be provided in the upgarde
520          * patch.
521          *
522          */
523         protected function mergeTemplateMeta()
524         {
525         //this is to handle the situation in Calls/Meetings where we updated the templateMeta and will fail if we don't update this.
526         //long term we should not do this and should provide a way for calls/meetings to update themselves.
527             if( isset($this->customData[$this->module][$this->viewDefs][$this->templateMetaName]) && strcmp(strtolower($this->module), 'calls') != 0 && strcmp(strtolower($this->module), 'meetings') != 0 )
528             {   
529                 $this->newData[$this->module][$this->viewDefs][$this->templateMetaName] = $this->customData[$this->module][$this->viewDefs][$this->templateMetaName];
530             }
531
532         }
533         
534         /**
535          * Sets the panel section for the meta-data after it has been merged
536          *
537          */
538         protected function setPanels(){
539                 $this->newData[$this->module][$this->viewDefs][$this->panelName] = $this->buildPanels();
540                 /*
541                 if(!$this->isMultiPanel) {
542                    $this->newData[$this->module][$this->viewDefs][$this->panelName] = $this->newData[$this->module][$this->viewDefs][$this->panelName][$this->defaultPanel];
543                 }
544         */
545         }
546         
547         /**
548          * Parses out the fields for each files meta data and then calls on mergeFields and setPanels
549          *
550          */
551         protected function mergeMetaData(){
552                 $this->originalFields = $this->getFields($this->originalData[$this->module][$this->viewDefs][$this->panelName]);
553                 $this->originalPanelIds = $this->getPanelIds($this->originalData[$this->module][$this->viewDefs][$this->panelName]);
554                 $this->customFields = $this->getFields($this->customData[$this->module][$this->viewDefs][$this->panelName]);
555                 $this->customPanelIds = $this->getPanelIds($this->customData[$this->module][$this->viewDefs][$this->panelName]);                
556                 $this->newFields = $this->getFields($this->newData[$this->module][$this->viewDefs][$this->panelName]);
557                 //echo var_export($this->newFields, true);
558                 $this->newPanelIds = $this->getPanelIds($this->newData[$this->module][$this->viewDefs][$this->panelName]);
559                 $this->mergeFields();
560                 $this->mergeTemplateMeta();
561                 $this->setPanels();
562         }
563         /**
564          * This takes in a  list of panels and returns an associative array of field names to the meta-data of the field as well as the locations of that field
565          *
566          * @param ARRAY $panels - this is the 'panel' section of the meta-data
567          * @return ARRAY $fields - an associate array of fields and their meta-data as well as their location
568          */
569         protected function getFields(&$panels){
570
571                 $fields = array();
572                 $blanks = 0;
573         $setDefaultPanel = false;
574   
575                 if(count($panels) == 1) {
576                    $arrayKeys = array_keys($panels);
577                    if(!empty($arrayKeys[0])) {
578                           $this->defaultPanel = $arrayKeys[0];
579                       $panels = $panels[$arrayKeys[0]];
580                    } else {
581                           $panels = $panels[''];
582                    }
583                    $setDefaultPanel = true;   
584                 }               
585                 
586                 if($this->scanForMultiPanel){
587                         require_once('include/SugarFields/Parsers/MetaParser.php');                     
588                         if($setDefaultPanel || !MetaParser::hasMultiplePanels($panels)) {
589                            $panels = array($this->defaultPanel=>$panels);
590                            $this->isMultiPanel = false;
591                         }
592                 }
593                 
594                 //echo "---------------------------------------------------------\n";
595                 //echo var_export($panels, true);
596                 
597                 foreach($panels as $panel_id=>$panel){  
598                         foreach($panel as $row_id=>$rows){
599                                 foreach($rows as $col_id=>$col){
600                                         if(empty($col)) {
601                                            $field_name = 'BLANK_' . $blanks;
602                                            $blanks++;
603                                         } else {
604                                                 $field_name = is_array($col) && isset($col['name']) ? $col['name'] : $col;
605                                                 if(is_array($col)){
606                                                         if(!empty($col['name'])) {
607                                                            $field_name = $col['name'];
608                                                         }
609                                                 }else{
610                                                         $field_name = $col;
611                                                 }
612                                         }
613                                         
614                                         if(is_string($field_name)) {
615                         // We need to replace all instances of the fake uploadfile and filename field that has custom code with the real filename field
616                         if(!empty($col['customCode']))
617                         {
618                             if($field_name == 'uploadfile')
619                             {
620                                 $replaceField = false;
621                                 if ( !empty($col['customCode']) ) {
622                                     $replaceField = true;
623                                     unset($col['customCode']);
624                                 }
625
626                                 if( !empty($col['displayParams']) && !empty($col['displayParams']['link']) ) {
627                                     $replaceField = true;
628                                 }
629
630                                 if ( $replaceField ) {
631                                     $field_name = 'filename';
632                                     $col['name'] = 'filename';
633                                 }
634                             } else if ($field_name == 'filename') {
635                                 $col = 'filename';
636                             }
637                         }
638
639                                                 $fields[$field_name] = array('data'=>$col, 'loc'=>array('panel'=>"{$panel_id}", 'row'=>"{$row_id}", 'col'=>"{$col_id}"));
640                                         }
641                                 }
642                         }               
643                 }
644                 
645                 //echo "---------------------------------------------------------\n";
646                 //echo var_export($fields, true);
647                 
648                 return $fields;
649         }
650                 
651                 
652         /**
653          * getPanelIds
654          * 
655          */
656         protected function getPanelIds($panels){
657
658                 $panel_ids = array();
659         $setDefaultPanel = false;
660         
661                 if(count($panels) == 1) {
662                    $arrayKeys = array_keys($panels);
663                    if(!empty($arrayKeys[0])) {
664                           $this->defaulPanel = $arrayKeys[0];
665                       $panels = $panels[$arrayKeys[0]];
666                    } else {
667                           $panels = $panels[''];
668                    }
669                    $setDefaultPanel = true;   
670                 }               
671                 
672                 if($this->scanForMultiPanel){
673                         require_once('include/SugarFields/Parsers/MetaParser.php');                     
674                         if($setDefaultPanel || !MetaParser::hasMultiplePanels($panels)) {
675                            $panels = array($this->defaultPanel=>$panels);
676                            $this->isMultiPanel = false;
677                         }
678                 }
679
680                 foreach($panels as $panel_id=>$panel){  
681                     $panel_ids[$panel_id] = $panel_id;
682                 }
683                                 
684                 return $panel_ids;
685         }       
686         
687         /**
688          * Loads the meta data of the original, new, and custom file into the variables originalData, newData, and customData respectively
689          *
690          * @param STRING $module - name of the module's files that are to be merged
691          * @param STRING $original_file - path to the file that originally shipped with sugar
692          * @param STRING $new_file - path to the new file that is shipping with the patch 
693          * @param STRING $custom_file - path to the custom file
694          */
695         protected function loadData($module, $original_file, $new_file, $custom_file){
696                 $this->module = $module;
697                 $varnmame = $this->varName;
698                 require($original_file);
699                 $this->originalData = $$varnmame;
700                 require($new_file);
701                 $this->newData = $$varnmame;
702                 if(file_exists($custom_file)){
703                         require($custom_file);
704                         $this->customData = $$varnmame;
705                 }else{
706                         $this->customData = $this->originalData;
707                 }       
708         }
709         
710         /**
711          * This will save the merged data to a file
712          *
713          * @param STRING $to - path of the file to save it to 
714          * @return BOOLEAN - success or failure of the save
715          */
716         public function save($to){
717                 return write_array_to_file("viewdefs['$this->module']['$this->viewDefs']", $this->newData[$this->module][$this->viewDefs], $to);
718         }
719         
720         /**
721          * This will return the meta data of the merged file
722          *
723          * @return ARRAY - the meta data of the merged file
724          */
725         public function getData(){
726                 return $this->newData;
727         }
728         
729         /**
730          * public function that will merge meta data from an original sugar file that shipped with the product, a customized file, and a new file shipped with an upgrade
731          *
732          * @param STRING $module - name of the module's files that are to be merged
733          * @param STRING $original_file - path to the file that originally shipped with sugar
734          * @param STRING $new_file - path to the new file that is shipping with the patch 
735          * @param STRING $custom_file - path to the custom file
736          * @param BOOLEAN $save - boolean on if it should save the results to the custom file or not
737          * @return BOOLEAN - if the merged file was saved if false is passed in for the save parameter it always returns true
738          */
739         public function merge($module, $original_file, $new_file, $custom_file=false, $save=true){
740                 $this->clear();
741                 $this->log("\n\n". 'Starting a merge in ' . get_class($this));
742                 $this->log('merging the following files');
743                 $this->log('original file:'  . $original_file);
744                 $this->log('new file:'  . $new_file);
745                 $this->log('custom file:'  . $custom_file);
746                 if(empty($custom_file) && $save){
747                         return true;
748                 }else{
749                         $this->loadData($module, $original_file, $new_file, $custom_file);
750                         $this->mergeMetaData();
751                         if($save && !empty($this->newData) && !empty($custom_file)){
752                                 //backup the file
753                                 copy($custom_file, $custom_file . '.suback.php');
754                                 return $this->save($custom_file);
755                         }
756                 }
757                 if(!$save)return true;
758                 return false;
759         }
760         /**
761          * Logs the given message if the message is not a string it will export it first. If $this->fp is NULL then it will try to log to the $GLOBALS['log'] if it is available
762          *
763          * @param MULTI $message
764          */
765         protected  function log($message){
766                 if(!is_string($message)){
767                         $message = var_export($message, true);
768                 }
769                 if(!empty($this->fp)){
770                         fwrite($this->fp, $message. "\n");
771                 }else{
772                         if(!empty($GLOBALS['log'])){
773                                 $GLOBALS['log']->debug($message . "\n");
774                         }
775                 }
776                 
777         }
778 }
779
780 ?>