FusionDirectory
 All Data Structures Files Functions Variables
class_SetAttribute.inc
1 <?php
2 /*
3  This code is part of FusionDirectory (http://www.fusiondirectory.org/)
4  Copyright (C) 2012-2016 FusionDirectory
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20 
24 class SetAttribute extends Attribute
25 {
26  public $attribute;
27  protected $valueUnicity = TRUE;
28  protected $editingValue = FALSE;
29  protected $linearRendering = TRUE;
30  protected $size = 4;
31 
38  function __construct ($attribute, $values = array(), $valueUnicity = TRUE)
39  {
40  parent::__construct(
41  $attribute->getLabel(), $attribute->getDescription(),
42  $attribute->getLdapName(), $attribute->isRequired(),
43  $values
44  );
45  $this->attribute = $attribute;
46  $this->attribute->setRequired(TRUE);
47  $this->valueUnicity = $valueUnicity;
48  }
49 
50  function setManagedAttributes ($dontcare)
51  {
52  trigger_error('method setManagedAttributes is not supported for SetAttributes');
53  }
54 
55  function setLinearRendering ($bool)
56  {
57  $this->linearRendering = $bool;
58  }
59 
60  protected function loadAttrValue ($attrs)
61  {
62  if (isset($attrs[$this->getLdapName()]["count"])) {
63  $this->value = array();
64  for ($i = 0; $i < $attrs[$this->getLdapName()]["count"]; $i++) {
65  $this->value[] = $attrs[$this->getLdapName()][$i];
66  }
67  } else {
68  $this->resetToDefault();
69  }
70  }
71 
72  function getAcl ()
73  {
74  if ($this->attribute === FALSE) {
75  return parent::getAcl();
76  }
77  return $this->attribute->getAcl();
78  }
79 
80  function setAcl ($acl)
81  {
82  if ($this->attribute === FALSE) {
83  return parent::setAcl($acl);
84  }
85  $this->attribute->setAcl($acl);
86  }
87 
88  function addPostValue ($value)
89  {
90  if ($value === '') {
91  return FALSE;
92  }
93  if ($this->valueUnicity && in_array($value, $this->postValue, TRUE)) {
94  return FALSE;
95  }
96  $this->postValue[] = $value;
97  return TRUE;
98  }
99 
100  function delPostValue ($key)
101  {
102  unset($this->postValue[$key]);
103  }
104 
105  function loadPostValue ()
106  {
107  $this->editingValue = FALSE;
108  $id = $this->getHtmlId();
109  if ($this->isVisible()) {
110  $this->postValue = $this->value;
111  if (isset($_POST["add".$id])) {
112  if ($this->attribute !== FALSE) {
113  $this->attribute->loadPostValue();
114  $this->attribute->applyPostValue();
115  $this->addPostValue($this->attribute->getValue());
116  }
117  } elseif (isset($_POST["del".$id]) && isset($_POST["row".$id])) {
118  foreach ($_POST["row".$id] as $key) {
119  $this->delPostValue($key);
120  }
121  } elseif ($this->attribute !== FALSE) {
122  $this->attribute->loadPostValue();
123  $this->attribute->applyPostValue();
124  $this->editingValue = $this->attribute->getValue();
125  }
126  }
127  }
128 
129  function check ()
130  {
131  $error = parent::check();
132  if (!empty($error) || ($this->attribute === FALSE)) {
133  return $error;
134  } else {
135  if (!is_array($this->value)) {
136  return sprintf(_('The value for multivaluated field "%s" is not an array'), $this->getLabel());
137  }
138  foreach ($this->value as $value) {
139  $this->attribute->setValue($value);
140  $error = $this->attribute->check();
141  if (!empty($error)) {
142  return $error;
143  }
144  }
145  }
146  }
147 
148  function renderFormInput ()
149  {
150  $display = $this->renderOnlyFormInput();
151  $attr_display = $this->renderAttributeInput(FALSE);
152  $buttons = $this->renderButtons();
153  return $this->renderAcl($display).$attr_display.$this->renderAcl($buttons);
154  }
155 
156  function renderTemplateInput ()
157  {
158  $display = $this->renderOnlyFormInput();
159  $attr_display = $this->renderAttributeInput(TRUE);
160  $buttons = $this->renderButtons();
161  return $this->renderAcl($display).$attr_display.$this->renderAcl($buttons);
162  }
163 
164  function renderOnlyFormInput()
165  {
166  if (($this->size < 15) && ($this->size < count($this->value))) {
167  $this->size = min(15, count($this->value));
168  }
169  $id = $this->getHtmlId();
170  $smarty = get_smarty();
171  $smarty->assign($id.'_values', $this->getDisplayValues());
172  $display = '<select multiple="multiple" name="row'.$id.'[]" id="row'.$id.'" size="'.$this->size.'"'.
173  ($this->disabled? ' disabled="disabled"':'').
174  ' >'."\n";
175  $display .= '{html_options options=$'.$id.'_values}';
176  $display .= '</select><br/>'."\n";
177  return $display;
178  }
179 
180  function getDisplayValues ()
181  {
182  if ($this->attribute === FALSE) {
183  return $this->value;
184  }
185  $attribute = $this->attribute;
186  return array_map(
187  function ($value) use($attribute)
188  {
189  return $attribute->displayValue($value);
190  },
191  $this->value
192  );
193  }
194 
195  function handleEditingValue()
196  {
197  if ($this->editingValue === FALSE) {
198  $this->attribute->resetToDefault();
199  } else {
200  $this->attribute->setValue($this->editingValue);
201  }
202  }
203 
204  function renderAttributeInput ($template = FALSE)
205  {
206  if ($this->attribute === FALSE) {
207  return;
208  }
209  $this->handleEditingValue();
210  if ($template) {
211  return $this->attribute->renderTemplateInput();
212  } else {
213  return $this->attribute->renderFormInput();
214  }
215  }
216 
217  function renderAttribute(&$attributes, $readOnly)
218  {
219  if ($this->attribute === FALSE) {
220  return parent::renderAttribute($attributes, $readOnly);
221  }
222  if ($this->visible) {
223  $this->attribute->setDisabled($this->disabled);
224  if ($this->linearRendering || $readOnly) {
225  parent::renderAttribute($attributes, $readOnly);
226  } else {
227  $attributes[$this->getLdapName()] = array(
228  'htmlid' => $this->getForHtmlId(),
229  'label' => '{literal}'.$this->getLabel().'{/literal}'.($this->isRequired()?'{$must}':''),
230  'description' => ($this->isRequired()?sprintf(_("%s (required)"), $this->getDescription()):$this->getDescription()),
231  'input' => $this->renderOnlyFormInput(),
232  );
233  $this->handleEditingValue();
234  $this->attribute->renderAttribute($attributes, $readOnly);
235  $attributes[$this->getLdapName().'_buttons'] = array(
236  'htmlid' => 'add'.$this->getHtmlId(),
237  'label' => '',
238  'description' => '',
239  'input' => $this->renderButtons(),
240  );
241  }
242  }
243  }
244 
245  function serializeAttribute(&$attributes, $form = TRUE)
246  {
247  parent::serializeAttribute($attributes, $form);
248  if ($this->attribute === FALSE) {
249  return;
250  }
251  if ($form) {
252  return;
253  } else {
254  $subattributes = array();
255  $this->attribute->setDisabled($this->disabled);
256  $this->attribute->serializeAttribute($subattributes, $form);
257  $attributes[$this->getLdapName()]['attributes'] = $subattributes;
258  $attributes[$this->getLdapName()]['attributes_order'] = array_keys($subattributes);
259  }
260  }
261 
262  function getForHtmlId()
263  {
264  // Label should point to the attribute
265  if (is_object($this->attribute)) {
266  return $this->attribute->getForHtmlId();
267  } else {
268  return '';
269  }
270  }
271 
272  function renderButtons ()
273  {
274  $id = $this->getHtmlId();
275  $buttons = $this->renderInputField('submit', 'add'.$id, array('value' => '{msgPool type=addButton}'));
276  $buttons .= $this->renderInputField('submit', 'del'.$id, array('value' => '{msgPool type=delButton}'));
277  return $buttons;
278  }
279 
280  function computeLdapValue ()
281  {
282  return array_values($this->value);
283  }
284 
285  public function htmlIds()
286  {
287  $id = $this->getHtmlId();
288  return array_merge(array('add'.$id,'del'.$id,'row'.$id), $this->attribute->htmlIds());
289  }
290 
295  function setParent (&$plugin)
296  {
297  parent::setParent($plugin);
298  if ($this->attribute !== FALSE) {
299  $this->attribute->setParent($plugin);
300  }
301  }
302 
303  function getArrayValues()
304  {
305  $result = array();
306  foreach ($this->value as $value) {
307  $this->attribute->setValue($value);
308  $row = array();
309  foreach ($this->attribute->getArrayValue() as $val) {
310  $row[] = $val;
311  }
312  $result[] = $row;
313  }
314  return $result;
315  }
316 
317  function foreignKeyUpdate($oldvalue, $newvalue, $source)
318  {
319  foreach ($this->value as $key => &$value) {
320  if ($value == $oldvalue) {
321  if ($newvalue === NULL) {
322  unset($this->value[$key]);
323  } elseif ($source['MODE'] == 'copy') {
324  $this->value[] = $newvalue;
325  } elseif ($source['MODE'] == 'move') {
326  $value = $newvalue;
327  }
328  }
329  }
330  unset($value);
331  }
332 
333  function foreignKeyCheck($value, $source)
334  {
335  return in_array($value, $this->value);
336  }
337 
338  function setSize($size)
339  {
340  $this->size = $size;
341  }
342 
343  function checkValue($value)
344  {
345  if (!is_array($value)) {
346  throw new InvalidValueException(sprintf(_('SetAttribute "%s" was set to a non-compatible value'), $this->getLabel()));
347  }
348  }
349 }
350 
352 {
353  protected $order;
354  protected $edit_enabled;
355  protected $height = 90;
356  protected $headers = FALSE;
357 
363  function __construct ($attribute, $order = TRUE, $values = array(), $edit_enabled = FALSE)
364  {
365  parent::__construct($attribute, $values);
366  $this->order = $order;
367  $this->edit_enabled = $edit_enabled;
368  }
369 
370  function setHeight($h)
371  {
372  $this->height = $h;
373  }
374 
375  function setHeaders($h)
376  {
377  $this->headers = $h;
378  }
379 
380  function readValue($value)
381  {
382  if ($this->order) {
383  return preg_split('/:/', $value, 2);
384  } else {
385  return $value;
386  }
387  }
388 
389  function writeValue($key, $value)
390  {
391  if ($this->order) {
392  return $key.":".$value;
393  } else {
394  return $value;
395  }
396  }
397 
398  function computeLdapValue ()
399  {
400  $ldapValue = array();
401  foreach ($this->value as $key => $value) {
402  $ldapValue[] = $this->writeValue($key, $value);
403  }
404  return $ldapValue;
405  }
406 
407  protected function loadAttrValue ($attrs)
408  {
409  if (isset($attrs[$this->getLdapName()]["count"])) {
410  $this->value = array();
411  for ($i = 0; $i < $attrs[$this->getLdapName()]["count"]; $i++) {
412  $value = $this->readValue($attrs[$this->getLdapName()][$i]);
413  if (is_array($value)) {
414  $this->value[$value[0]] = $value[1];
415  } else {
416  $this->value[] = $value;
417  }
418  }
419  } else {
420  $this->resetToDefault();
421  }
422  if ($this->order) {
423  $this->reIndexValues();
424  }
425  }
426 
427  function renderOnlyFormInput ()
428  {
429  $id = $this->getHtmlId();
430  $div = new divSelectBox('rows'.$id);
431  $smarty = get_smarty();
432  $div->SetHeight($this->height);
433  $div->SetHeaders($this->headers);
434  foreach ($this->value as $key => $value) {
435  $fields = array();
436  foreach ($this->getAttributeArrayValue($key, $value) as $field) {
437  if (is_array($field)) {
438  $fields[] = $field;
439  } else {
440  $fields[] = array('string' => $field);
441  }
442  }
443  if (empty($fields)) {
444  continue;
445  }
446 
447  list ($img, $nbicons) = $this->genRowIcons($key, $value);
448 
449  $fields[] = array("html" => $img, "attach" => 'style="border:0px;width:'.($nbicons * 20).'px;"');
450  $div->AddEntry($fields);
451  }
452  $smarty->assign("div_$id", $div->DrawList());
453  return '{$div_'.$id.'}'."\n";
454  }
455 
456  protected function genRowIcons($key, $value)
457  {
458  $id = $this->getHtmlId();
459 
460  $img = '';
461  $nbicons = 1;
462 
463  if ($this->order) {
464  $nbicons += 2;
465  if ($key != 0) {
466  $img .= $this->renderInputField(
467  'image', $id.'_up_'.$key,
468  array(
469  'src' => 'geticon.php?context=actions&amp;icon=view-sort-descending&amp;size=16',
470  'title' => _('Sort up'),
471  'alt' => _('Sort up'),
472  'class' => 'center'
473  )
474  );
475  } else {
476  $img .= '<img src="images/empty.png" alt="" style="width:16px;"/>';
477  }
478  if (($key + 1) < count($this->value)) {
479  $img .= $this->renderInputField(
480  'image', $id.'_down_'.$key,
481  array(
482  'src' => 'geticon.php?context=actions&amp;icon=view-sort-ascending&amp;size=16',
483  'title' => _('Sort down'),
484  'alt' => _('Sort down'),
485  'class' => 'center'
486  )
487  );
488  } else {
489  $img .= '<img src="images/empty.png" alt="" style="width:16px;"/>';
490  }
491  }
492  if ($this->edit_enabled) {
493  $nbicons++;
494  $img .= $this->renderInputField(
495  'image', $id.'_edit_'.$key,
496  array(
497  'src' => 'geticon.php?context=actions&amp;icon=document-edit&amp;size=16',
498  'title' => _('Edit'),
499  'alt' => _('Edit'),
500  'class' => 'center'
501  )
502  );
503  }
504  $img .= $this->renderInputField(
505  'image', $id.'_del_'.$key,
506  array(
507  'src' => 'geticon.php?context=actions&amp;icon=edit-delete&amp;size=16',
508  'title' => _('Delete'),
509  'alt' => _('Delete'),
510  'class' => 'center'
511  )
512  );
513 
514  return array ($img, $nbicons);
515  }
516 
517  protected function getAttributeArrayValue($key, $value)
518  {
519  $this->attribute->setValue($value);
520  return $this->attribute->getArrayValue();
521  }
522 
523  protected function reIndexValues ()
524  {
525  $this->value = array_values($this->value);
526  }
527 
528  function loadPostValue ()
529  {
530  $this->editingValue = FALSE;
531  if ($this->isVisible()) {
532  $this->postValue = $this->value;
533  $id = $this->getHtmlId();
534  foreach (array_keys($_POST) as $name) {
535  if ($this->handlePostValueActions($id, $name)) {
536  break;
537  }
538  }
539  $this->handleAddAndEditValue();
540  }
541  }
542 
543  protected function handlePostValueActions($id, $postValue)
544  {
545  if ($this->order) {
546  if (preg_match('/^'.$id.'_up_/', $postValue)) {
547  $key = preg_replace('/^'.$id.'_up_/', '', $postValue);
548  $key = preg_replace('/_[xy]$/', '', $key);
549 
550  $tmp = $this->postValue[$key];
551  $this->postValue[$key] = $this->postValue[$key - 1];
552  $this->postValue[$key - 1] = $tmp;
553  return TRUE;
554  }
555  if (preg_match('/^'.$id.'_down_/', $postValue)) {
556  $key = preg_replace('/^'.$id.'_down_/', '', $postValue);
557  $key = preg_replace('/_[xy]$/', '', $key);
558 
559  $tmp = $this->postValue[$key];
560  $this->postValue[$key] = $this->postValue[$key + 1];
561  $this->postValue[$key + 1] = $tmp;
562  return TRUE;
563  }
564  }
565  if ($this->edit_enabled) {
566  if (preg_match('/^'.$id.'_edit_/', $postValue)) {
567  $key = preg_replace('/^'.$id.'_edit_/', '', $postValue);
568  $key = preg_replace('/_[xy]$/', '', $key);
569  $this->handleEdit($key);
570  return TRUE;
571  }
572  }
573  if (preg_match('/^'.$id.'_del_/', $postValue)) {
574  $key = preg_replace('/^'.$id.'_del_/', '', $postValue);
575  $key = preg_replace('/_[xy]$/', '', $key);
576  $this->delPostValue($key);
577  return TRUE;
578  }
579  return FALSE;
580  }
581 
582  protected function handleAddAndEditValue()
583  {
584  $id = $this->getHtmlId();
585  if ($this->attribute === FALSE) {
586  return;
587  }
588  if (isset($_POST["add$id"])) {
589  $this->attribute->loadPostValue();
590  $this->attribute->applyPostValue();
591  if ($error = $this->attribute->check()) {
592  msg_dialog::display(sprintf(_('Invalid value for %s'), $this->getLabel()), $error);
593  } else {
594  $this->addPostValue($this->attribute->getValue());
595  }
596  } elseif ($this->editingValue === FALSE) {
597  $this->attribute->loadPostValue();
598  $this->attribute->applyPostValue();
599  $this->editingValue = $this->attribute->getValue();
600  }
601  }
602 
603  protected function handleEdit($key)
604  {
605  $this->editingValue = $this->value[$key];
606  $this->delPostValue($key);
607  $this->plugin->focusedField = $this->getHtmlId();
608  }
609 
610  function applyPostValue ()
611  {
612  parent::applyPostValue();
613  if ($this->order) {
614  $this->reIndexValues();
615  }
616  }
617 
618  public function htmlIds()
619  {
620  $id = $this->getHtmlId();
621  $ids = array('add'.$id);
622  if ($this->attribute !== FALSE) {
623  $ids = array_merge($ids, $this->attribute->htmlIds());
624  }
625  $nb_values = count($this->value);
626  for ($i = 0; $i < $nb_values; ++$i) {
627  if ($this->order) {
628  if ($i > 0) {
629  $ids[] = $id.'_up_'.$i;
630  }
631  if (($i + 1) < $nb_values) {
632  $ids[] = $id.'_down_'.$i;
633  }
634  }
635  $ids[] = $id.'_del_'.$i;
636  }
637  return $ids;
638  }
639 
640  function renderButtons ()
641  {
642  $id = $this->getHtmlId();
643  $buttons = $this->renderInputField('submit', 'add'.$id, array('value' => '{msgPool type=addButton}'));
644  return $buttons;
645  }
646 }
647 
649 {
650  protected $objectClass;
651  protected $objectClasses;
652 
653  function __construct ($label, $description, $ldapName, $objectClass, $attributes, $order = FALSE, $values = array(), $edit_enabled = FALSE, $acl = "")
654  {
655  $attributes_keys = array();
656  foreach ($attributes as $attribute) {
657  $attributes_keys[$attribute->getLdapName()] = $attribute;
658  $attributes_keys[$attribute->getLdapName()]->htmlid_prefix = $ldapName.'_';
659  }
660  $composite = new CompositeAttribute(
661  $description, $ldapName,
662  $attributes_keys,
663  FALSE, FALSE,
664  $acl, $label
665  );
666  parent::__construct($composite, $order, $values, $edit_enabled);
667  if (is_array($objectClass)) {
668  $this->objectClass = $objectClass[0];
669  $this->objectClasses = $objectClass;
670  } else {
671  $this->objectClass = $objectClass;
672  $this->objectClasses = array($objectClass);
673  }
674  }
675 
676  protected function loadAttrValue ($attrs)
677  {
678  global $config;
679  /* Should we take dn from attrs or plugin? */
680  if (isset($attrs['dn'])) {
681  $ldap = $config->get_ldap_link();
682  $ldap->cd($attrs['dn']);
683  $ldap->search('objectClass='.$this->objectClass, array('*'), 'one');
684  $this->value = array();
685  while ($subattrs = $ldap->fetch()) {
686  $this->attribute->resetToDefault();
687  foreach ($this->attribute->attributes as &$attribute) {
688  $attribute->loadAttrValue($subattrs);
689  }
690  unset($attribute);
691  $this->value[] = $this->attribute->getValue();
692  }
693  } else {
694  $this->resetToDefault();
695  }
696  }
697 
698  /* Not saving anything into base node */
699  function fillLdapValue (&$attrs)
700  {
701  }
702 
703  /* Special LDAP treatment that this attribute does after plugin ldap save */
704  function postLdapSave ($ldap)
705  {
706  /* First delete all old nodes */
707  $ldap->cd($this->plugin->dn);
708  $ldap->search('objectClass='.$this->objectClass, array('dn'), 'one');
709  $delete = array();
710  while ($attrs = $ldap->fetch()) {
711  $delete[] = $attrs['dn'];
712  }
713  foreach ($delete as $dn) {
714  $ldap->rmdir($dn);
715  }
716  /* Then add our values */
717  foreach ($this->value as $val) {
718  $attrs = array('objectClass' => $this->objectClasses);
719  $this->attribute->setValue($val);
720  foreach ($this->attribute->attributes as &$attribute) {
721  $attribute->fillLdapValue($attrs);
722  }
723  unset($attribute);
724  $dn = $this->compute_attribute_dn();
725  $ldap->cd($dn);
726  foreach (array_keys($attrs) as $index) {
727  if (is_array($attrs[$index]) && (count($attrs[$index]) == 0)) {
728  unset($attrs[$index]);
729  }
730  }
731  $ldap->add($attrs);
732  if (!$ldap->success()) {
733  msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, LDAP_ADD, get_class()), LDAP_ERROR);
734  }
735  }
736  }
737 
738  function compute_attribute_dn ()
739  {
740  /* Later we might want to be able to choose which attribute to use in the dn */
741  reset($this->attribute->attributes);
742  $attribute = key($this->attribute->attributes);
743  return $attribute.'='.$this->attribute->attributes[$attribute]->computeLdapValue().','.$this->plugin->dn;
744  }
745 }
renderAcl($display)
Add ACL information around display.
Exception class which can be thrown if an attribute is set to a value with a non-compatible type...
This class allow to handle easily any kind of LDAP attribute.
setParent(&$plugin)
Set the parent plugin for this attribute.
static ldaperror($error, $dn= '', $type=0, $plugin= '')
Display LDAP error.
This class allow to handle easily a composite attribute.
& get_smarty()
Get global smarty object.
Definition: functions.inc:953
__construct($attribute, $values=array(), $valueUnicity=TRUE)
The constructor of SetAttribute.
__construct($attribute, $order=TRUE, $values=array(), $edit_enabled=FALSE)
The constructor of OrderedArrayAttribute.
This class allow to handle easily a multi-valuated attribute.
This class contains all the functions to manage select box.
resetToDefault()
Reset this attribute to its default value.
static display($s_title, $s_message, $i_type=INFO_DIALOG)
Display a message dialog.