2011-10-07 01:44:55 +02:00
< ? php
/**
* EGroupware - eTemplate custom fields widget
*
* @ license http :// opensource . org / licenses / gpl - license . php GPL - GNU General Public License
* @ package etemplate
* @ subpackage api
* @ link http :// www . egroupware . org
* @ author Nathan Gray
* @ copyright 2011 Nathan Gray
* @ version $Id $
*/
/**
* Widgets for custom fields and listing custom fields
*
*/
class etemplate_widget_customfields extends etemplate_widget_transformer
{
/**
* Allowd types of customfields
*
* The additionally allowed app - names from the link - class , will be add by the edit - method only ,
* as the link - class has to be called , which can NOT be instanciated by the constructor , as
* we get a loop in the instanciation .
*
* @ var array
*/
protected static $cf_types = array (
'text' => 'Text' ,
'float' => 'Float' ,
'label' => 'Label' ,
'select' => 'Selectbox' ,
'ajax_select' => 'Search' ,
'radio' => 'Radiobutton' ,
'checkbox' => 'Checkbox' ,
'date' => 'Date' ,
'date-time' => 'Date+Time' ,
'select-account' => 'Select account' ,
'button' => 'Button' , // button to execute javascript
'url' => 'Url' ,
'url-email' => 'EMail' ,
'url-phone' => 'Phone number' ,
'htmlarea' => 'Formatted Text (HTML)' ,
'link-entry' => 'Select entry' , // should be last type, as the individual apps get added behind
);
/**
* @ var $prefix string Prefix for every custiomfield name returned in $content ( # for general (admin) customfields)
*/
protected static $prefix = '#' ;
2012-05-03 16:17:47 +02:00
2012-03-23 00:36:31 +01:00
// Make settings available globally
2011-10-14 19:56:29 +02:00
const GLOBAL_VALS = '~custom_fields~' ;
2011-10-07 01:44:55 +02:00
2012-03-23 00:36:31 +01:00
// Used if there's no ID provided
const GLOBAL_ID = 'custom_fields' ;
2011-10-07 01:44:55 +02:00
protected $legacy_options = 'sub-type,use-private,field-names' ;
protected static $transformation = array (
'type' => array (
'customfields-types' => array (
'type' => 'select' ,
'sel_options' => array ()
),
'customfields-list' => array (
'readonly' => true
)
)
);
2012-04-24 21:46:24 +02:00
public function __construct ( $xml )
2011-10-07 01:44:55 +02:00
{
parent :: __construct ( $xml );
}
/**
* Fill type options in self :: $request -> sel_options to be used on the client
*
* @ param string $cname
*/
public function beforeSendToClient ( $cname )
{
2011-10-11 20:15:51 +02:00
// No name, no way to get parameters client-side.
2012-03-23 00:36:31 +01:00
if ( ! $this -> id ) $this -> id = self :: GLOBAL_ID ;
2011-10-11 20:15:51 +02:00
2011-10-07 01:44:55 +02:00
$form_name = self :: form_name ( $cname , $this -> id );
2011-10-14 19:56:29 +02:00
// Store properties at top level, so all customfield widgets can share
$app =& $this -> getElementAttribute ( self :: GLOBAL_VALS , 'app' );
if ( $this -> getElementAttribute ( $form_name , 'app' ))
{
$app =& $this -> getElementAttribute ( $form_name , 'app' );
} else {
// Checking creates it even if it wasn't there
unset ( self :: $request -> modifications [ $form_name ][ 'app' ]);
}
2011-10-07 01:44:55 +02:00
2012-06-06 06:13:19 +02:00
if ( $this -> getElementAttribute ( $form_name , 'customfields' ))
{
$customfields =& $this -> getElementAttribute ( $form_name , 'customfields' );
}
elseif ( $app )
{
// Checking creates it even if it wasn't there
unset ( self :: $request -> modifications [ $form_name ][ 'customfields' ]);
$customfields =& $this -> getElementAttribute ( self :: GLOBAL_VALS , 'customfields' );
}
2011-10-07 01:44:55 +02:00
if ( ! $app )
{
2011-10-14 19:56:29 +02:00
$app =& $this -> setElementAttribute ( self :: GLOBAL_VALS , 'app' , $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ]);
$customfields =& $this -> setElementAttribute ( self :: GLOBAL_VALS , 'customfields' , config :: get_customfields ( $app ));
2011-10-07 01:44:55 +02:00
}
// if we are in the etemplate editor or the app has no cf's, load the cf's from the app the tpl belongs too
if ( $app && $app != 'stylite' && $app != $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ] && (
2012-04-24 21:46:24 +02:00
$GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ] == 'etemplate' || ! $this -> attrs [ 'customfields' ] ||
2011-10-07 01:44:55 +02:00
etemplate :: $hooked
))
{
// app changed
$customfields =& config :: get_customfields ( $app );
}
// Filter fields
2013-11-27 18:17:37 +01:00
if ( $this -> attrs [ 'field-names' ])
{
if ( $this -> attrs [ 'field-names' ][ 0 ] == '!' ) {
$negate_field_filter = true ;
$this -> attrs [ 'field-names' ] = substr ( $this -> attrs [ 'field_names' ], 1 );
}
$field_filter = explode ( ',' , $this -> attrs [ 'field_names' ]);
}
2011-10-07 01:44:55 +02:00
$fields = $customfields ;
2013-08-20 13:57:44 +02:00
2013-11-27 18:17:37 +01:00
$use_private = self :: expand_name ( $this -> attrs [ 'use-private' ], 0 , 0 , '' , '' , self :: $cont );
$this -> attrs [ 'sub-type' ] = self :: expand_name ( $this -> attrs [ 'sub-type' ], 0 , 0 , '' , '' , self :: $cont );
2011-10-07 01:44:55 +02:00
foreach (( array ) $fields as $key => $field )
{
// remove private or non-private cf's, if only one kind should be displayed
2013-11-28 19:32:36 +01:00
if (( string ) $use_private !== '' && ( boolean ) $field [ 'private' ] != ( boolean ) $use_private )
2011-10-07 01:44:55 +02:00
{
unset ( $fields [ $key ]);
}
// Remove filtered fields
if ( $field_filter && ( ! $negate_field_filter && ! in_array ( $key , $field_filter ) ||
$negate_field_filter && in_array ( $key , $field_filter )))
{
unset ( $fields [ $key ]);
}
}
// check if name refers to a single custom field --> show only that
2012-03-12 23:29:51 +01:00
if (( $pos = strpos ( $form_name , self :: $prefix )) !== false && // allow the prefixed name to be an array index too
2011-10-07 01:44:55 +02:00
preg_match ( " / $this->prefix ([^ \ ]]+)/ " , $form_name , $matches ) && isset ( $fields [ $name = $matches [ 1 ]]))
{
$fields = array ( $name => $fields [ $name ]);
$value = array ( $this -> prefix . $name => $value );
$singlefield = true ;
$form_name = substr ( $form_name , 0 , - strlen ( " [ $this->prefix $name ] " ));
}
2012-03-12 23:29:51 +01:00
if ( ! is_array ( $fields )) $fields = array ();
2011-10-07 01:44:55 +02:00
switch ( $type = $this -> type )
{
case 'customfields-types' :
foreach ( self :: $cf_types as $lname => $label )
{
$sel_options [ $lname ] = lang ( $label );
$fields_with_vals [] = $lname ;
}
$link_types = egw_link :: app_list ();
ksort ( $link_types );
foreach ( $link_types as $lname => $label ) $sel_options [ $lname ] = '- ' . $label ;
self :: $transformation [ 'type' ][ $type ][ 'sel_options' ] = $sel_options ;
self :: $transformation [ 'type' ][ $type ][ 'no_lang' ] = true ;
2012-03-20 23:37:52 +01:00
return parent :: beforeSendToClient ( $cname );
2011-10-07 01:44:55 +02:00
case 'customfields-list' :
foreach ( array_reverse ( $fields ) as $lname => $field )
{
if ( ! empty ( $this -> attrs [ 'sub-type' ]) && ! empty ( $field [ 'type2' ]) && strpos ( ',' . $field [ 'type2' ] . ',' , ',' . $type2 . ',' ) === false ) continue ; // not for our content type//
if ( isset ( $value [ $this -> prefix . $lname ]) && $value [ $this -> prefix . $lname ] !== '' ) //break;
{
$fields_with_vals [] = $lname ;
}
//$stop_at_field = $name;
}
break ;
default :
foreach ( array_reverse ( $fields ) as $lname => $field )
{
$fields_with_vals [] = $lname ;
}
}
2011-10-14 19:56:29 +02:00
if ( $fields != $customfields )
{
// This widget has different settings from global
$this -> setElementAttribute ( $form_name , 'customfields' , $fields );
2013-03-20 21:47:54 +01:00
$this -> setElementAttribute ( $form_name , 'fields' , array_merge (
array_fill_keys ( array_keys ( $customfields ), false ),
array_fill_keys ( array_keys ( $fields ), true )
));
2011-10-14 19:56:29 +02:00
}
2011-10-07 01:44:55 +02:00
parent :: beforeSendToClient ( $cname );
2012-03-22 17:34:45 +01:00
// Re-format date custom fields from Y-m-d
2012-06-06 06:13:19 +02:00
$field_settings =& self :: get_array ( self :: $request -> modifications , " { $this -> id } [customfields] " , true );
$field_settings = array ();
2013-06-19 20:11:30 +02:00
$link_types = egw_link :: app_list ();
2012-03-22 17:34:45 +01:00
foreach ( $fields as $fname => $field )
{
2013-06-19 01:26:43 +02:00
if ( $field [ 'type' ] == 'date' && ( $d_val = self :: $request -> content [ self :: $prefix . $fname ]) && ! is_numeric ( $d_val ))
2012-03-22 17:34:45 +01:00
{
2013-06-19 01:26:43 +02:00
self :: $request -> content [ self :: $prefix . $fname ] = strtotime ( $d_val );
2012-03-22 17:34:45 +01:00
}
2012-06-06 06:13:19 +02:00
// Run beforeSendToClient for each field
2013-06-19 20:11:30 +02:00
$type = $field [ 'type' ];
// Link-tos needs to change from appname to link-to
if ( $link_types [ $field [ 'type' ]])
{
$type = 'link-to' ;
}
$widget = self :: factory ( $type , '<' . $type . ' type="' . $type . '" id="' . self :: $prefix . $fname . '"/>' , self :: $prefix . $fname );
2012-06-06 06:13:19 +02:00
if ( method_exists ( $widget , 'beforeSendToClient' ))
{
2013-06-19 01:26:43 +02:00
$widget -> id = self :: $prefix . $fname ;
2013-06-19 20:11:30 +02:00
$widget -> attrs [ 'type' ] = $type ;
if ( $type == 'link-to' )
{
$widget -> attrs [ 'only_app' ] = $field [ 'type' ];
}
2013-11-04 16:41:58 +01:00
$widget -> beforeSendToClient ( $this -> id == self :: GLOBAL_ID ? '' : $this -> id );
2012-06-06 06:13:19 +02:00
}
2012-03-22 17:34:45 +01:00
}
2011-10-07 01:44:55 +02:00
}
2012-03-23 00:36:31 +01:00
/**
* Validate input
*
* Following attributes get checked :
* - needed : value must NOT be empty
* - min , max : int and float widget only
* - maxlength : maximum length of string ( longer strings get truncated to allowed size )
* - preg : perl regular expression incl . delimiters ( set by default for int , float and colorpicker )
* - int and float get casted to their type
*
* @ param string $cname current namespace
2012-05-03 16:17:47 +02:00
* @ param array $expand values for keys 'c' , 'row' , 'c_' , 'row_' , 'cont'
2012-03-23 00:36:31 +01:00
* @ param array $content
* @ param array & $validated = array () validated content
*/
2012-05-03 16:17:47 +02:00
public function validate ( $cname , array $expand , array $content , & $validated = array ())
2012-03-23 00:36:31 +01:00
{
2012-05-03 16:17:47 +02:00
if ( $this -> id )
2012-03-23 00:36:31 +01:00
{
2012-05-03 16:17:47 +02:00
$form_name = self :: form_name ( $cname , $this -> id , $expand );
}
else
{
$form_name = self :: GLOBAL_ID ;
}
2012-03-23 00:36:31 +01:00
2012-05-03 16:17:47 +02:00
if ( ! $this -> is_readonly ( $cname , $form_name ))
{
2012-03-23 00:36:31 +01:00
$value_in = self :: get_array ( $content , $form_name );
2013-06-25 22:49:13 +02:00
$app =& $this -> getElementAttribute ( self :: GLOBAL_VALS , 'app' );
$customfields =& $this -> getElementAttribute ( self :: GLOBAL_VALS , 'customfields' );
2012-05-03 16:17:47 +02:00
if ( is_array ( $value_in ))
{
2012-03-30 00:57:00 +02:00
foreach ( $value_in as $field => $value )
2012-03-23 00:36:31 +01:00
{
2013-06-25 22:49:13 +02:00
$field_settings = $customfields [ substr ( $field , 1 )];
if (( string ) $value === '' && $field_settings [ 'needed' ])
2012-03-30 00:57:00 +02:00
{
self :: set_validation_error ( $form_name , lang ( 'Field must not be empty !!!' ), '' );
}
$valid =& self :: get_array ( $validated , $this -> id ? $form_name : $field , true );
2012-05-03 16:17:47 +02:00
2012-04-24 21:46:24 +02:00
$valid = is_array ( $value ) ? implode ( ',' , $value ) : $value ;
2013-08-20 13:57:44 +02:00
//error_log(__METHOD__."() $form_name $field: ".array2string($value).' --> '.array2string($value));
2012-03-23 00:36:31 +01:00
}
2012-05-24 23:12:26 +02:00
} elseif ( $this -> type == 'customfields-types' ) {
// Transformation doesn't handle validation
$valid =& self :: get_array ( $validated , $this -> id ? $form_name : $field , true );
$valid = $value_in ;
2013-08-20 13:57:44 +02:00
//error_log(__METHOD__."() $form_name $field: ".array2string($value).' --> '.array2string($value));
2012-03-23 00:36:31 +01:00
}
}
}
2011-10-07 01:44:55 +02:00
}