FusionDirectory
class_simpleTabs.inc
Go to the documentation of this file.
1 <?php
2 /*
3  This code is part of FusionDirectory (http://www.fusiondirectory.org/)
4  Copyright (C) 2003-2010 Cajus Pollmeier
5  Copyright (C) 2011-2016 FusionDirectory
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21 
31 {
32  var $dn;
33  var $acl;
34  var $is_template;
35 
36  public $objectType = FALSE;
37  protected $specialTabs = TRUE;
38  protected $plNotify = [];
39 
40  var $last = "";
41  var $current = "";
42  var $disabled = "";
43  var $by_name = [];
47  var $by_object = [];
48  var $acl_category;
49 
50  /* A parent object if available, e.g. a management class. */
51  var $parent = NULL;
52 
53  var $baseclass = "";
54 
55  public $ignoreAcls = FALSE;
56 
60  function __construct (string $type, $dn, $attrs_object = NULL)
61  {
62  global $config;
63 
64  $infos = objects::infos($type);
65  $data = $config->data['TABS'][$infos['tabGroup']];
66  $this->acl_category = $infos['aclCategory'];
67  $this->objectType = $type;
68  $this->dn = $dn;
69 
70  if (!count($data)) {
71  throw new FusionDirectoryException(
72  sprintf(
73  _('No plugin definitions found to initialize "%s", please check your configuration file.'),
74  get_class($this)
75  )
76  );
77  }
78 
79  $this->baseclass = NULL;
80  foreach ($data as $tab) {
81  if (!plugin_available($tab['CLASS'])) {
82  continue;
83  }
84  if (!is_a($tab['CLASS'], 'SimpleTab', TRUE)) {
85  throw new FusionDirectoryException('Invalid class '.$tab['CLASS'].' found in '.$type.' tab list');
86  }
87 
88  $this->by_name[$tab['CLASS']] = $tab['NAME'];
89  $this->plNotify[$tab['CLASS']] = FALSE;
90 
91  if ($this->baseclass === NULL) {
92  $this->by_object[$tab['CLASS']] = new $tab['CLASS']($this->dn, $attrs_object, $this, TRUE);
93  $this->baseclass = $tab['CLASS'];
94  } else {
95  $this->by_object[$tab['CLASS']] = new $tab['CLASS']($this->dn, $this->by_object[$this->baseclass], $this, FALSE);
96  }
97 
98  $this->by_object[$tab['CLASS']]->set_acl_category($this->acl_category);
99  }
100 
101  /* Initialize current */
102  $this->current = $this->baseclass;
103 
104  if ($infos['mainAttr']) {
105  $baseobject = $this->getBaseObject();
106  if (
107  ($baseobject instanceof simplePlugin) &&
108  ($baseobject->attributesAccess[$infos['mainAttr']]->getUnique() === FALSE)
109  ) {
110  $baseobject->attributesAccess[$infos['mainAttr']]->setUnique('one');
111  }
112  }
113 
114  if ($this->specialTabs) {
115  /* Add references/acls/snapshots */
116  $this->addSpecialTabs();
117  }
118  }
119 
125  function re_init ()
126  {
127  $baseobject = NULL;
128  foreach ($this->by_object as $name => $object) {
129  $class = get_class($object);
130  if (in_array($class, ["reference","acl"])) {
131  continue;
132  }
133  if ($baseobject === NULL) {
134  $baseobject = new $class($this->dn, NULL, $this, TRUE);
135  $this->by_object[$name] = $baseobject;
136  } else {
137  $this->by_object[$name] = new $class($this->dn, $baseobject, $this, FALSE);
138  }
139  $this->by_object[$name]->set_acl_category($this->acl_category);
140  }
141  }
142 
146  public static function getPotentialTabList (string $type, array $infos): array
147  {
148  global $config;
149 
150  return $config->data['TABS'][$infos['tabGroup']];
151  }
152 
156  function setActiveTabs (&$tabObject)
157  {
158  foreach ($this->by_object as $class => $plugin) {
159  if ($plugin->isActive()) {
160  $tabObject->by_object[$class]->is_account = $plugin->is_account;
161  }
162  }
163  }
164 
165  function resetCopyInfos ()
166  {
167  $this->dn = 'new';
168  foreach ($this->by_object as &$obj) {
169  $obj->resetCopyInfos();
170  }
171  unset($obj);
172  }
173 
174  function resetBase ()
175  {
176  global $ui;
177  $baseobject = $this->getBaseObject();
178  if (isset($baseobject->base)) {
179  logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $baseobject->base, 'Fixing base');
180  $baseobject->base = $ui->getCurrentBase();
181  logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $baseobject->base, 'Fixed base');
182  } else {
183  logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, '', 'no base');
184  }
185  }
186 
187  function getBaseObject (): SimpleTab
188  {
189  return $this->by_object[$this->baseclass];
190  }
191 
193  function readOnly ()
194  {
195  return $this->getBaseObject()->readOnly();
196  }
197 
201  function save_object ()
202  {
203  trigger_error('obsolete');
204  $this->readPost();
205  }
206 
207  public function readPostTabChange ()
208  {
209  /* Look for pressed tab button */
210  foreach (array_keys($this->by_object) as $class) {
211  if (isset($_POST[$class]) || (isset($_POST['arg']) && ($_POST['arg'] == $class))) {
212  $this->current = $class;
213  break;
214  }
215  }
216  }
217 
218  public function readPost ()
219  {
220  /* Ensure that the currently selected tab is valid. */
221  if (!isset($this->by_name[$this->current])) {
222  $this->current = key($this->by_name);
223  }
224 
225  /* Rotate current to last */
226  $this->last = $this->current;
227 
228  /* Save last tab */
229  if ($this->last != '') {
230  logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->last, 'Reading POST');
231 
232  $this->by_object[$this->last]->readPost();
233  }
234 
235  $this->readPostTabChange();
236  }
237 
238  function execute ()
239  {
240  trigger_error('obsolete');
241  $this->update();
242  return $this->render();
243  }
244 
245  public function update (): bool
246  {
247  /* Call update on all tabs as they may react to changes in other tabs */
248  foreach ($this->by_object as $key => $obj) {
249  $obj->update();
250  }
251 
252  return TRUE;
253  }
254 
257  public function render (): string
258  {
259  /* Compute tab content */
260  $tabContent = $this->by_object[$this->current]->render();
261 
262  /* Build tab line */
263  $display = $this->renderTabList($this->dialogOpened());
264 
265  /* Show object */
266  $display .= '<div class="tab-content">'."\n";
267  $display .= $tabContent;
268  $display .= '</div>';
269 
270  return $display;
271  }
272 
276  public function loadTabs ()
277  {
278  }
279 
285  protected function renderTabList (bool $disabled = FALSE): string
286  {
287  $display = '';
288  if (!$disabled) {
289  $display .= '<input type="hidden" name="arg" value=""/>';
290  }
291  $display .= '<table class="tabs-header"><tbody><tr>';
292  $index = 0;
293  $style = ['tab-left', 'tab-active', 'tab-right'];
294  foreach ($this->by_name as $class => $name) {
295  $obj = $this->by_object[$class];
296 
297  /* Activate right tabs with style "tab-right"
298  * Activate current tab with style "tab-active " */
299  if (($index == 1) || ($class == $this->current)) {
300  $index++;
301  }
302 
303  /* Paint tab */
304  if ($obj->aclHasPermissions() && empty($obj->aclGetPermissions(''))) {
305  $display .= '<td class="nonreadable">';
306  } else {
307  $display .= '<td>';
308  }
309 
310  /* Shorten string if its too long for the tab headers*/
311  $title = _($name);
312  if (mb_strlen($title, 'UTF-8') > 28) {
313  $title = mb_substr($title, 0, 25, 'UTF-8')."...";
314  }
315 
316  $cssClasses = $style[$index];
317 
318  /* Take care about notifications */
319  if ($this->plNotify[$class] && $obj->isActive()) {
320  $cssClasses .= ' tab-notify';
321  }
322  if ($disabled) {
323  $cssClasses .= ' tab-disabled';
324  }
325  if (!$obj->isActive()) {
326  $cssClasses .= ' tab-inactive';
327  }
328 
329 
330  $display .= '<div class="'.$cssClasses.'">';
331  if ($disabled) {
332  $display .= '<a>';
333  } else {
334  $display .= '<a '.
335  'id="tab_'.$class.'" '.
336  'onclick="return true;" '.
337  'href="'."javascript:document.mainform.arg.value='$class';document.mainform.submit();".'">';
338  }
339  $display .= htmlescape($title).'</a></div></td>';
340  }
341 
342  $display .= "<td>\n";
343  $display .= '<div class="tab-border">&nbsp;</div></td></tr></tbody></table>';
344 
345  return $display;
346  }
347 
353  public function delete (bool $checkAcl = TRUE): array
354  {
355  if ($checkAcl && !$this->getBaseObject()->acl_is_removeable()) {
356  return [new SimplePluginPermissionError($this, msgPool::permDelete($this->getBaseObject()->dn))];
357  }
358 
359  /* Delete all tabs in reverse order */
360  foreach (array_reverse($this->by_object) as $obj) {
361  $errors = $obj->remove(TRUE);
362  if (!empty($errors)) {
363  return $errors;
364  }
365  }
366 
367  return [];
368  }
369 
373  public function check (): array
374  {
375  global $config;
376  $messages = [];
377 
378  if ($this->getBaseObject()->is_template) {
379  $ldap = $config->get_ldap_link();
380  $ldap->cd($config->current['BASE']);
381  $filter = '(&(objectClass=fdTemplate)(cn='.ldap_escape_f($this->getBaseObject()->_template_cn).'))';
382  $ldap->search($filter, ['dn']);
383  while ($attrs = $ldap->fetch()) {
384  if ($attrs['dn'] != $this->getBaseObject()->dn) {
385  $messages[] = new SimplePluginCheckError(
386  $this->getBaseObject()->attributesAccess['_template_cn'],
387  msgPool::duplicated($this->getBaseObject()->attributesAccess['_template_cn']->getLabel(), $attrs['dn'])
388  );
389  }
390  }
391  return $messages;
392  }
393 
394  $current_set = FALSE;
395 
396  /* Check all plugins */
397  foreach ($this->by_object as $key => $obj) {
398  $this->plNotify[$key] = FALSE;
399  if ($obj->isActive() && (!$obj->is_template)) {
400  logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $key, "Checking");
401 
402  $msg = $obj->check();
403 
404  if (count($msg)) {
405  $this->plNotify[$key] = TRUE;
406  if (!$current_set) {
407  $current_set = TRUE;
408  $this->current = $key;
409  $messages = $msg;
410  }
411  }
412  }
413  }
414 
415  return $messages;
416  }
417 
418  /*
419  * \brief Save object in the tab
420  */
421  function save ()
422  {
423  global $ui;
424  $messages = $this->check();
425  if (!empty($messages)) {
426  return $messages;
427  }
428 
429  $baseobject = $this->getBaseObject();
430  $old_dn = $this->dn;
431  try {
432  $new_dn = $baseobject->compute_dn();
433  logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $new_dn, 'Saving');
434  } catch (FusionDirectoryException $e) {
435  return [
436  new SimplePluginError(
437  $baseobject,
438  htmlescape(sprintf(_('Failed to compute DN for object: %s'), $e->getMessage())),
439  0,
440  $e
441  )
442  ];
443  }
444 
445  $errors = [];
446  $creation = ($this->dn == 'new');
447 
448  /* Move ? */
449  if ($this->dn != $new_dn) {
450  /* Write entry on new 'dn' */
451  if ($creation) {
452  /* use the new one */
453  $this->dn = $new_dn;
454  } else {
455  if (($error = $baseobject->move($this->dn, $new_dn)) === TRUE) {
456  $this->dn = $new_dn;
457  } else {
458  $errors[] = new SimplePluginError(
459  $baseobject,
460  htmlescape(sprintf(_('Move from "%s" to "%s" failed: %s'), $this->dn, $new_dn, $error))
461  );
462  return $errors;
463  }
464  }
465  }
466 
467  /* Save all plugins */
468  $first = TRUE;
469  foreach ($this->by_object as $key => $obj) {
470  logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $key, 'Saving');
471 
472  $obj->dn = $this->dn;
473 
474  if ($obj->isActive()) {
475  $result = $obj->save();
476  } else {
477  $result = $obj->remove(FALSE);
478  }
479  if (!empty($result)) {
480  if ($creation && $first) {
481  /* If the save of main tab fails for a creation, cancel the save of other tabs */
482  $this->dn = $old_dn;
483  $obj->dn = $this->dn;
484  return $result;
485  }
486  $errors = array_merge($errors, $result);
487  }
488  if ($first) {
489  $first = FALSE;
490  }
491  }
492 
493  if (empty($errors) && isset($ui->dn) && ($this->dn == $ui->dn)) {
494  /* If the logged in user was edited, update his information */
495  $ui->loadLDAPInfo();
496  }
497 
498  if (!empty($errors)) {
499  $this->dn = $old_dn;
500  foreach ($this->by_object as $obj) {
501  $obj->dn = $this->dn;
502  }
503  }
504 
505  return $errors;
506  }
507 
514  function adapt_from_template (array $attrs, array $skip = [])
515  {
516  foreach ($this->by_object as $key => &$obj) {
517  logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $key, "Adapting");
518  $obj->parent = &$this;
519  $obj->adapt_from_template($attrs, $skip);
520  }
521  unset($obj);
522  }
523 
527  function addSpecialTabs ()
528  {
529  global $config;
530  $baseobject = $this->getBaseObject();
531  foreach ($config->data['TABS']['SPECIALTABS'] as $tab) {
532  if (!plugin_available($tab['CLASS'])) {
533  continue;
534  }
535 
536  $this->by_name[$tab['CLASS']] = $tab['NAME'];
537  $this->plNotify[$tab['CLASS']] = FALSE;
538  $this->by_object[$tab['CLASS']] = new $tab['CLASS']($this->dn, $baseobject, $this, FALSE);
539  $this->by_object[$tab['CLASS']]->set_acl_category($this->acl_category);
540  }
541  }
542 
546  function getAclBase (): string
547  {
548  return $this->getBaseObject()->getAclBase(FALSE);
549  }
550 
551  function setTemplateMode ($cn)
552  {
553  $this->getBaseObject()->_template_cn = $cn;
554 
555  foreach ($this->by_object as &$obj) {
556  $obj->setTemplate(TRUE);
557  }
558  unset($obj);
559  }
560 
561  public function setNeedEditMode ($bool)
562  {
563  foreach ($this->by_object as &$obj) {
564  $obj->setNeedEditMode($bool);
565  }
566  unset($obj);
567  }
568 
569  public function setIgnoreAcls ($bool)
570  {
571  $this->ignoreAcls = $bool;
572  }
573 
574  public function dialogOpened (): bool
575  {
576  return $this->by_object[$this->current]->is_modal_dialog();
577  }
578 
579  function objectInfos ()
580  {
581  if ($this->objectType === FALSE) {
582  return FALSE;
583  }
584  return objects::infos($this->objectType);
585  }
586 
587  /* Return tab or service if activated, FALSE otherwise */
588  function getTabOrServiceObject ($tab)
589  {
590  if (isset($this->by_object[$tab]) && $this->by_object[$tab]->isActive()) {
591  return $this->by_object[$tab];
592  } elseif (is_subclass_of($tab, 'simpleService') && isset($this->by_object['servicesManagement'])) {
593  return $this->by_object['servicesManagement']->getServiceObject($tab);
594  } else {
595  return FALSE;
596  }
597  }
598 }
599 
604 {
605  protected $specialTabs = FALSE;
606 }
renderTabList(bool $disabled=FALSE)
Generate the tab classes.
htmlescape(string $str)
Escape string for HTML output.
Definition: php_setup.inc:32
This class is made for easy plugin creation for editing LDAP attributes.
render()
This function display the plugin and return the html code.
readOnly()
Indicates if this tab class is read-only (because of locks)
readPost()
Interpret POST content.
This interface should be implemented by all dialog classes in FusionDirectory.
__construct(string $type, $dn, $attrs_object=NULL)
Tabs classes constructor.
This class contains all function to manage tabs classes.
static getPotentialTabList(string $type, array $infos)
Returns the list of tabs which may appear for a given object type.
re_init()
Reinitializes the tab classes with fresh ldap values.
adapt_from_template(array $attrs, array $skip=[])
Adapt from template.
Error returned by any method of SimplePlugin.
save_object()
Save a tabs object.
setActiveTabs(&$tabObject)
Sets the active tabs from this instance to an other one. Used by templates.
For objects which does not support special tabs such as LDAP and references.
static debug(int $level, int $line, string $function, string $file, $data, string $info='')
Debug output method.
Error returned by check method of SimplePlugin.
Parent class for all exceptions thrown in FusionDirectory.
static permDelete($name='')
Display that we have no permission to delete an object.
getAclBase()
Get LDAP base to use for ACL checks.
static duplicated($name, $dn=NULL)
Display error about existing entry in the system.
loadTabs()
Load tab list if needed.
update()
Update state and return FALSE if the dialog was closed.
addSpecialTabs()
Add special Tabs.
plugin_available($plugin)
Check if plugin is available.
Definition: functions.inc:108