]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - modules/DynamicFields/templates/Fields/TemplateField.php
Release 6.5.16
[Github/sugarcrm.git] / modules / DynamicFields / templates / Fields / TemplateField.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-2013 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 $GLOBALS['studioReadOnlyFields'] = array('date_entered'=>1, 'date_modified'=>1, 'created_by'=>1, 'id'=>1, 'modified_user_id'=>1);
39 class TemplateField{
40         /*
41                 The view is the context this field will be used in
42                 -edit
43                 -list
44                 -detail
45                 -search
46                 */
47         var $view = 'edit';
48         var $name = '';
49         var $vname = '';
50     public $label = '';
51         var $id = '';
52         var $size = '20';
53         var $len = '255';
54         var $required = false;
55         var $default = null;
56         var $default_value = null;
57         var $type = 'varchar';
58         var $comment = '';
59         var $bean;
60         var $ext1 = '';
61         var $ext2 = '';
62         var $ext3 = '';
63         var $ext4 = '';
64         var $audited= 0;
65         var $massupdate = 0;
66         var $importable = 'true' ;
67         var $duplicate_merge=0;
68         var $new_field_definition;
69         var $reportable = true;
70         var $label_value = '';
71         var $help = '';
72         var $formula = '';
73     var $unified_search = 0;
74     var $supports_unified_search = false;
75         var $vardef_map = array(
76                 'name'=>'name',
77                 'label'=>'vname',
78         // bug 15801 - need to ALWAYS keep default and default_value consistent as some methods/classes use one, some use another...
79                 'default_value'=>'default',
80                 'default'=>'default_value',
81                 'display_default'=>'default_value',
82         //              'default_value'=>'default_value',
83         //              'default'=>'default_value',
84                 'len'=>'len',
85                 'required'=>'required',
86                 'type'=>'type',
87                 'audited'=>'audited',
88                 'massupdate'=>'massupdate',
89                 'options'=>'ext1',
90                 'help'=>'help',
91             'comments'=>'comment',
92             'importable'=>'importable',
93                 'duplicate_merge'=>'duplicate_merge',
94                 'duplicate_merge_dom_value'=>'duplicate_merge_dom_value', //bug #14897
95                 'merge_filter'=>'merge_filter',
96                 'reportable' => 'reportable',
97                 'ext2'=>'ext2',
98                 'ext4'=>'ext4',
99             'ext3'=>'ext3',
100         'labelValue' => 'label_value',
101                 'unified_search'=>'unified_search',
102         'full_text_search'=>'full_text_search',
103         );
104     // Bug #48826
105     // fields to decode from post request
106     var $decode_from_request_fields_map = array('formula', 'dependency');
107         /*
108                 HTML FUNCTIONS
109                 */
110         function get_html(){
111                 $view = $this->view;
112                 if(!empty($GLOBALS['studioReadOnlyFields'][$this->name]))$view = 'detail';
113                 switch($view){
114                         case 'search':return $this->get_html_search();
115                         case 'edit': return $this->get_html_edit();
116                         case 'list': return $this->get_html_list();
117                         case 'detail': return $this->get_html_detail();
118
119                 }
120         }
121         function set($values){
122                 foreach($values as $name=>$value){
123                         $this->$name = $value;
124                 }
125
126         }
127
128         function get_html_edit(){
129                 return 'not implemented';
130         }
131
132         function get_html_list(){
133                 return $this->get_html_detail();
134         }
135
136         function get_html_detail(){
137                 return 'not implemented';
138         }
139
140         function get_html_search(){
141                 return $this->get_html_edit();
142         }
143         function get_html_label(){
144
145                 $label =  "{MOD." .$this->vname . "}";
146                 if(!empty($GLOBALS['app_strings'][$this->vname])){
147                         $label = "{APP." .$this->label . "}";
148                 }
149                 if($this->view == 'edit' && $this->is_required()){
150                         $label .= '<span class="required">*</span>';
151                 }
152                 if($this->view == 'list'){
153                         if(isset($this->bean)){
154                                 if(!empty($this->id)){
155                                         $name = $this->bean->table_name . '_cstm.'. $this->name;
156                                         $arrow = $this->bean->table_name . '_cstm_'. $this->name;
157                                 }else{
158                                         $name = $this->bean->table_name . '.'. $this->name;
159                                         $arrow = $this->bean->table_name . '_'. $this->name;
160                                 }
161                         }else{
162                                 $name = $this->name;
163                                 $arrow = $name;
164                         }
165                         $label = "<a href='{ORDER_BY}$name' class='listViewThLinkS1'>{MOD.$this->label}{arrow_start}{".$arrow."_arrow}{arrow_end}</a>";
166                 }
167                 return $label;
168
169         }
170
171         /*
172                 XTPL FUNCTIONS
173                 */
174
175         function get_xtpl($bean = false){
176                 if($bean)
177                 $this->bean = $bean;
178                 $view = $this->view;
179                 if(!empty($GLOBALS['studioReadOnlyFields'][$this->name]))$view = 'detail';
180                 switch($view){
181                         case 'search':return $this->get_xtpl_search();
182                         case 'edit': return $this->get_xtpl_edit();
183                         case 'list': return $this->get_xtpl_list();
184                         case 'detail': return $this->get_xtpl_detail();
185
186                 }
187         }
188
189         function get_xtpl_edit(){
190                 return '/*not implemented*/';
191         }
192
193         function get_xtpl_list(){
194                 return get_xtpl_detail();
195         }
196
197         function get_xtpl_detail(){
198                 return '/*not implemented*/';
199         }
200
201         function get_xtpl_search(){
202                 //return get_xtpl_edit();
203         }
204
205         function is_required(){
206                 if($this->required){
207                         return true;
208                 }
209                 return false;
210
211         }
212
213
214
215
216         /*
217                 DB FUNCTIONS
218                 */
219
220         function get_db_type(){
221             if(!empty($this->type)) {
222                 $type = $GLOBALS['db']->getColumnType($this->type);
223             }
224             if(!empty($type)) return " $type";
225             $type = $GLOBALS['db']->getColumnType("varchar");
226         return " $type({$this->len})";
227         }
228
229         function get_db_default($modify=false){
230                 $GLOBALS['log']->debug('get_db_default(): default_value='.$this->default_value);
231                 if (!$modify or empty($this->new_field_definition['default_value']) or $this->new_field_definition['default_value'] != $this->default_value ) {
232                         if(!is_null($this->default_value)){ // add a default value if it is not null - we want to set a default even if default_value is '0', which is not null, but which is empty()
233                                 if(NULL == trim($this->default_value)){
234                                         return " DEFAULT NULL";
235                                 }
236                                 else {
237                                         return " DEFAULT '$this->default_value'";
238                                 }
239                         }else{
240                                 return '';
241                         }
242                 }
243         }
244
245         /*
246          * Return the required clause for this field
247          * Confusingly, when modifying an existing field ($modify=true) there are two exactly opposite cases:
248          * 1. if called by Studio, only $this->required is set. If set, we return "NOT NULL" otherwise we return "NULL"
249          * 2. if not called by Studio, $this->required holds the OLD value of required, and new_field_definition['required'] is the NEW
250          * So if not called by Studio we want to return NULL if required=true (because we are changing FROM this setting)
251          */
252
253         function get_db_required($modify=false){
254                 //              $GLOBALS['log']->debug('get_db_required required='.$this->required." and ".(($modify)?"true":"false")." and ".print_r($this->new_field_definition,true));
255                 $req = "";
256
257                 if ($modify) {
258                         if (!empty($this->new_field_definition['required'])) {
259                                 if ($this->required and $this->new_field_definition['required'] != $this->required) {
260                                         $req = " NULL ";
261                                 }
262                         }
263                         else
264                         {
265                                 $req = ($this->required) ? " NOT NULL " : ''; // bug 17184 tyoung - set required correctly when modifying custom field in Studio
266                         }
267                 }
268                 else
269                 {
270                         if (empty($this->new_field_definition['required']) or $this->new_field_definition['required'] != $this->required ) {
271                                 if(!empty($this->required) && $this->required){
272                                         $req = " NOT NULL";
273                                 }
274                         }
275                 }
276
277                 return $req;
278         }
279
280         /*      function get_db_required($modify=false){
281                 $GLOBALS['log']->debug('get_db_required required='.$this->required." and ".(($modify)?"true":"false")." and ".print_r($this->new_field_definition,true));
282                 if ($modify) {
283                 if (!empty($this->new_field_definition['required'])) {
284                 if ($this->required and $this->new_field_definition['required'] != $this->required) {
285                 return " null ";
286                 }
287                 return "";
288                 }
289                 }
290                 if (empty($this->new_field_definition['required']) or $this->new_field_definition['required'] != $this->required ) {
291                 if(!empty($this->required) && $this->required){
292                 return " NOT NULL";
293                 }
294                 }
295                 return '';
296                 }
297                 */
298         /**
299          * Oracle Support: do not set required constraint if no default value is supplied.
300          * In this case the default value will be handled by the application/sugarbean.
301          */
302         function get_db_add_alter_table($table)
303         {
304                 return $GLOBALS['db']->getHelper()->addColumnSQL($table, $this->get_field_def(), true);
305         }
306
307         function get_db_delete_alter_table($table)
308         {
309                 return $GLOBALS['db']->getHelper()->dropColumnSQL(
310                 $table,
311                 $this->get_field_def()
312                 );
313         }
314
315         /**
316          * mysql requires the datatype caluse in the alter statment.it will be no-op anyway.
317          */
318         function get_db_modify_alter_table($table){
319                 return $GLOBALS['db']->alterColumnSQL($table, $this->get_field_def());
320         }
321
322
323         /*
324          * BEAN FUNCTIONS
325          *
326          */
327         function get_field_def(){
328                 $array =  array(
329                         'required'=>$this->convertBooleanValue($this->required),
330                         'source'=>'custom_fields',
331                         'name'=>$this->name,
332                         'vname'=>$this->vname,
333                         'type'=>$this->type,
334                         'massupdate'=>$this->massupdate,
335                         'default'=>$this->default,
336             'no_default'=> !empty($this->no_default),
337                         'comments'=> (isset($this->comments)) ? $this->comments : '',
338                     'help'=> (isset($this->help)) ?  $this->help : '',
339                     'importable'=>$this->importable,
340                         'duplicate_merge'=>$this->duplicate_merge,
341                         'duplicate_merge_dom_value'=> $this->getDupMergeDomValue(),
342                         'audited'=>$this->convertBooleanValue($this->audited),
343                         'reportable'=>$this->convertBooleanValue($this->reportable),
344             'unified_search'=>$this->convertBooleanValue($this->unified_search),
345             'merge_filter' => empty($this->merge_filter) ? "disabled" : $this->merge_filter
346                 );
347         if (isset($this->full_text_search)) {
348             $array['full_text_search'] = $this->full_text_search;
349         }
350                 if(!empty($this->len)){
351                         $array['len'] = $this->len;
352                 }
353                 if(!empty($this->size)){
354                         $array['size'] = $this->size;
355                 }
356
357         $this->get_dup_merge_def($array);
358
359                 return $array;
360         }
361
362         protected function convertBooleanValue($value)
363         {
364                 if ($value === 'true' || $value === '1' || $value === 1)
365                 return  true;
366                 else if ($value === 'false' || $value === '0' || $value === 0)
367                 return  false;
368                 else
369                 return $value;
370         }
371
372
373         /* if the field is duplicate merge enabled this function will return the vardef entry for the same.
374          */
375         function get_dup_merge_def(&$def) {
376         switch ($def['duplicate_merge_dom_value']) {
377                         case 0:
378                                 $def['duplicate_merge']='disabled';
379                 $def['merge_filter']='disabled';
380                                 break;
381                         case 1:
382                                 $def['duplicate_merge']='enabled';
383                 $def['merge_filter']='disabled';
384                                 break;
385                         case 2:
386                                 $def['merge_filter']='enabled';
387                                 $def['duplicate_merge']='enabled';
388                                 break;
389                         case 3:
390                                 $def['merge_filter']='selected';
391                                 $def['duplicate_merge']='enabled';
392                                 break;
393                         case 4:
394                                 $def['merge_filter']='enabled';
395                                 $def['duplicate_merge']='disabled';
396                                 break;
397                 }
398
399         }
400
401     /**
402      * duplicate_merge_dom_value drives the dropdown in the studio editor. This dropdown drives two fields though,
403      * duplicate_merge and merge_filter. When duplicate_merge_dom_value is not set, we need to derive it from the values
404      * of those two fields. Also, when studio sends this value down to be read in PopulateFromPost, it is set to
405      * duplicate_merge rather than duplicate_merge_dom_value, so we must check if duplicate_merge is a number rather
406      * than a string as well.
407      * @return int
408      */
409     function getDupMergeDomValue(){
410         if (isset($this->duplicate_merge_dom_value)) {
411             return $this->duplicate_merge_dom_value;
412         }
413
414         //If duplicate merge is numeric rather than a string, it is probably what duplicate_merge_dom_value was set to.
415         if (is_numeric($this->duplicate_merge))
416             return $this->duplicate_merge;
417
418
419         //Figure out the duplicate_merge_dom_value based on the values of merge filter and duplicate merge
420         if (empty($this->merge_filter) || $this->merge_filter === 'disabled' )
421         {
422             if (empty($this->duplicate_merge) || $this->duplicate_merge === 'disabled') {
423                 $this->duplicate_merge_dom_value = 0;
424             } else {
425                 $this->duplicate_merge_dom_value = 1;
426             }
427         } else {
428             if ($this->merge_filter === "selected")
429                 $this->duplicate_merge_dom_value = 3;
430             else if (empty($this->duplicate_merge) || $this->duplicate_merge === 'disabled') {
431                 $this->duplicate_merge_dom_value = 4;
432             } else {
433                 $this->duplicate_merge_dom_value = 2;
434             }
435         }
436
437         return $this->duplicate_merge_dom_value;
438     }
439
440         /*
441                 HELPER FUNCTIONS
442                 */
443
444
445         function prepare(){
446                 if(empty($this->id)){
447                         $this->id = $this->name;
448                 }
449         }
450
451         /**
452          * populateFromRow
453          * This function supports setting the values of all TemplateField instances.
454          * @param $row The Array key/value pairs from fields_meta_data table
455          */
456         function populateFromRow($row=array()) {
457                 $fmd_to_dyn_map = array('comments' => 'comment', 'require_option' => 'required', 'label' => 'vname',
458                                                             'mass_update' => 'massupdate', 'max_size' => 'len', 'default_value' => 'default', 'id_name' => 'ext3');
459                 if(!is_array($row)) {
460                         $GLOBALS['log']->error("Error: TemplateField->populateFromRow expecting Array");
461                 }
462                 //Bug 24189: Copy fields from FMD format to Field objects and vice versa
463                 foreach ($fmd_to_dyn_map as $fmd_key => $dyn_key) {
464             if (isset($row[$dyn_key])) {
465                 $this->$fmd_key = $row[$dyn_key];
466             }
467             if (isset($row[$fmd_key])) {
468                                 $this->$dyn_key = $row[$fmd_key];
469                         }
470                 }
471                 foreach($row as $key=>$value) {
472                         $this->$key = $value;
473                 }
474         }
475
476         function populateFromPost(){
477                 foreach($this->vardef_map as $vardef=>$field){
478
479                         if(isset($_REQUEST[$vardef])){              
480                 $this->$vardef = $_REQUEST[$vardef];
481
482                 //  Bug #48826. Some fields are allowed to have special characters and must be decoded from the request
483                 // Bug 49774, 49775: Strip html tags from 'formula' and 'dependency'.
484                 if (is_string($this->$vardef) && in_array($vardef, $this->decode_from_request_fields_map))
485                 {
486                     $this->$vardef = html_entity_decode(strip_tags(from_html($this->$vardef)));
487                 }
488
489
490                 //Remove potential xss code from help field
491                 if($field == 'help' && !empty($this->$vardef))
492                 {
493                     $help = htmlspecialchars_decode($this->$vardef, ENT_QUOTES);
494                     $this->$vardef = htmlentities(remove_xss($help));
495                 }
496
497
498                                 if($vardef != $field){
499                                         $this->$field = $this->$vardef;
500                                 }
501                         }
502                 }
503                 $this->applyVardefRules();
504                 $GLOBALS['log']->debug('populate: '.print_r($this,true));
505
506         }
507
508         protected function applyVardefRules()
509         {
510         }
511
512         function get_additional_defs(){
513                 return array();
514         }
515
516         function delete($df){
517                 $df->deleteField($this);
518         }
519
520     /**
521      * get_field_name
522      *
523      * This is a helper function to return a field's proper name.  It checks to see if an instance of the module can
524      * be created and then attempts to retrieve the field's name based on the name lookup skey supplied to the method.
525      *
526      * @param String $module The name of the module
527      * @param String $name The field name key
528      * @return The field name for the module
529      */
530     protected function get_field_name($module, $name)
531     {
532        $bean = loadBean($module);
533        if(empty($bean) || is_null($bean))
534        {
535           return $name;
536        }
537
538        $field_defs = $bean->field_defs;
539        return isset($field_defs[$name]['name']) ? $field_defs[$name]['name'] : $name;
540     }
541
542     /**
543      * save
544      *
545      * This function says the field template by calling the DynamicField addFieldObject function.  It then
546      * checks to see if updates are needed for the SearchFields.php file.  In the event that the unified_search
547      * member variable is set to true, a search field definition is updated/created to the SearchFields.php file.
548      *
549      * @param DynamicField $df
550      */
551         function save($df){
552                 //          $GLOBALS['log']->debug('saving field: '.print_r($this,true));
553                 $df->addFieldObject($this);
554
555         require_once('modules/ModuleBuilder/parsers/parser.searchfields.php');
556         $searchFieldParser = new ParserSearchFields( $df->getModuleName() , $df->getPackageName() ) ;
557             //If unified_search is enabled for this field, then create the SearchFields entry
558             $fieldName = $this->get_field_name($df->getModuleName(), $this->name);
559         if($this->unified_search && !isset($searchFieldParser->searchFields[$df->getModuleName()][$fieldName]))
560         {
561            $searchFieldParser->addSearchField($fieldName, array('query_type'=>'default'));
562            $searchFieldParser->saveSearchFields($searchFieldParser->searchFields);
563         }
564         }
565
566 }
567
568
569 ?>