fixed server-side valdation of autorepeated rows/columns

had to change signature of validate function to get information for autorepeating through
removed entity-encoding of square brackets, as they mess up validiation (havnt found any negative effects so far)
This commit is contained in:
Ralf Becker 2012-05-03 14:17:47 +00:00
parent a4b71c7d3a
commit 0d66dd98b7
17 changed files with 312 additions and 133 deletions

View File

@ -215,7 +215,10 @@ class etemplate_new extends etemplate_widget_template
throw new egw_exception_wrong_parameter('Can NOT read template '.array2string(self::$request->template));
}
$validated = array();
$template->run('validate', array('', $content, &$validated), true); // $respect_disabled=true: do NOT validate disabled widgets and children
$expand = array(
'cont' => &self::$request->content,
);
$template->run('validate', array('', $expand, $content, &$validated), true); // $respect_disabled=true: do NOT validate disabled widgets and children
if (self::validation_errors(self::$request->ignore_validation))
{
@ -251,7 +254,10 @@ class etemplate_new extends etemplate_widget_template
translation::add_app($GLOBALS['egw_info']['flags']['currentapp']);
$validated = array();
$template->run('validate', array('', $content, &$validated), true); // $respect_disabled=true: do NOT validate disabled widgets and children
$expand = array(
'cont' => &self::$request->content,
);
$template->run('validate', array('', $expand, $content, &$validated), true); // $respect_disabled=true: do NOT validate disabled widgets and children
if (self::validation_errors(self::$request->ignore_validation))
{
error_log(__METHOD__."(,".array2string($content).') validation_errors='.array2string(self::$validation_errors));

View File

@ -155,7 +155,11 @@ class etemplate_widget
{
if ($reader->name != 'id' && $template->attr[$reader->name] != $reader->value)
{
if (!$cloned) $template = clone($this);
if (!$cloned)
{
$template = clone($this);
$cloned = true; // only clone it once, otherwise we loose attributes!
}
$template->attrs[$reader->name] = $reader->value;
// split legacy options
@ -326,16 +330,23 @@ class etemplate_widget
* Default implementation only calls method on itself and run on all children
*
* @param string $method_name
* @param array $params=array('') parameter(s) first parameter has to be the cname!
* @param array $params=array('') parameter(s) first parameter has to be the cname, second $expand!
* @param boolean $respect_disabled=false false (default): ignore disabled, true: method is NOT run for disabled widgets AND their children
*/
public function run($method_name, $params=array(''), $respect_disabled=false)
{
// maintain $expand array name-expansion
$cname = $params[0];
$expand =& $params[1];
if ($expand['cname'] !== $cname)
{
$expand['cont'] =& self::get_array(self::$request->content, $cname);
$expand['cname'] = $cname;
}
if ($respect_disabled && ($disabled = $this->attrs['disabled']))
{
// check if disabled contains @ or !
$cname = $params[0];
$disabled = self::check_disabled($disabled, $cname ? self::get_array(self::$request->content, $cname) : self::$request->content);
$disabled = self::check_disabled($disabled, $expand);
if ($disabled)
{
error_log(__METHOD__."('$method_name', ".array2string($params).', '.array2string($respect_disabled).") $this disabled='{$this->attrs['disabled']}'='$disabled': NOT running");
@ -360,12 +371,10 @@ class etemplate_widget
* if no =check is given all set non-empty and non-zero strings are true (standard php behavior)
*
* @param string $disabled expression to check, eg. "!@var" for !$content['var']
* @param array $content the content-array in the context of the grid
* @param int $row=null to be able to use $row or $row_content in value of checks
* @param int $c=null to be able to use $row or $row_content in value of checks
* @param array $expand values for keys 'c', 'row', 'c_', 'row_', 'cont'
* @return boolean true if the row/col is disabled or false if not
*/
protected static function check_disabled($disabled,$content,$row=null,$c=null)
protected static function check_disabled($disabled, array $expland)
{
if ($not = $disabled[0] == '!')
{
@ -374,8 +383,8 @@ class etemplate_widget
list($val,$check_val) = $vals = explode('=',$disabled);
// use expand_name to be able to use @ or $
$val = self::expand_name($val,$c,$row,'','',$content);
$check_val = self::expand_name($check_val,$c,$row,'','',$content);
$val = self::expand_name($val,$expand['c'], $expand['row'], $expand['c_'], $expand['row_'], $expand['cont']);
$check_val = self::expand_name($check_val,$expand['c'], $expand['row'], $expand['c_'], $expand['row_'], $expand['cont']);
$result = count($vals) == 1 ? $val != '' : ($check_val[0] == '/' ? preg_match($check_val,$val) : $val == $check_val);
if ($not) $result = !$result;
@ -428,11 +437,13 @@ class etemplate_widget
$cont = array();
}
if (!is_numeric($c)) $c = boetemplate::chrs2num($c);
$col = boetemplate::num2chrs($c-1); // $c-1 to get: 0:'@', 1:'A', ...
$col_ = boetemplate::num2chrs($c_-1);
$col = self::num2chrs($c-1); // $c-1 to get: 0:'@', 1:'A', ...
$col_ = self::num2chrs($c_-1);
$row_cont = $cont[$row];
$col_row_cont = $cont[$col.$row];
/* RB: dont think any of this is needed in eTemplate2, as this escaping probably needs to be done on clientside anyway
// check if name is enclosed in single quotes as argument eg. to an event handler or
// variable name is contained in quotes and curly brackets, eg. "'{$cont[nm][path]}'" or
// used as name for a button like "delete[$row_cont[something]]" --> quote contained quotes (' or ")
@ -471,7 +482,7 @@ class etemplate_widget
$value = str_replace('&',urlencode('&'),$value);
$name = str_replace($matches[3],$value,$name);
}
}
}*/
eval('$name = "'.str_replace('"','\\"',$name).'";');
}
if ($is_index_in_content)
@ -485,10 +496,30 @@ class etemplate_widget
$name = self::get_array($cont,substr($name,1));
}
}
$name = str_replace(array('[',']'),array('[',']'),$name);
// RB: not sure why this business with entity encoding for square brakets, it messes up validation
//$name = str_replace(array('[',']'),array('[',']'),$name);
return $name;
}
/**
* generates column-names from index: 'A', 'B', ..., 'AA', 'AB', ..., 'ZZ' (not more!)
*
* @param int $num numerical index to generate name from 1 => 'A'
* @return string the name
*/
static function num2chrs($num)
{
$min = ord('A');
$max = ord('Z') - $min + 1;
if ($num >= $max)
{
$chrs = chr(($num / $max) + $min - 1);
}
$chrs .= chr(($num % $max) + $min);
return $chrs;
}
/**
* Convert object to string
*
@ -543,10 +574,15 @@ class etemplate_widget
*
* @param string $cname basename
* @param string $name name
* @param array $expand=null values for keys 'c', 'row', 'c_', 'row_', 'cont'
* @return string complete form-name
*/
static function form_name($cname,$name)
static function form_name($cname,$name,array $expand=null)
{
if ($expand && !empty($name))
{
$name = self::expand_name($name, $expand['c'], $expand['row'], $expand['c_'], $expand['row_'], $expand['cont']);
}
if (count($name_parts = explode('[', $name, 2)) > 1)
{
$name_parts = array_merge(array($name_parts[0]), explode('][', substr($name_parts[1],0,-1)));
@ -558,7 +594,9 @@ class etemplate_widget
$form_name = array_shift($name_parts);
if (count($name_parts))
{
$form_name .= '['.implode('][',$name_parts).']';
// RB: not sure why this business with entity encoding for square brakets, it messes up validation
//$form_name .= '['.implode('][',$name_parts).']';
$form_name .= '['.implode('][',$name_parts).']';
}
return $form_name;
}
@ -615,12 +653,19 @@ class etemplate_widget
* - $readonlys[__ALL__] set and $readonlys[$form_name] !== false
* - $readonlys[$form_name] evaluates to true
*
* @param string $cname=''
* @param string $form_name=null form_name, to not calculate him again
* @return boolean
*/
public function is_readonly($cname='')
public function is_readonly($cname='', $form_name=null)
{
$form_name = self::form_name($cname, $this->id);
if (!isset($form_name))
{
$expand = array(
'cont' => self::get_array(self::$request->content, $cname),
);
$form_name = self::form_name($cname, $this->id, $expand);
}
$readonly = $this->attrs['readonly'] || self::$request->readonlys[$form_name] ||
isset(self::$request->readonlys['__ALL__']) && self::$request->readonlys[$form_name] !== false;
@ -767,7 +812,7 @@ class etemplate_widget_box extends etemplate_widget
{
$cname =& $params[0];
$old_cname = $params[0];
if ($this->id) $cname = self::form_name($cname, $this->id);
if ($this->id) $cname = self::form_name($cname, $this->id, $params[1]);
parent::run($method_name, $params, $respect_disabled);
$params[0] = $old_cname;

View File

@ -17,20 +17,23 @@
class etemplate_widget_button extends etemplate_widget
{
/**
* Validate input
* Validate buttons
*
* Readonly buttons can NOT be pressed
* Readonly buttons can NOT be pressed!
*
* @param string $cname current namespace
* @param array $expand values for keys 'c', 'row', 'c_', 'row_', 'cont'
* @param array $content
* @param array &$validated=array() validated content
* @return boolean true if no validation error, false otherwise
*/
public function validate($cname, array $content, &$validated=array())
public function validate($cname, array $expand, array $content, &$validated=array())
{
$form_name = self::form_name($cname, $this->id);
$form_name = self::form_name($cname, $this->id, $expand);
//error_log(__METHOD__."('$cname', ".array2string($expand).", ...) $this: get_array(\$content, '$form_name')=".array2string(self::get_array($content, $form_name)));
if (self::get_array($content, $form_name) && !$this->is_readonly($cname))
// need to check === true, as get_array() ignores a "[]" postfix and returns array() eg. for a not existing $row_cont[id] in "delete[$row_cont[id]]"
if (!$this->is_readonly($cname, $form_name) && self::get_array($content, $form_name) === true)
{
$valid =& self::get_array($validated, $form_name, true);
$valid = 'pressed'; // that's what it was in old etemplate

View File

@ -35,20 +35,21 @@ class etemplate_widget_checkbox extends etemplate_widget
* Same is true for the radio buttons of a radio-group sharing the same name.
*
* @param string $cname current namespace
* @param array $expand values for keys 'c', 'row', 'c_', 'row_', 'cont'
* @param array $content
* @param array &$validated=array() validated content
* @return boolean true if no validation error, false otherwise
*/
public function validate($cname, array $content, &$validated=array())
public function validate($cname, array $expand, array $content, &$validated=array())
{
$form_name = self::form_name($cname, $this->id);
$form_name = self::form_name($cname, $this->id, $expand);
if (($multiple = substr($form_name, -2) == '[]') && $this->type == 'checkbox')
{
$form_name = substr($form_name, 0, -2);
}
if (!$this->is_readonly($cname))
if (!$this->is_readonly($cname, $form_name))
{
$value = self::get_array($content, $form_name);
$valid =& self::get_array($validated, $form_name, true);

View File

@ -50,7 +50,7 @@ class etemplate_widget_customfields extends etemplate_widget_transformer
* @var $prefix string Prefix for every custiomfield name returned in $content (# for general (admin) customfields)
*/
protected static $prefix = '#';
// Make settings available globally
const GLOBAL_VALS = '~custom_fields~';
@ -210,24 +210,26 @@ class etemplate_widget_customfields extends etemplate_widget_transformer
* - int and float get casted to their type
*
* @param string $cname current namespace
* @param array $expand values for keys 'c', 'row', 'c_', 'row_', 'cont'
* @param array $content
* @param array &$validated=array() validated content
*/
public function validate($cname, array $content, &$validated=array())
public function validate($cname, array $expand, array $content, &$validated=array())
{
if (!$this->is_readonly($cname))
if ($this->id)
{
if($this->id)
{
$form_name = self::form_name($cname, $this->id);
}
else
{
$form_name = self::GLOBAL_ID;
}
$form_name = self::form_name($cname, $this->id, $expand);
}
else
{
$form_name = self::GLOBAL_ID;
}
if (!$this->is_readonly($cname, $form_name))
{
$value_in = self::get_array($content, $form_name);
if(is_array($value_in)) {
if(is_array($value_in))
{
foreach($value_in as $field => $value)
{
if ((string)$value === '' && $this->attrs['needed'])
@ -235,7 +237,7 @@ class etemplate_widget_customfields extends etemplate_widget_transformer
self::set_validation_error($form_name,lang('Field must not be empty !!!'),'');
}
$valid =& self::get_array($validated, $this->id ? $form_name : $field, true);
$valid = is_array($value) ? implode(',',$value) : $value;
error_log(__METHOD__."() $form_name $field: ".array2string($value).' --> '.array2string($value));
}

View File

@ -47,16 +47,17 @@ class etemplate_widget_date extends etemplate_widget_transformer
* Validate input
*
* @param string $cname current namespace
* @param array $expand values for keys 'c', 'row', 'c_', 'row_', 'cont'
* @param array $content
* @param array &$validated=array() validated content
* @return boolean true if no validation error, false otherwise
*/
public function validate($cname, array $content, &$validated=array())
public function validate($cname, array $expand, array $content, &$validated=array())
{
if (!$this->is_readonly($cname) && $this->type != 'date-since') // date-since is always readonly
{
$form_name = self::form_name($cname, $this->id);
$form_name = self::form_name($cname, $this->id, $expand);
if (!$this->is_readonly($cname, $form_name) && $this->type != 'date-since') // date-since is always readonly
{
$value = self::get_array($content, $form_name);
$valid =& self::get_array($validated, $form_name, true);

View File

@ -17,8 +17,13 @@
*/
class etemplate_widget_file extends etemplate_widget
{
public function __construct($xml='') {
/**
* Constructor
*
* @param string $xml
*/
public function __construct($xml='')
{
if($xml) parent::__construct($xml);
// Legacy multiple - id ends in []
@ -29,15 +34,15 @@ class etemplate_widget_file extends etemplate_widget
}
/**
* Ajax callback to receive an incoming file
*
* The incoming file is moved from its temporary location (otherwise server will delete it) and
* the file information is stored into the widget's value. When the form is submitted, the information for all
* files uploaded is available in the returned $content array. Because files are uploaded asynchronously,
* submission should be quick.
*
* @note Currently, no attempt is made to clean up files automatically.
*/
* Ajax callback to receive an incoming file
*
* The incoming file is moved from its temporary location (otherwise server will delete it) and
* the file information is stored into the widget's value. When the form is submitted, the information for all
* files uploaded is available in the returned $content array. Because files are uploaded asynchronously,
* submission should be quick.
*
* @note Currently, no attempt is made to clean up files automatically.
*/
public static function ajax_upload() {
$response = egw_json_response::get();
$request_id = str_replace(' ', '+', rawurldecode($_REQUEST['request_id']));
@ -48,11 +53,11 @@ class etemplate_widget_file extends etemplate_widget
}
if (!($template = etemplate_widget_template::instance(self::$request->template['name'], self::$request->template['template_set'],
self::$request->template['version'], self::$request->template['load_via'])))
{
self::$request->template['version'], self::$request->template['load_via'])))
{
// Can't use callback
error_log("Could not get template for file upload, callback skipped");
}
}
$file_data = array();
@ -146,42 +151,47 @@ class etemplate_widget_file extends etemplate_widget
* Merge any already uploaded files into the content array
*
* @param string $cname current namespace
* @param array $expand values for keys 'c', 'row', 'c_', 'row_', 'cont'
* @param array $content
* @param array &$validated=array() validated content
*/
public function validate($cname, array $content, &$validated=array())
public function validate($cname, array $expand, array $content, &$validated=array())
{
$form_name = self::form_name($cname, $this->id);
$value = $value_in = self::get_array($content, $form_name);
$valid =& self::get_array($validated, $form_name, true);
$form_name = self::form_name($cname, $this->id, $expand);
if(!is_array($value)) $value = array();
// Incoming values indexed by temp name
if($value[0]) $value = $value[0];
foreach($value as $tmp => $file)
if (!$this->is_readonly($cname, $form_name))
{
if (is_dir($GLOBALS['egw_info']['server']['temp_dir']) && is_writable($GLOBALS['egw_info']['server']['temp_dir']))
{
$path = $GLOBALS['egw_info']['server']['temp_dir'].'/'.$tmp;
}
else
{
$path = $tmp.'+';
}
$stat = stat($path);
$valid[] = array(
'name' => $file['name'],
'type' => $file['type'],
'tmp_name' => $path,
'error' => UPLOAD_ERR_OK, // Always OK if we get this far
'size' => $stat['size'],
'ip' => $_SERVER['REMOTE_ADDR'], // Assume it's the same as for when it was uploaded...
);
}
$value = $value_in = self::get_array($content, $form_name);
$valid =& self::get_array($validated, $form_name, true);
if($valid && !$this->attrs['multiple']) $valid = $valid[0];
if(!is_array($value)) $value = array();
// Incoming values indexed by temp name
if($value[0]) $value = $value[0];
foreach($value as $tmp => $file)
{
if (is_dir($GLOBALS['egw_info']['server']['temp_dir']) && is_writable($GLOBALS['egw_info']['server']['temp_dir']))
{
$path = $GLOBALS['egw_info']['server']['temp_dir'].'/'.$tmp;
}
else
{
$path = $tmp.'+';
}
$stat = stat($path);
$valid[] = array(
'name' => $file['name'],
'type' => $file['type'],
'tmp_name' => $path,
'error' => UPLOAD_ERR_OK, // Always OK if we get this far
'size' => $stat['size'],
'ip' => $_SERVER['REMOTE_ADDR'], // Assume it's the same as for when it was uploaded...
);
}
if($valid && !$this->attrs['multiple']) $valid = $valid[0];
}
}
}
etemplate_widget::registerWidget('etemplate_widget_file', array('file'));

View File

@ -13,6 +13,28 @@
/**
* eTemplate grid widget incl. row(s) and column(s)
*
* Example of a grid containing 3 columns and 2 rows (last one autorepeated)
*
* <grid>
* <columns>
* <column>
* <column width="75%">
* <column disabled="@no_actions">
* </columns>
* <rows>
* <row>
* <description value="ID" />
* <description value="Text" />
* <description value="Action" />
* <row>
* <row>
* <description id="${row}[id]" />
* <textbox id="${row}[text]" />
* <button id="delete[$row_cont[id]]" value="Delete" />
* </row>
* </rows>
* </grid>
*/
class etemplate_widget_grid extends etemplate_widget_box
{
@ -29,29 +51,39 @@ class etemplate_widget_grid extends etemplate_widget_box
* Run a given method on all children
*
* Reimplemented to implement column based disabling:
* - added 4th var-parameter to hold key of disabled column
* - added 5th var-parameter to hold key of disabled column
* - if a column is disabled run returns false and key get added by columns run to $columns_disabled
* - row run method checks now for each child (arbitrary widget) if it the column's key is included in $columns_disabled
* - as a grid can contain other grid's as direct child, we have to backup and initialise $columns_disabled in grid run!
*
* @param string $method_name
* @param array $params=array('') parameter(s) first parameter has to be the cname!
* @param array $params=array('') parameter(s) first parameter has to be the cname, second $expand!
* @param boolean $respect_disabled=false false (default): ignore disabled, true: method is NOT run for disabled widgets AND their children
* @param array $columns_disabled=array() disabled columns
*/
public function run($method_name, $params=array(''), $respect_disabled=false, &$columns_disabled=array())
{
// maintain $expand array name-expansion
$cname =& $params[0];
$expand =& $params[1];
$old_cname = $params[0];
if ($this->id) $cname = self::form_name($cname, $this->id, $expand);
if ($expand['cname'] !== $cname)
{
$expand['cont'] =& self::get_array(self::$request->content, $cname);
$expand['cname'] = $cname;
}
// as a grid can contain other grid's as direct child, we have to backup and initialise $columns_disabled
if ($this->type == 'grid')
{
$backup_columns_disabled = $columns_disabled;
$columns_disabled = array();
}
if ($respect_disabled && ($disabled = $this->attrs['disabled']))
{
// check if disabled contains @ or !
$cname = $params[0];
$disabled = self::check_disabled($disabled, $cname ? self::get_array(self::$request->content, $cname) : self::$request->content);
$disabled = self::check_disabled($disabled, $expand);
if ($disabled)
{
error_log(__METHOD__."('$method_name', ".array2string($params).', '.array2string($respect_disabled).") $this disabled='{$this->attrs['disabled']}'='$disabled': NOT running");
@ -62,8 +94,32 @@ class etemplate_widget_grid extends etemplate_widget_box
{
call_user_func_array(array($this, $method_name), $params);
}
foreach($this->children as $n => $child)
//foreach($this->children as $n => $child)
for($n = 0; ; ++$n)
{
// maintain $expand array name-expansion
switch($this->type)
{
case 'rows':
$expand['row'] = $n;
break;
case 'columns':
$expand['c'] = $n;
break;
}
if (isset($this->children[$n]))
{
$child = $this->children[$n];
}
// check if we need to autorepeat last row ($child)
elseif (isset($child) && ($this->type == 'rows' || $this->type == 'columns') && $child->need_autorepeat($cname, $expand))
{
// not breaking repeats last row/column ($child)
}
else
{
break;
}
if ($this->type == 'row')
{
if (in_array($n, $columns_disabled))
@ -83,7 +139,53 @@ class etemplate_widget_grid extends etemplate_widget_box
{
$columns_disabled = $backup_columns_disabled;
}
$params[0] = $old_cname;
return true;
}
/**
* Check if a row or column needs autorepeating, because still content left
*
* We only check direct children and grandchildren of first child (eg. box in first column)!
*
* @param string $cname
* @param array $expand
*/
private function need_autorepeat($cname, array $expand)
{
// check id's of children
foreach($this->children as $n => $direct_child)
{
foreach(array_merge(array($direct_child), $n ? array() : $direct_child->children) as $child)
{
$pat = $child->id;
while(($pat = strstr($pat, '$')))
{
$pat = substr($pat,$pat[1] == '{' ? 2 : 1);
switch ($this->type)
{
case 'column':
$Ok = $pat[0] == 'c' && !(substr($pat,0,4) == 'cont' || substr($pat,0,2) == 'c_' ||
substr($pat,0,4) == 'col_');
break;
case 'row':
$Ok = $pat[0] == 'r' && !(substr($pat,0,2) == 'r_' || substr($pat,0,4) == 'row_');
break;
default:
return false;
}
if ($Ok && ($value = self::get_array(self::$request->content,
$fname=self::form_name($cname, $child->id, $expand))) !== false && isset($value))
{
//error_log(__METHOD__."('$method_name', ) $this autorepeating row $expand[row] because of $child->id = '$fname' is ".array2string($value));
return true;
}
}
}
}
return false;
}
}
etemplate_widget::registerWidget('etemplate_widget_grid', array('grid', 'rows', 'row', 'columns', 'column'));

View File

@ -22,15 +22,16 @@ class etemplate_widget_htmlarea extends etemplate_widget
* Input is run throught HTMLpurifier, to make sure users can NOT enter javascript or other nasty stuff (XSS!).
*
* @param string $cname current namespace
* @param array $expand values for keys 'c', 'row', 'c_', 'row_', 'cont'
* @param array $content
* @param array &$validated=array() validated content
* @return boolean true if no validation error, false otherwise
*/
public function validate($cname, array $content, &$validated=array())
public function validate($cname, array $expand, array $content, &$validated=array())
{
$form_name = self::form_name($cname, $this->id);
$form_name = self::form_name($cname, $this->id, $expand);
if (!$this->is_readonly($cname))
if (!$this->is_readonly($cname, $form_name))
{
$value = self::get_array($content, $form_name);
$valid =& self::get_array($validated, $form_name, true);

View File

@ -179,7 +179,7 @@ class etemplate_widget_link extends etemplate_widget
$link['help'] = lang('Remove this link (not the entry itself)');
}
}
$response = egw_json_response::get();
// Strip keys, unneeded and cause index problems on the client side
$response->data(array_values($links));
@ -201,15 +201,16 @@ class etemplate_widget_link extends etemplate_widget
* - int and float get casted to their type
*
* @param string $cname current namespace
* @param array $expand values for keys 'c', 'row', 'c_', 'row_', 'cont'
* @param array $content
* @param array &$validated=array() validated content
*/
public function validate($cname, array $content, &$validated=array())
public function validate($cname, array $expand, array $content, &$validated=array())
{
if (!$this->is_readonly($cname))
{
$form_name = self::form_name($cname, $this->id);
$form_name = self::form_name($cname, $this->id, $expand);
if (!$this->is_readonly($cname, $form_name))
{
$value = $value_in =& self::get_array($content, $form_name);
// Look for files

View File

@ -65,15 +65,16 @@ class etemplate_widget_menupopup extends etemplate_widget
* Validate input
*
* @param string $cname current namespace
* @param array $expand values for keys 'c', 'row', 'c_', 'row_', 'cont'
* @param array $content
* @param array &$validated=array() validated content
*/
public function validate($cname, array $content, &$validated=array())
public function validate($cname, array $expand, array $content, &$validated=array())
{
$form_name = self::form_name($cname, $this->id);
$form_name = self::form_name($cname, $this->id, $expand);
$ok = true;
if (!$this->is_readonly($cname))
if (!$this->is_readonly($cname, $form_name))
{
$value = $value_in = self::get_array($content, $form_name);
@ -131,7 +132,7 @@ class etemplate_widget_menupopup extends etemplate_widget
self::setElementAttribute($form_name, 'no_lang', $no_lang);
}
}
// Make sure &nbsp;s, etc. are properly encoded when sent, and not double-encoded
foreach(self::$request->sel_options[$form_name] as &$label)
{

View File

@ -677,12 +677,13 @@ class etemplate_widget_nextmatch extends etemplate_widget
* - int and float get casted to their type
*
* @param string $cname current namespace
* @param array $expand values for keys 'c', 'row', 'c_', 'row_', 'cont'
* @param array $content
* @param array &$validated=array() validated content
*/
public function validate($cname, array $content, &$validated=array())
public function validate($cname, array $expand, array $content, &$validated=array())
{
$form_name = self::form_name($cname, $this->id);
$form_name = self::form_name($cname, $this->id, $expand);
$value = self::get_array($content, $form_name);
// On client, rows does not get its own namespace, but all apps are expecting it
@ -720,7 +721,7 @@ class etemplate_widget_nextmatch extends etemplate_widget
* Reimplemented to add namespace, and make sure row template gets included
*
* @param string $method_name
* @param array $params=array('') parameter(s) first parameter has to be cname!
* @param array $params=array('') parameter(s) first parameter has to be cname, second $expand!
* @param boolean $respect_disabled=false false (default): ignore disabled, true: method is NOT run for disabled widgets AND their children
*/
public function run($method_name, $params=array(''), $respect_disabled=false)
@ -728,10 +729,12 @@ class etemplate_widget_nextmatch extends etemplate_widget
$old_param0 = $params[0];
$cname =& $params[0];
// Need this check or the headers will get involved too
if($this->type == 'nextmatch') {
if($this->type == 'nextmatch')
{
if ($this->id) $cname = self::form_name($cname, $this->id, $params[1]);
parent::run($method_name, $params, $respect_disabled);
if ($this->id) $cname = self::form_name($cname, $this->id);
if($this->attrs['template'])
if ($this->attrs['template'])
{
$row_template = etemplate_widget_template::instance($this->attrs['template']);
$row_template->run($method_name, $params, $respect_disabled);

View File

@ -72,10 +72,11 @@ class etemplate_widget_projectmanager extends etemplate_widget_transformer
* @todo
* @param string $cname current namespace
* @param array $content
* @param array $expand values for keys 'c', 'row', 'c_', 'row_', 'cont'
* @param array &$validated=array() validated content
* @return boolean true if no validation error, false otherwise
*/
public function validate($cname, array $content, &$validated=array())
public function validate($cname, array $expand, array $content, &$validated=array())
{
}
}

View File

@ -122,17 +122,14 @@ class etemplate_widget_template extends etemplate_widget
*
* Reimplemented because templates can have an own namespace specified in attrs[content], NOT id!
*
* @param array $content
* @param array &$validated=array() validated content
* @param string $cname='' current namespace
* @param string $method_name
* @param array $params=array('') parameter(s) first parameter has to be cname, second $expand!
* @param boolean $respect_disabled=false false (default): ignore disabled, true: method is NOT run for disabled widgets AND their children
* @todo handle template references containing content in id, eg. id="edit.$cont[something]"
*/
public function run($method_name, $params=array(''), $respect_disabled=false)
{
$cname =& $params[0];
if ($this->attrs['content']) $cname = self::form_name($cname, $this->attrs['content']);
if ($this->attrs['content']) $cname = self::form_name($cname, $this->attrs['content'], $params[1]);
parent::run($method_name, $params, $respect_disabled);
}
}

View File

@ -53,12 +53,16 @@ class etemplate_widget_textbox extends etemplate_widget
* - int and float get casted to their type
*
* @param string $cname current namespace
* @param array $expand values for keys 'c', 'row', 'c_', 'row_', 'cont'
* @param array $content
* @param array &$validated=array() validated content
* @param array $expand=array values for keys 'c', 'row', 'c_', 'row_', 'cont'
*/
public function validate($cname, array $content, &$validated=array())
public function validate($cname, array $expand, array $content, &$validated=array())
{
if (!$this->is_readonly($cname))
$form_name = self::form_name($cname, $this->id, $expand);
if (!$this->is_readonly($cname, $form_name))
{
if (!isset($this->attrs['preg']))
{
@ -75,7 +79,6 @@ class etemplate_widget_textbox extends etemplate_widget
break;
}
}
$form_name = self::form_name($cname, $this->id);
$value = $value_in = self::get_array($content, $form_name);
$valid =& self::get_array($validated, $form_name, true);

View File

@ -46,15 +46,16 @@ class etemplate_widget_tree extends etemplate_widget
* Validate input
*
* @param string $cname current namespace
* @param array $expand values for keys 'c', 'row', 'c_', 'row_', 'cont'
* @param array $content
* @param array &$validated=array() validated content
*/
public function validate($cname, array $content, &$validated=array())
public function validate($cname, array $expand, array $content, &$validated=array())
{
$form_name = self::form_name($cname, $this->id);
$form_name = self::form_name($cname, $this->id, $expand);
$ok = true;
if (!$this->is_readonly($cname))
if (!$this->is_readonly($cname, $form_name))
{
$value = $value_in = self::get_array($content, $form_name);
@ -101,7 +102,7 @@ class etemplate_widget_tree extends etemplate_widget
self::setElementAttribute($form_name, 'no_lang', $no_lang);
}
}
// Make sure &nbsp;s, etc. are properly encoded when sent, and not double-encoded
foreach(self::$request->sel_options[$form_name] as &$label)
{
@ -161,7 +162,7 @@ class etemplate_widget_tree extends etemplate_widget
* @param string $widget_type
* @param string $legacy_options options string of widget
* @param boolean $no_lang=false initial value of no_lang attribute (some types set it to true)
* @param boolean $readonly=false
* @param boolean $readonly=false
* @param mixed $value=null value for readonly
* @return array with value => label pairs
*/

View File

@ -30,13 +30,13 @@ class etemplate_widget_vfs extends etemplate_widget_file
self::store_file($field, $file);
}
}
/**
* Ajax callback to receive an incoming file
*
* The incoming file is automatically placed into the appropriate VFS location.
* If the entry is not yet created, the file information is stored into the widget's value.
* When the form is submitted, the information for all files uploaded is available in the returned
* If the entry is not yet created, the file information is stored into the widget's value.
* When the form is submitted, the information for all files uploaded is available in the returned
* $content array and the application should deal with the file.
*/
public static function store_file($path, $file) {
@ -91,12 +91,13 @@ error_log(lang('Error copying uploaded file to vfs!'));
* Merge any already uploaded files into the content array
*
* @param string $cname current namespace
* @param array $expand values for keys 'c', 'row', 'c_', 'row_', 'cont'
* @param array $content
* @param array &$validated=array() validated content
*/
public function validate($cname, array $content, &$validated=array())
public function validate($cname, array $expand, array $content, &$validated=array())
{
$form_name = self::form_name($cname, $this->id);
$form_name = self::form_name($cname, $this->id, $expand);
$value = $value_in = self::get_array($content, $form_name);
$valid =& self::get_array($validated, $form_name, true);