class_csvimport.inc 10.6 KB
Newer Older
1 2 3
<?php
/*
  This code is part of FusionDirectory (http://www.fusiondirectory.org/)
4
  Copyright (C) 2015-2016 FusionDirectory
5 6 7 8 9 10 11 12 13 14 15 16 17

  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
Benoit Mortier's avatar
Benoit Mortier committed
18
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110 - 1301, USA.
19 20
*/

21
class csvimport extends simplePlugin
22
{
23
  protected $template_object;
24
  protected $cachedChoices;
Benoit Mortier's avatar
Benoit Mortier committed
25 26 27 28

  static function plInfo()
  {
    return array(
29 30 31 32 33
      'plShortName'   => _('CSV import'),
      'plDescription' => _('Import of csv data into the ldap tree'),
      'plSelfModify'  => FALSE,
      'plObjectType'  => array('ldapmanager'),
      'plPriority'    => 3,
Benoit Mortier's avatar
Benoit Mortier committed
34

35
      'plProvidedAcls' => parent::generatePlProvidedAcls(static::getAttributesInfo())
Benoit Mortier's avatar
Benoit Mortier committed
36 37 38
    );
  }

39
  static function getAttributesInfo ()
Benoit Mortier's avatar
Benoit Mortier committed
40
  {
41 42 43 44 45 46
    return array(
      'import' => array(
        'name'  => _('Import CSV'),
        'attrs' => array(
          new SelectAttribute (
            _('Object type'), _('Type of objects you wish to import'),
47 48 49
            'type', TRUE,
            array(), '', NULL,
            'import_file'
50 51 52
          ),
          new SelectAttribute (
            _('Template'), _('Select a template to apply to imported entries'),
53 54 55
            'template_dn', TRUE,
            array(), '', NULL,
            'import_file'
56 57 58
          ),
          new FileAttribute (
            _('CSV file'), _('Import a CSV file into your LDAP'),
59
            'import_file', FALSE
60 61 62 63
          ),
          new SelectAttribute (
            _('Separator'), _('Character used as separator in the CSV file'),
            'separator', TRUE,
64 65
            array(',', ';'), '', NULL,
            'import_file'
66
          ),
67 68 69
          new HiddenAttribute (
            'valueSeparator', FALSE, '|'
          ),
70 71 72
          new SetAttribute(
            new StringAttribute(
              _('Fixed values'), _('Some fixed values that you might wanna use in the filling of the template.'),
73 74 75
              'fixed_values', FALSE,
              '',
              'import_file'
76 77 78 79 80
            )
          ),
          new ButtonAttribute (
            '', '',
            'import_submit',
81 82 83
            _('Import'),
            NULL, '',
            'import_file'
84 85 86 87 88 89 90 91 92 93
          )
        )
      ),
      'fields' => array(
        'name'  => _('Template filling'),
        'attrs' => array(
          new CompositeAttribute (
            _('Select fields associations'),
            'fields',
            array(),
94 95
            '', '',
            'import_file',
96 97 98 99 100
            ''
          ),
          new ButtonAttribute (
            '', '',
            'import_submit_fields',
101 102 103
            _('Import'),
            NULL, '',
            'import_file'
104 105 106 107
          )
        )
      )
    );
Benoit Mortier's avatar
Benoit Mortier committed
108 109
  }

110
  function __construct ($dn = NULL, $object = NULL, $parent = NULL, $mainTab = FALSE)
Benoit Mortier's avatar
Benoit Mortier committed
111
  {
112
    parent::__construct($dn, $object, $parent, $mainTab);
113
    $this->attributesAccess['type']->setSubmitForm('typeChanged');
114
    $choices = template::getTemplatedTypes();
115 116 117 118
    $this->attributesAccess['type']->setChoices(array_keys($choices), array_values($choices));
    /* People usually import users, so set it as default */
    $this->attributesAccess['type']->setDefaultValue('USER');
    $this->attributesAccess['type']->resetToDefault();
119 120
    $this->attributesAccess['import_submit_fields']->setDisabled(TRUE);
  }
121

122 123 124 125 126
  function typeChanged()
  {
    $templates = objects::getTemplates($this->type);
    $this->attributesAccess['template_dn']->setChoices(array_keys($templates), array_values($templates));
  }
Benoit Mortier's avatar
Benoit Mortier committed
127

128 129
  function handle_import_submit()
  {
130
    $this->csv_data = $this->parse_csv($this->import_file);
131 132 133 134 135 136 137

    $messages = $this->check();
    if (!empty($messages)) {
      msg_dialog::displayChecks($messages);
      return;
    }

138
    $this->template_object = new template($this->type, $this->template_dn);
139 140

    /* Add nonrequired field filling feature */
141
    $fields = array();
142 143 144 145
    if (isset($this->csv_data[0])) {
      foreach ($this->csv_data[0] as $key => $field_value) {
        $fields[$key] = $key.' - '.$field_value;
      }
146 147
    }
    $fields = array_merge($fields, $this->fixed_values);
148
    $tpl_attributes = $this->template_object->serialize();
149
    $attributesObjects = array();
150
    $this->cachedChoices = array();
151
    reset($fields);
152 153
    foreach ($tpl_attributes as $class => $class_infos) {
      foreach ($class_infos['attrs'] as $attr => $attr_infos) {
154 155
        if ($attr_infos['visible']) {
          $attributesObjects[] = $this->build_attribute($fields, $class, $class_infos, $attr, $attr_infos);
156
        }
157
      }
158 159 160 161
    }
    $this->attributesAccess['fields']->setAttributes($attributesObjects);
    $this->attributesAccess['import_submit_fields']->setDisabled(FALSE);
  }
Benoit Mortier's avatar
Benoit Mortier committed
162

163 164 165 166 167 168 169 170 171
  private function build_attribute(&$fields, $class, $class_infos, $attr, $attr_infos)
  {
    $choices  = $fields;
    $value    = NULL;
    $ldapName = 'template_'.$class.':'.$attr;
    if (isset ($attr_infos['choices'])) {
      $choices = array_merge($choices, array_values($attr_infos['choices']));
      $this->cachedChoices[$ldapName] = array_keys($attr_infos['choices']);
      if (isset($attr_infos['value']) && !empty($attr_infos['value'])) {
172
        $value = count($fields) + array_search($attr_infos['value'], $this->cachedChoices[$ldapName]);
173 174 175 176 177 178 179 180 181 182 183 184 185
      }
    }
    if ($value === NULL) {
      $value = key($fields);
      next($fields);
    }
    if (isset($attr_infos['attributes'])) {
      $subattrs = array();
      foreach ($attr_infos['attributes'] as $subattr => $subattr_infos) {
        if ($subattr_infos['visible']) {
          $subattribute = $this->build_attribute($fields, $class, $class_infos, $subattr, $subattr_infos);
        } else {
          $this->cachedChoices['template_'.$class.':'.$subattr] = array($attr_infos['value']);
186
          $subattribute = new HiddenAttribute('template_'.$class.':'.$subattr, FALSE, count($fields));
187
        }
188
        $subattrs[] = $subattribute;
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
      }
      return new CompositeAttribute(
        '', $ldapName,
        $subattrs,
        FALSE, FALSE
      );
    }
    if ($value === NULL) {
      $value = key($fields);
      next($fields);
    }
    if (in_array('SetAttribute', $attr_infos['type'])) {
      return new SetAttribute(
        new SelectAttribute(
          $class_infos['name'].' > '.$attr_infos['label'], '',
          $ldapName, TRUE,
          array_keys($choices), $value,
206 207
          array_values($choices),
          'import_file'
208 209 210 211 212 213 214 215
        )
      );
    } else {
      return
        new SelectAttribute(
          $class_infos['name'].' > '.$attr_infos['label'], '',
          $ldapName, TRUE,
          array_keys($choices), $value,
216 217
          array_values($choices),
          'import_file'
218 219 220 221
        );
    }
  }

222 223 224
  function handle_import_submit_fields()
  {
    $success = 0;
225
    foreach ($this->csv_data as $rownumber => $row) {
226 227 228
      $values = array();
      foreach ($this->attributesAccess['fields']->attributes as $attribute) {
        preg_match('/^template_([^:]+):(.*)$/', $attribute->getLdapName(), $m);
229
        $values[$m[1]][$m[2]] = $this->compute_attribute_value($attribute, $row);
Benoit Mortier's avatar
Benoit Mortier committed
230
      }
231
      $this->template_object->reset();
232 233
      $this->template_object->deserialize($values);
      $tabObject = $this->template_object->apply();
234
      $msgs = $tabObject->save();
235
      if (count($msgs)) {
236
        $msg = '<ul><li>'.implode('</li><li>', $msgs).'</li></ul>';
237
        msg_dialog::display(sprintf(_('Import failed for line %d'), $rownumber + 1), $msg, ERROR_DIALOG);
238 239 240
        break;
      } else {
        $success++;
Benoit Mortier's avatar
Benoit Mortier committed
241 242
      }
    }
243 244
    if ($success > 0) {
      msg_dialog::display(_('Success'), sprintf(_('Successfully imported %d entries'), $success), INFO_DIALOG);
Benoit Mortier's avatar
Benoit Mortier committed
245
    }
246
  }
Benoit Mortier's avatar
Benoit Mortier committed
247

248 249 250 251 252 253 254 255 256 257 258 259 260 261
  private function compute_attribute_value($attribute, $row, $i = NULL)
  {
    if ($attribute instanceof CompositeAttribute) {
      $value = array();
      foreach ($attribute->attributes as $key => $subattribute) {
        $value[$key] = $this->compute_attribute_value($subattribute, $row);
      }
      return $value;
    }
    if ($i === NULL) {
      $i = $attribute->getValue();
    }
    if (is_array($i)) {
      $value = array();
262
      foreach ($i as $j) {
263 264
        $v = explode($this->valueSeparator, $this->compute_attribute_value($attribute, $row, $j));
        $value = array_merge($value, $v);
265 266 267 268 269 270 271 272 273 274 275 276 277
      }
      return $value;
    } else {
      if ($i < count($row)) {
        return $row[$i];
      } elseif ($i < (count($row) + count($this->fixed_values))) {
        return $this->fixed_values[$i - count($row)];
      } else {
        return $this->cachedChoices[$attribute->getLdapName()][$i - count($row) - count($this->fixed_values)];
      }
    }
  }

278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
  function parse_csv($str)
  {
    $lines  = preg_split("/\n/", $str);

    $anz    = 0;
    $rest   = 0;
    $data   = array();

    /* check column count */
    if (is_array($lines)) {
      foreach ($lines as $line) {
        /* continue if theres a comment */
        if (substr(trim($line), 0, 1) == "#") {
          continue;
        }
293

294
        $cells  = str_getcsv($line, $this->separator);
295

296 297
        if (count($cells) > $anz ) {
          $anz = count($cells);
Benoit Mortier's avatar
Benoit Mortier committed
298 299
        }
      }
300
    }
Benoit Mortier's avatar
Benoit Mortier committed
301

302 303
    /* At least one entry */
    if ($anz > 1) {
Benoit Mortier's avatar
Benoit Mortier committed
304

305 306 307 308 309 310
      /* Generate array with output info  */
      if (is_array($lines)) {
        foreach ($lines as $line) {
          $line_data = array();
          $rest = 0;
          $cnt  = 0;
Benoit Mortier's avatar
Benoit Mortier committed
311

312 313
          /* dont use comments or empty lines */
          if ((substr(trim($line), 0, 1) == "#") || (empty($line))) {
Benoit Mortier's avatar
Benoit Mortier committed
314 315 316
            continue;
          }

317 318
          /* get all elements  */
          $cells  = str_getcsv($line, $this->separator);
Benoit Mortier's avatar
Benoit Mortier committed
319

320 321 322
          /* attach all elements to data array */
          if (is_array($cells)) {
            foreach ($cells as $cell) {
323 324
              $cnt++;
              $line_data[] = trim($cell);
Benoit Mortier's avatar
Benoit Mortier committed
325 326
            }
          }
327

328 329 330 331 332
          /* cell count less than anz, attach some empty fields */
          if (($cnt < $anz) && ($cnt > 0)) {
            $rest = $anz - $cnt;
            for ($i = 0; $i < $rest; $i++) {
              $line_data[] = "";
Benoit Mortier's avatar
Benoit Mortier committed
333 334
            }
          }
335

336
          $data[] = $line_data;
Benoit Mortier's avatar
Benoit Mortier committed
337 338
        }
      }
339
    }
Benoit Mortier's avatar
Benoit Mortier committed
340

341 342
    return $data;
  }
Benoit Mortier's avatar
Benoit Mortier committed
343

344 345
  function save()
  {
346 347 348 349 350 351
    return array();
  }

  function remove($fulldelete = FALSE)
  {
    return array();
Benoit Mortier's avatar
Benoit Mortier committed
352
  }
353 354
}
?>