FRED™  3.0
FRED™: Framework for Rapid and Easy Development
Controller.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Rsi\Fred;
4 
5 class Controller extends Component{
6 
7  const TOTAL_COUNT = 'count';
8  const TOTAL_SUM = 'sum';
9  const TOTAL_AVG = 'avg';
10  const TOTAL_MAX = 'max';
11  const TOTAL_MIN = 'min';
12  const TOTAL_UNIQUE = 'unique';
13  const TOTAL_NULL = 'null';
14  const TOTAL_NOT_NULL = 'not_null';
15 
16  public $domainRedir = []; //!< Prefered domain notation (key = domain mask regex, value = prefered domain, incl. protocol).
17  public $domainRedirPermanent = false; //!< True to make a redirection permanent (HTTP status code = 301; defaults to 302).
18  public $defaultWidgetNamespace = __CLASS__ . '\\Widget';
19  public $defaultViewNamespace = __CLASS__ . '\\View';
20  public $defaultViewType = 'html';
21  public $viewClassName = null; //!< Fix the view to a certain View or Controller class (empty = same as called class).
22  public $fragmentId = null;
23 
24  public $display = Controller\Widget::DISPLAY_WRITEABLE; //!< Default display mode for widgets.
25  public $defaultCaption = null; //!< An asterisk will be replaced with widget ID.
26  public $defaultHint = null; //!< An asterisk will be replaced with the widget ID or type.
27  public $helpCaption = 'Help';
28  public $errorStr = '[caption]{[!caption]{[id]}}: [error]';
29 
30  public $inactiveMessage = '[@inactiveMessage]'; //!< Message for inactive user who is redirected to login controller.
31 
32  public $clientErrorPrio = null; //!< Log client errors with this prio (empty = do not log).
33  public $clientErrorBanDelay = 10; //!< Ban delay for the first error in a new session (prevent flooding via multiple
34  // sessions).
35  public $clientErrorMax = 25; //!< Maximum number of client errors to log in one session.
36 
37  protected $_securityChecksIgnore = []; //!< Security checks to ignore (key = action, null = default; value = array with
38  // checks to ignore, true = all).
39  protected $_authSets = []; //!< Possible sets of necessary authentication (array of arrays of authentication checks).
40  protected $_rights = []; //!< Necessary right needed per action (key = action, null = default; value = right, optionally
41  // completed with a minimal level in 'right:level' notation, or only a level relative to the default right in ':level'
42  // notation).
43  protected $_checkWidgets = ['default' => false,'fragment' => false,'pingAlive' => false,'clientError' => false,'featureHint' => false,'requestSocket' => false];
44  //!< Widgets to check per action (key = action; value = array with ID's of widget to check; null = default, otherwise all).
45 
46  protected $_action = null;
47  protected $_widgets = null;
48  protected $_constraints = null;
49  protected $_view = null;
50 
51  protected function init(){
52  parent::init();
53  $this->publish('authSets',self::READWRITE);
54  if($this->action == 'default') $this->domainRedir();
55  }
56 
57  protected function domainRedir(){
58  if($this->domainRedir && !in_array($domain = \Rsi\Http::host(true),$this->domainRedir))
59  foreach($this->domainRedir as $mask => $redir) if(preg_match($mask,$domain)){
60  \Rsi\Http::redirHeader($redir . \Rsi\Record::get($_SERVER,'REQUEST_URI'),$this->domainRedirPermanent);
61  $this->_fred->halt();
62  }
63  }
64 
65  public function clientConfig(){
66  $widgets = $constraints = [];
67  foreach($this->widgets as $id => $widget) $widgets[$id] = array_filter($widget->clientConfig());
68  foreach($this->constraints as $constraint) $constraints[] = array_filter($constraint);
69  return array_merge(parent::clientConfig(),[
70  'route' => $this->route('*'),
71  'widgets' => $widgets,
72  'checkWidgets' => $this->_checkWidgets,
73  'constraints' => $constraints
74  ]);
75  }
76  /**
77  * Add an authentication check to all sets, or create a new one if none exists.
78  * @param string $name Authentication check name.
79  */
80  protected function addAuth($name){
81  if(!$this->_authSets) $this->_authSets[] = [$name];
82  else foreach($this->_authSets as &$set) if(!in_array($name,$set)) $set[] = $name;
83  unset($set);
84  }
85  /**
86  * Remove an authentication check from all sets.
87  * @param string $name Authentication check name.
88  */
89  protected function removeAuth($name){
90  $sets = [];
91  foreach($this->_authSets as $key => $set) $sets[$key] = array_diff($set,[$name]);
92  $this->_authSets = array_filter($sets);
93  }
94  /**
95  * Add a single widget.
96  * @param string $id Widget ID.
97  * @param Rsi\Fred\Controller\Widget $widget
98  */
99  protected function addWidget($id,$widget){
100  $widget->controller = $this;
101  $this->_widgets[$id] = $widget;
102  }
103  /**
104  * Add multiple widgets.
105  * @param array $widgets Key = ID, value = widget.
106  */
107  protected function addWidgets($widgets){
108  foreach($widgets as $id => $widget) $this->addWidget($id,$widget);
109  }
110  /**
111  * Create a widget by type.
112  * @param string $type Widget type (class name).
113  * @param string $config Configuration.
114  * @return Widget
115  */
116  protected function widgetByType($type,$config){
117  $class_name = (substr($type,0,1) == '\\' ? '' : $this->defaultWidgetNamespace . '\\') . ucfirst($type);
118  return new $class_name($config);
119  }
120  /**
121  * Add a widget by type.
122  * @param string $id Widget ID.
123  * @param string $type Widget type (class name).
124  * @param string $config Configuration.
125  */
126  protected function addByType($id,$type,$config){
127  $this->addWidget($id,$this->widgetByType($type,$config));
128  }
129  /**
130  * Create a widget from a database definition.
131  * @param string $table Name of the table.
132  * @param string $column Column name.
133  * @param array $extra Extra configuration to add to the definition.
134  * @return Widget
135  */
136  protected function widgetFromDef($table,$column,$extra = null){
137  $def = $this->component('def')->column($table,$column,$extra);
138  return $this->widgetByType($def['type'],$def);
139  }
140  /**
141  * Add widgets from a database definition.
142  * @param string $table Name of the table.
143  * @param string|array $columns One or more column names (all table columns when empty).
144  * @param array $extra Extra configuration to add to the definition.
145  * @param string $prefix Prefix to add to the column name for the widget ID.
146  */
147  protected function addFromDef($table,$columns = null,$extra = null,$prefix = null){
148  if(!$columns) $columns = array_keys($this->component('def')->table($table));
149  elseif(!is_array($columns)) $columns = [$columns];
150  foreach($columns as $column) $this->addWidget($prefix . $column,$this->widgetFromDef($table,$column,$extra));
151  }
152  /**
153  * Add widgets from a definition record.
154  * @param Rsi\Fred\Def\Record $record Definition record.
155  * @param string $prefix Prefix to add to the column name for the widget ID.
156  */
157  protected function addFromRecord($record,$prefix = null){
158  foreach($record->columns as $column => $config) $this->addByType($prefix . $column,$config['type'],$config);
159  }
160  /**
161  * Copy data from a definition record to the request.
162  * @param Rsi\Fred\Def\Record $record Definition record.
163  * @param string $prefix Prefix to add to the column name for the widget ID.
164  */
165  protected function dataFromRecord($record,$prefix = null){
166  $request = $this->component('request');
167  foreach($record->columns as $column => $config) $request->data[$prefix . $column] = $record->get($column);
168  }
169  /**
170  * Copy data from the request to a definition record.
171  * @param Rsi\Fred\Def\Record $record Definition record.
172  * @param string $prefix Prefix to add to the column name for the widget ID.
173  */
174  protected function dataToRecord($record,$prefix = null){
175  $request = $this->component('request');
176  foreach($record->columns as $column => $config) $record->set($column,$request->data[$prefix . $column]);
177  }
178  /**
179  * Remove one or more widget(s).
180  * @param string $ids,... Widget ID('s).
181  */
182  protected function deleteWidget(...$ids){
183  $this->getWidgets();
184  foreach($ids as $id) unset($this->_widgets[$id]);
185  }
186  /**
187  * Add a constraint.
188  * @param array $ids Widgets involved (an asterisk will be replaced with the current index during checking, '*--' with the
189  * previous index, '*++' with the next). Widgets that are empty (nothing) are ignored.
190  * @param string $operator Like used with \\Rsi\\Str::operator().
191  * @param string $group Group widget values (use TOTAL_* constants), rather than checking them one-by-one.
192  * @param number $total Grouping reference value. Set to true to make this equal to the number of values.
193  */
194  protected function addConstraint($ids,$operator,$group = null,$total = null){
195  $this->_constraints[] = compact('ids','operator','group','total');
196  }
197  /**
198  * Initialize the widgets.
199  * Called by the widget getter.
200  */
201  protected function initWidgets(){
202  }
203  /**
204  * Reset the controller.
205  * Called when the same controller is used for both the handling of the request ('post') and the view. Use this to perform
206  * actions between those two events.
207  */
208  public function reset(){
209  $this->_action = null;
210  }
211  /**
212  * Note if an action is expected.
213  * @param string $id Widget ID.
214  * @param string $action
215  */
216  public function expect($id,$action){
217  $expected = $this->session->expected ?: [];
218  \Rsi\Record::set($expected,[$id,$action],true);
219  $this->session->expected = $expected;
220  }
221  /**
222  * Was the action expected?
223  * @param string $id Widget ID.
224  * @param string $action
225  * @return bool
226  */
227  public function expected($id,$action){
228  if($result = \Rsi\Record::get($expected = $this->session->expected,[$id,$action = $this->action])){
229  unset($expected[$id][$action]);
230  $this->session->expected = $expected;
231  }
232  return $result;
233  }
234  /**
235  * Parameters for the route to this controller.
236  * @return array
237  */
238  public function routeParams(){
239  return [];
240  }
241  /**
242  * Route to this controller.
243  * @param string $type
244  * @param array $params Extra params.
245  * @return string
246  */
247  public function route($type = null,$params = null){
248  $router = $this->component('router');
249  if(($type === null) && (($type = $router->viewType) == $this->defaultViewType)) $type = null;
250  return $router->reverse($this->name,$type,($params ?: []) + $this->routeParams());
251  }
252  /**
253  * Navigate to another controller.
254  * @param int $levels Number of levels to go up.
255  * @param string $suffix Suffix to add.
256  * @param bool|array $params Parameters for the controller (set to false to only change the view controller name).
257  */
258  public function redir($levels = 1,$suffix = null,$params = null){
259  $request = $this->component('request');
260  $name = \Rsi\File::dirname($this->name,$levels) . $suffix;
261  if($params === false) $request->viewControllerName = $name;
262  else $request->redir = $this->component('router')->reverse($name,null,$params);
263  }
264  /**
265  * Default caption for a widget.
266  * @param string $id Widget ID.
267  * @return string
268  */
269  public function caption($id){
270  return str_replace('*',$id,$this->defaultCaption);
271  }
272  /**
273  * Default hint for a widget.
274  * @param string $id Widget ID or type.
275  * @return string
276  */
277  public function hint($id){
278  return str_replace('*',$id,$this->defaultHint);
279  }
280  /**
281  * Unknwon action called.
282  */
283  protected function unkownAction(){
284  $this->_fred->externalError('Unknown controller action',['class' => get_called_class(),'action' => $this->action]);
285  }
286  /**
287  * Default action (if no action specified).
288  */
289  protected function actionDefault(){
290  }
291  /**
292  * Return a fragment from the view.
293  */
294  protected function actionFragment(){
295  $this->fragmentId = $this->_fred->request->fragmentId;
296  }
297  /**
298  * Ping to keep the session alive.
299  */
300  protected function actionPingAlive(){
301  $alive = $this->component('alive');
302  if($this->component('request')->redir = $alive->ping()){
303  $message = $this->component('message');
304  $local = $this->component('local');
305  $message->warning($this->inactiveMessage,[
306  'maxSessionTime' => $alive->maxSessionTime ? $local->formatNumber($alive->maxSessionTime,1,0) : null,
307  'maxInactiveTime' => $alive->maxInactiveTime ? $local->formatNumber($alive->maxInactiveTime,1,0) : null,
308  'sessionStart' => $local->formatDateTime($alive->session->start),
309  'sessionAlive' => $local->formatDateTime($alive->session->alive)
310  ]);
311  }
312  }
313  /**
314  * Log client-side errors.
315  */
316  protected function actionClientError(){
317  if($this->clientErrorPrio){
318  $security = $this->component('security');
319  $request = $this->component('request');
320  if(
321  (count($errors = $security->session->clientErrors ?: []) < $this->clientErrorMax) &&
322  !in_array($hash = md5($request->message . $request->url . $request->lineNo),$errors)
323  ){
324  $this->component('log')->add(
325  $this->clientErrorPrio,
326  'Client error: ' . $request->message,
327  $request->url,
328  $request->lineNo,
329  array_filter(['column' => $request->column,'trace' => $request->trace,'journal' => $request->journal])
330  );
331  if(!$errors) $security->addBan('clientError',$this->clientErrorBanDelay);
332  $errors[] = $hash;
333  $security->session->clientErrors = $errors;
334  }
335  }
336  }
337  /**
338  * Return a feature hint translation.
339  */
340  protected function actionFeatureHint(){
341  $request = $this->component('request');
342  $request->result = $this->component('hint')->trans($request->id,$request->count);
343  }
344  /**
345  * Request a socket.
346  */
347  protected function actionRequestSocket(){
348  $socket = $this->component('socket');
349  $this->component('request')->result = [
350  'host' => $socket->clientHost,
351  'port' => $socket->clientPort,
352  'prefix' => $socket->clientPrefix,
353  'token' => $socket->token()
354  ];
355  }
356  /**
357  * Add an error to the request.
358  * @param string $id ID of the widget involved.
359  * @param string $error Error type.
360  */
361  protected function addError($id,$error){
362  $this->component('request')->errors[$id] = $this->component('trans')->str($this->errorStr,[
363  'id' => $id,
364  'error' => $error,
365  'caption' => strip_tags($this->widgets[$id]->caption($id))
366  ]);
367  }
368  /**
369  * Calculate the total for an array.
370  * @param array $values Array with values (string or numeric).
371  * @param string $type Type of total (see TOTAL_* constants).
372  * @return mixed Calculated value for array.
373  */
374  public function arrayTotal($values,$type){
375  if($values) switch($type){
376  case self::TOTAL_SUM: return array_sum($values);
377  case self::TOTAL_COUNT: return count($values);
378  case self::TOTAL_AVG: return array_sum($values) / count($values);
379  case self::TOTAL_MAX: return max($values);
380  case self::TOTAL_MIN: return min($values);
381  case self::TOTAL_UNIQUE: return count(array_unique($values));
382  }
383  return null;
384  }
385  /**
386  * Check a constraint.
387  * @param array $widget_ids Widgets in the action.
388  * @param array $ids Widgets involved.
389  * @param string $operator Like used with \\Rsi\\Str::operator().
390  * @param string $group Group widget values (use TOTAL_* constants), rather than checking them one-by-one.
391  * @param number $total Grouping reference value.
392  */
393  protected function checkConstraint($widget_ids,$ids,$operator,$group = null,$total = null){
394  $request = $this->component('request');
395  $indexes = null;
396  $sub_ids = [];
397  foreach($ids as $id){
398  $id = explode(Controller\Widget::CHILD_ID_SEPARATOR,$id);
399  if(
400  in_array($widget_id = array_shift($id),$widget_ids) &&
401  !$this->widgets[$widget_id]->nothing($value = $request->data[$widget_id])
402  ){
403  $sub_ids[] = [$widget_id,$id];
404  if($indexes === null) while($id) switch($sub = array_shift($id)){
405  case '*':
406  $indexes = $value ? array_keys($value) : [];
407  break 2; //exit while
408  default:
409  $value = \Rsi\Record::get($value,$sub);
410  }
411  }
412  }
413  if($indexes === null) $indexes = [null];
414  foreach($indexes as $i => $index){
415  $init = $prev = false;
416  $values = [];
417  foreach($sub_ids as list($widget_id,$id)){
418  $value = $request->data[$widget_id];
419  while($id){
420  switch($sub = array_shift($id)){
421  case '*':
422  $sub = $index;
423  break;
424  case '*--':
425  if(!$i) break 3; //exit sub_ids, next index
426  $sub = $indexes[$i - 1];
427  break;
428  case '*++':
429  if($i + 1 >= count($indexes)) break 3; //exit sub_ids, next index
430  $sub = $indexes[$i + 1];
431  break;
432  }
433  $value = \Rsi\Record::get($value,$sub);
434  if(!is_numeric($sub) && $this->widgets[$widget_id]->widgets[$sub]->nothing($value)) continue 2; //next sub_id
435  }
436  if($group) $values[] = $value;
437  elseif(!$init) $init = true;
438  elseif(!\Rsi\Str::operator($prev,$operator,$value)) $this->addError($widget_id,'constraint');
439  $prev = $value;
440  }
441  if($group && $values && !\Rsi\Str::operator(
442  $this->arrayTotal($values,$group),
443  $operator,
444  $total === true ? count($values) : $total
445  )) foreach($sub_ids as list($widget_id,$id)) $this->addError($widget_id,'group');
446  }
447  }
448  /**
449  * Check widget values.
450  * Widget data is taken from the request data array. Errors are added to the request.
451  * @param array $ids Widgets to check (empty = all).
452  * @return bool True if everything is OK.
453  */
454  protected function checkWidgets($ids = null){
455  $request = $this->component('request');
456  if(!$ids) $ids = array_keys($this->widgets);
457  foreach($ids as $id){
458  $widget = $this->widgets[$id];
459  if($widget->writeable && ($error = $widget->check($request->data[$id] ?? null))) $this->addError($id,$error);
460  }
461  if(!$request->errors) foreach($this->constraints as $constraint)
462  $this->checkConstraint($ids,$constraint['ids'],$constraint['operator'],$constraint['group'],$constraint['total']);
463  return !$request->errors;
464  }
465  /**
466  * Execute the action (if specified) on the controller.
467  * Security checks are executed before. All input and output is handled through the request component. An action can only
468  * trust the values from the data array. If the value is not present, the user is not authorized to modify it. All other
469  * values must be checked.
470  */
471  public function execute(){
472  $request = $this->component('request');
473  if($id = \Rsi\Str::part($request->widgetId,Controller\Widget::CHILD_ID_SEPARATOR)){
474  if(!array_key_exists($id,$this->widgets))
475  $this->_fred->externalError('Unknown widget',['class' => get_called_class(),'id' => $id]);
476  else{
477  $widget = $this->widgets[$id];
478  if(!$widget->readable) $this->_fred->externalError(
479  'User not authorized for widget',
480  ['class' => get_called_class(),'id' => $id,'action' => $this->action]
481  );
482  else $widget->execute();
483  }
484  }
485  elseif(!method_exists($this,$method = 'action' . ucfirst($this->action))) $this->unkownAction();
486  else{ //action on this controller
487  if(!$this->component('security')->check($this->securityChecksIgnore))
488  $this->_fred->externalError('Suspicious controller call',['class' => get_called_class()]);
489  $convert = $this->view->convert;
490  if(($widgets = $this->widgets) && ($ids = array_key_exists($this->action,$this->_checkWidgets) && ($this->_checkWidgets[$this->action] !== null)
491  ? $this->_checkWidgets[$this->action]
492  : (array_key_exists(null,$this->_checkWidgets) ? $this->_checkWidgets[null] : array_keys($widgets))
493  )){
494  foreach($ids as $id){
495  $request->data[$id] = null;
496  $widget = $widgets[$id];
497  if($widget->writeable){
498  $value = $widget->purge($request->complex(['widget',$id]));
499  $value = $convert ? $widget->convert($value) : $widget->clientConvert($value);
500  if($error = $widget->check($value)) $this->addError($id,$error);
501  else $request->data[$id] = $widget->dataConvert($value);
502  }
503  }
504  if(!$request->errors) foreach($this->constraints as $constraint)
505  $this->checkConstraint($ids,$constraint['ids'],$constraint['operator'],$constraint['group'],$constraint['total']);
506  }
507  foreach($widgets as $id => $widget) if(!$ids || !in_array($id,$ids)) $request->data[$id] = $widget->defaultValue;
508  if(!$request->errors) call_user_func([$this,$method]);
509  }
510  }
511  /**
512  * Necessary right for an action.
513  * @param string $action
514  * @return string Necessary right.
515  */
516  protected function actionRight($action){
517  $right = null;
518  if(array_key_exists($action ?: null,$this->_rights)){
519  $right = $this->_rights[$action];
520  if(substr($right,0,1) == User::RIGHT_LEVEL_SEPARATOR)
521  $right = \Rsi\Str::part($this->_rights[null],User::RIGHT_LEVEL_SEPARATOR) . $right;
522  }
523  elseif(array_key_exists(null,$this->_rights)) $right = $this->_rights[null];
524  return $right;
525  }
526  /**
527  * Available actions for current user.
528  * @param string $prefix Prefix where the action name has to start with.
529  * @return array Array with action names.
530  */
531  public function actions($prefix = null){
532  $actions = [];
533  $prefix = 'action' . ucfirst($prefix);
534  foreach(get_class_methods($this) as $method) if(
535  \Rsi\Str::startsWith($method,$prefix) &&
536  $this->component('user')->authorized($this->actionRight($action = lcfirst(substr($method,6))))
537  ) $actions[] = $action;
538  return $actions;
539  }
540 
541  protected function getAction(){
542  if($this->_action === null) $this->_action = $this->component('request')->action ?: 'default';
543  return $this->_action;
544  }
545 
546  protected function setCheckWidgets($check_widgets){
547  foreach($check_widgets as $action => $ids) $this->_checkWidgets[$action] = $ids ? array_values($ids) : $ids;
548  }
549 
550  protected function getConstraints(){
551  if($this->_constraints === null) $this->getWidgets();
552  return $this->_constraints;
553  }
554 
555  protected function getName(){
556  foreach($this->component('front')->controllerNamespaces + [null => null] as $namespace => $prefix)
557  if(\Rsi\Str::startsWith(get_called_class(),$namespace)) break;
558  return str_replace('\\','/',$prefix . substr(get_called_class(),strlen($namespace) + ($prefix ? 0 : 1)));
559  }
560 
561  protected function getRight(){
562  return $this->actionRight($this->action);
563  }
564 
565  protected function setRights($rights){
566  $this->_rights = array_merge($this->_rights,$rights);
567  }
568 
569  protected function getSecurityChecksIgnore(){
570  if($this->action && array_key_exists($this->action,$this->_securityChecksIgnore)) return $this->_securityChecksIgnore[$this->action];
571  if(array_key_exists(null,$this->_securityChecksIgnore)) return $this->_securityChecksIgnore[null];
572  return null;
573  }
574 
575  protected function setSecurityChecksIgnore($security_checks_ignore){
576  $this->_securityChecksIgnore = array_merge($this->_securityChecksIgnore,$security_checks_ignore);
577  }
578 
579  protected function getView(){
580  if($this->_view === null){
581  $type = $this->component('router')->viewType ?: $this->defaultViewType;
582  if(
583  !class_exists($class_name = str_replace('Controller','View',$this->viewClassName ?: get_called_class()) . '\\' . ucfirst($type)) && //specific view for this type
584  !class_exists($class_name = $this->defaultViewNamespace . '\\' . ucfirst($type)) && //general view for this type
585  !class_exists($class_name = str_replace('Controller','View',$this->viewClassName ?: get_called_class()) . '\\' . ucfirst($type = $this->defaultViewType)) //specific view for default type
586  ) $class_name = $this->defaultViewNamespace . '\\' . ucfirst($type); //default view for default type
587  $this->_view = new $class_name($this->_fred,array_replace_recursive(
588  $this->config('view',[]),
589  $this->config(['view',$type],[]),
590  ['controller' => $this]
591  ));
592  }
593  return $this->_view;
594  }
595 
596  protected function getWidgets(){
597  if($this->_widgets === null){
598  $this->_widgets = $this->_constraints = [];
599  $this->initWidgets();
600  }
601  return $this->_widgets;
602  }
603 
604  protected function setWidgets($value){
605  if($value === false) $this->_widgets = [];
606  else $this->addWidgets($value);
607  }
608 
609  protected function _get($key){
610  return $this->widgets[$key];
611  }
612 
613  protected function _set($key,$value){
614  $this->addWidget($key,$value);
615  }
616 
617 }
route($type=null, $params=null)
Route to this controller.
Definition: Controller.php:247
addAuth($name)
Add an authentication check to all sets, or create a new one if none exists.
Definition: Controller.php:80
setCheckWidgets($check_widgets)
Definition: Controller.php:546
$inactiveMessage
Message for inactive user who is redirected to login controller.
Definition: Controller.php:30
addWidgets($widgets)
Add multiple widgets.
Definition: Controller.php:107
widgetFromDef($table, $column, $extra=null)
Create a widget from a database definition.
Definition: Controller.php:136
setSecurityChecksIgnore($security_checks_ignore)
Definition: Controller.php:575
addByType($id, $type, $config)
Add a widget by type.
Definition: Controller.php:126
removeAuth($name)
Remove an authentication check from all sets.
Definition: Controller.php:89
addFromDef($table, $columns=null, $extra=null, $prefix=null)
Add widgets from a database definition.
Definition: Controller.php:147
const DISPLAY_WRITEABLE
Show editable input element(s).
Definition: Widget.php:39
addError($id, $error)
Add an error to the request.
Definition: Controller.php:361
$clientErrorBanDelay
Ban delay for the first error in a new session (prevent flooding via multiple.
Definition: Controller.php:33
expect($id, $action)
Note if an action is expected.
Definition: Controller.php:216
redir($levels=1, $suffix=null, $params=null)
Navigate to another controller.
Definition: Controller.php:258
config($key, $default=null)
Retrieve a config value.
Definition: Component.php:53
$_authSets
Possible sets of necessary authentication (array of arrays of authentication checks).
Definition: Controller.php:39
addWidget($id, $widget)
Add a single widget.
Definition: Controller.php:99
$clientErrorMax
Maximum number of client errors to log in one session.
Definition: Controller.php:35
actionDefault()
Default action (if no action specified).
Definition: Controller.php:289
routeParams()
Parameters for the route to this controller.
Definition: Controller.php:238
$_action
Widgets to check per action (key = action; value = array with ID&#39;s of widget to check; null = default...
Definition: Controller.php:46
dataToRecord($record, $prefix=null)
Copy data from the request to a definition record.
Definition: Controller.php:174
checkConstraint($widget_ids, $ids, $operator,$group=null, $total=null)
Check a constraint.
Definition: Controller.php:393
addFromRecord($record, $prefix=null)
Add widgets from a definition record.
Definition: Controller.php:157
actionRight($action)
Necessary right for an action.
Definition: Controller.php:516
actionClientError()
Log client-side errors.
Definition: Controller.php:316
actionFeatureHint()
Return a feature hint translation.
Definition: Controller.php:340
$domainRedirPermanent
True to make a redirection permanent (HTTP status code = 301; defaults to 302).
Definition: Controller.php:17
deleteWidget(... $ids)
Remove one or more widget(s).
Definition: Controller.php:182
$display
Default display mode for widgets.
Definition: Controller.php:24
checkWidgets($ids=null)
Check widget values.
Definition: Controller.php:454
widgetByType($type, $config)
Create a widget by type.
Definition: Controller.php:116
hint($id)
Default hint for a widget.
Definition: Controller.php:277
addConstraint($ids, $operator,$group=null, $total=null)
Add a constraint.
Definition: Controller.php:194
unkownAction()
Unknwon action called.
Definition: Controller.php:283
$defaultCaption
An asterisk will be replaced with widget ID.
Definition: Controller.php:25
$_securityChecksIgnore
Security checks to ignore (key = action, null = default; value = array with.
Definition: Controller.php:37
actionPingAlive()
Ping to keep the session alive.
Definition: Controller.php:300
reset()
Reset the controller.
Definition: Controller.php:208
publish($property, $visibility=self::READABLE)
Publish a property (or hide it again).
Definition: Thing.php:27
initWidgets()
Initialize the widgets.
Definition: Controller.php:201
_set($key, $value)
Definition: Controller.php:613
expected($id, $action)
Was the action expected?
Definition: Controller.php:227
Basic component class.
Definition: Component.php:8
$viewClassName
Fix the view to a certain View or Controller class (empty = same as called class).
Definition: Controller.php:21
const RIGHT_LEVEL_SEPARATOR
Separator between right and level in a single string notation.
Definition: User.php:10
actions($prefix=null)
Available actions for current user.
Definition: Controller.php:531
dataFromRecord($record, $prefix=null)
Copy data from a definition record to the request.
Definition: Controller.php:165
arrayTotal($values, $type)
Calculate the total for an array.
Definition: Controller.php:374
actionFragment()
Return a fragment from the view.
Definition: Controller.php:294
execute()
Execute the action (if specified) on the controller.
Definition: Controller.php:471
$clientErrorPrio
Log client errors with this prio (empty = do not log).
Definition: Controller.php:32
actionRequestSocket()
Request a socket.
Definition: Controller.php:347
$domainRedir
Prefered domain notation (key = domain mask regex, value = prefered domain, incl. protocol)...
Definition: Controller.php:16
caption($id)
Default caption for a widget.
Definition: Controller.php:269
component($name)
Get a component (local or default).
Definition: Component.php:80
$defaultHint
An asterisk will be replaced with the widget ID or type.
Definition: Controller.php:26
$_rights
Necessary right needed per action (key = action, null = default; value = right, optionally.
Definition: Controller.php:40