• Côme Chilliet's avatar
    :sparkles: feat(core) Big refactor of dialog system · 94eaa6ba
    Côme Chilliet authored
    This replaces save_object and execute methods by 3 methods:
    readPost - Reads POST data
    update - Update object state
    render - Render HTML UI
    
    The point is to avoid reading POST and rendering HTML when this is not
     needed (when doing stuff through the webservice for instance).
    
    It’s also more consisent across FD with all classes handling some kind
     of dialog implementing the new interface FusionDirectoryDialog which
     makes sure these 3 methods are implemented.
    
    issue #6072
    Unverified
    94eaa6ba
class_template.inc 10.97 KiB
<?php
/*
  This code is part of FusionDirectory (http://www.fusiondirectory.org/)
  Copyright (C) 2014-2020  FusionDirectory
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
/*!
 * \file class_template.inc
 * Source code for the class template
/*! \brief Class for applying a template */
class template implements FusionDirectoryDialog
  protected $type;
  protected $dn;
  protected $needed;
  protected $attrs;
  protected $tabObject;
  protected $attributes;
  protected $applied = FALSE;
  static protected $uiSpecialAttributes = ['dn','cn','uid','sn','givenName'];
  static function plInfo ()
    return [
      'plShortName'   => _('Template'),
      'plDescription' => _('Object template, used to create several objects with similar values'),
      /* Categories for templates are computed in config class */
      'plCategory'    => [],
      'plProvidedAcls' => [
        'template_cn' => _('Template name')
  static function getTemplatedTypes ()
    $result = [];
    $types  = objects::types();
    foreach ($types as $type) {
      if (in_array($type, departmentManagement::getDepartmentTypes())) {
        continue;
      $infos = objects::infos($type);
      if ($infos['templateActive']) {
        $result[$type] = $infos['name'];
    asort($result);
    return $result;
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
function __construct ($type, $dn) { $this->type = $type; $this->dn = $dn; list($this->attrs, $depends) = templateHandling::fetch($this->dn); $this->needed = templateHandling::neededAttrs($this->attrs, $depends); $this->needed[] = 'base'; $this->tabObject = objects::create($this->type); /* Used to know which tab is activated */ $tempTabObject = objects::open($this->dn, $this->type); $tempTabObject->setActiveTabs($this->tabObject); $this->attributes = []; foreach ($this->tabObject->by_object as $class => $tab) { if ($tab->isActive()) { $this->attributes[$class] = []; $attrs = array_unique(array_merge($tab->getRequiredAttributes(), $this->needed)); foreach (array_keys($tab->attributesAccess) as $attr) { if (!$tab->showInTemplate($attr, $this->attrs)) { continue; } if (in_array($attr, $attrs)) { $this->attributes[$class][] = $attr; } } if (empty($this->attributes[$class])) { /* Do not show empty sections */ unset($this->attributes[$class]); } } } } /*! \brief Used when you need to re-apply the same template with different values */ function reset () { list($this->attrs, $depends) = templateHandling::fetch($this->dn); // This is needed because it removes %askme% values from attrs $this->needed = templateHandling::neededAttrs($this->attrs, $depends); $this->needed[] = 'base'; $this->tabObject = objects::create($this->type); /* Used to know which tab is activated */ $tempTabObject = objects::open($this->dn, $this->type); $tempTabObject->setActiveTabs($this->tabObject); $this->applied = FALSE; } function getDn () { return $this->dn; } function getBase () { if (is_object($this->tabObject)) { return $this->tabObject->getBaseObject()->base; } else { $infos = objects::infos($this->type); return dn2base($this->dn, 'ou=templates,'.$infos['ou']); } } function getNeeded (): array { return $this->attributes; } function alterAttributes ($mandatories, $readonly, $hidden) { foreach ($mandatories as $class => $attrs) { foreach ($attrs as $attr) {
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
if (!in_array($attr, $this->attributes[$class])) { $this->attributes[$class][] = $attr; } $this->tabObject->by_object[$class]->attributesAccess[$attr]->setRequired(TRUE); } } foreach ($readonly as $class => $attrs) { foreach ($attrs as $attr) { if (!in_array($attr, $this->attributes[$class])) { $this->attributes[$class][] = $attr; } $this->tabObject->by_object[$class]->attributesAccess[$attr]->setDisabled(TRUE); } } foreach ($hidden as $class => $attrs) { foreach ($attrs as $attr) { if (!in_array($attr, $this->attributes[$class])) { $this->attributes[$class][] = $attr; } $this->tabObject->by_object[$class]->attributesAccess[$attr]->setDisabled(TRUE); $this->tabObject->by_object[$class]->attributesAccess[$attr]->setVisible(FALSE); } } } function getAttribute ($tab, $attr) { return $this->tabObject->by_object[$tab]->attributesAccess[$attr]; } function getAttributeTab ($attr) { foreach ($this->tabObject->by_object as $tab => $tabObject) { if (isset($tabObject->attributesAccess[$attr])) { return $tab; } } } /*! \brief Serialize this template for webservice */ function serialize () { $ret = []; foreach ($this->tabObject->by_object as $class => $plugin) { if (!isset($this->attributes[$class])) { continue; } $ret[$class] = ['name' => $this->tabObject->by_name[$class], 'attrs' => []]; foreach ($this->attributes[$class] as $attr) { $plugin->attributesAccess[$attr]->serializeAttribute($ret[$class]['attrs'], FALSE); } $ret[$class]['attrs_order'] = array_keys($ret[$class]['attrs']); } return $ret; } /*! \brief Deserialize values into the template */ function deserialize ($values) { foreach ($values as $class => $class_values) { $result = $this->tabObject->by_object[$class]->deserializeValues($class_values); if ($result !== TRUE) { return $result; } } return TRUE; }
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
/*! \brief Get all attribute values * * this produces a format that you can send to setValues later (after a reset for instance) */ function getValues () { $ret = []; foreach ($this->tabObject->by_object as $class => $plugin) { $ret[$class] = []; foreach ($plugin->attributesAccess as $name => $attr) { $ret[$class][$name] = $attr->getValue(); } } return $ret; } /*! \brief Set values */ function setValues ($values, $ldapFormat = FALSE) { foreach ($values as $class => $class_values) { foreach ($class_values as $name => $value) { if ($ldapFormat) { $value = $this->tabObject->by_object[$class]->attributesAccess[$name]->inputValue($value); } $this->tabObject->by_object[$class]->attributesAccess[$name]->setValue($value); } } } public function readPost () { foreach ($this->tabObject->by_object as $plugin) { $plugin->readPost(); } } public function update (): bool { foreach ($this->tabObject->by_object as $plugin) { $plugin->update(); } return TRUE; } public function dialogOpened () { return $this->tabObject->dialogOpened(); } public function render (): string { $smarty = get_smarty(); $sections = []; $posted = []; $smarty->assign('baseACL', 'rw'); foreach ($this->tabObject->by_object as $class => &$plugin) { if (!isset($this->attributes[$class])) { continue; } if ($plugin->is_modal_dialog()) { $this->tabObject->current = $class; return $plugin->render(); } $attributesRendered = []; foreach ($this->attributes[$class] as $attr) { if ($plugin->attributesAccess[$attr]->getAclInfo() !== FALSE) { // We assign ACLs so that attributes can use them in their template code
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
$smarty->assign($plugin->attributesAccess[$attr]->getAcl().'ACL', $plugin->aclGetPermissions($plugin->attributesAccess[$attr]->getAcl())); } $readable = $plugin->attrIsReadable($attr); $writable = $plugin->attrIsWriteable($attr); $plugin->attributesAccess[$attr]->renderAttribute($attributesRendered, FALSE, $readable, $writable); } $smarty->assign('section', $this->tabObject->by_name[$class]); $smarty->assign('sectionId', $class); $smarty->assign('sectionClasses', ' fullwidth'); $smarty->assign('attributes', $attributesRendered); $posted[] = $class.'_posted'; $sections[] = $smarty->fetch(get_template_path('simpleplugin_section.tpl')); } unset($plugin); $smarty->assign('sections', $sections); $smarty->assign('hiddenPostedInput', $posted); $smarty->assign('focusedField', ''); return $smarty->fetch(get_template_path('simpleplugin.tpl')); } /* Apply template and current values to an object and returns it for saving or edition * Cannot be called twice! If you need to, call reset between calls */ function apply ($targetdn = NULL) { if ($this->applied) { trigger_error('Templates can’t be applied twice without calling reset before'); return; } if ($targetdn !== NULL) { $this->tabObject = objects::open($targetdn, $this->type); unset($this->attrs['objectClass']['count']); foreach ($this->tabObject->by_object as $class => $plugin) { if ($plugin->isActive()) { $this->attrs['objectClass'] = $plugin->mergeObjectClasses($this->attrs['objectClass']); } } } foreach ($this->tabObject->by_object as $class => &$plugin) { if (!isset($this->attributes[$class])) { continue; } foreach ($this->attributes[$class] as $attr) { $plugin->attributesAccess[$attr]->fillLdapValue($this->attrs); } } unset($plugin); foreach ($this->tabObject->by_object as $class => &$plugin) { if (!isset($this->attributes[$class])) { continue; } foreach ($this->attributes[$class] as $attr) { $plugin->attributesAccess[$attr]->fillLdapValueHook($this->attrs); } } unset($plugin); foreach ($this->attrs as &$array) { if (!is_array($array)) { $array = [$array]; } if (!isset($array['count'])) { $array['count'] = count($array); } } unset($array);
351352353354355356357358359360361362363364
$ui = get_userinfo(); $specialAttrs = []; foreach (static::$uiSpecialAttributes as $attr) { $specialAttrs['caller'.strtoupper($attr)] = $ui->$attr; } $this->attrs = templateHandling::parseArray($this->attrs, $specialAttrs, $targetdn); $this->tabObject->adapt_from_template($this->attrs, array_merge([], ...array_values($this->attributes))); $this->applied = TRUE; return $this->tabObject; } }