ILIAS  Release_5_0_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.ilDataCollectionDataSet.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
4 require_once("./Services/DataSet/classes/class.ilDataSet.php");
5 require_once('class.ilDataCollectionCache.php');
6 require_once('class.ilObjDataCollection.php');
7 
15 
19  protected $db;
23  protected $data = array();
29  protected $record_field_ids_2_storage = array();
49  protected $caches = array(
50  'dcl' => array(),
51  'il_dcl_table' => array(),
52  'il_dcl_field' => array(),
53  'il_dcl_field_prop' => array(),
54  'il_dcl_record' => array(),
55  'il_dcl_record_field' => array(),
56  'il_dcl_stloc1_value' => array(),
57  'il_dcl_stloc2_value' => array(),
58  'il_dcl_stloc3_value' => array(),
59  'il_dcl_view' => array(),
60  'il_dcl_viewdefinition' => array(),
61  );
65  protected $import_dc_object;
69  protected $count_imported_tables = 0;
75  protected $import_record_field_cache = array();
79  protected $user;
83  protected $import_temp_refs = array();
87  protected $import_temp_refs_props = array();
91  protected $import_temp_new_mob_ids = array();
92 
93 
94  public function __construct() {
95  global $ilDB, $ilUser;
97  $this->db = $ilDB;
98  $this->user = $ilUser;
99  }
100 
101 
105  public function getSupportedVersions() {
106  return array( '4.5.0' );
107  }
108 
109 
118  public function getCache($a_entity) {
119  if (!in_array($a_entity, array_keys($this->caches))) {
120  throw new ilException("Entity '$a_entity' does not exist in Cache");
121  }
122 
123  return $this->caches[$a_entity];
124  }
125 
126 
133  public function getXmlNamespace($a_entity, $a_schema_version) {
134  return 'http://www.ilias.de/xml/Modules/DataCollection/' . $a_entity;
135  }
136 
137 
145  public function importRecord($a_entity, $a_types, $a_rec, $a_mapping, $a_schema_version) {
146  switch ($a_entity) {
147  case 'dcl':
148  if($new_id = $a_mapping->getMapping('Services/Container','objs',$a_rec['id']))
149  {
150  $newObj = ilObjectFactory::getInstanceByObjId($new_id,false);
151  }
152  else
153  {
154  $newObj = new ilObjDataCollection();
155  $newObj->create(true);
156  }
157  // Calling new_obj->create() will create the main table for us
158  $newObj->setTitle($a_rec['title']);
159  $newObj->setDescription($a_rec['description']);
160  $newObj->setApproval($a_rec['approval']);
161  $newObj->setPublicNotes($a_rec['public_notes']);
162  $newObj->setNotification($a_rec['notification']);
163  $newObj->setPublicNotes($a_rec['public_notes']);
164  $newObj->setOnline(false);
165  $newObj->setRating($a_rec['rating']);
166 
167  $newObj->update();
168  $this->import_dc_object = $newObj;
169  $a_mapping->addMapping('Modules/DataCollection', 'dcl', $a_rec['id'], $newObj->getId());
170  break;
171  case 'il_dcl_table':
172  // If maintable, update. Other tables must be created as well
173  $table = ($this->count_imported_tables
174  > 0) ? new ilDataCollectionTable() : ilDataCollectionCache::getTableCache($this->import_dc_object->getMainTableId());
175  $table->setTitle($a_rec['title']);
176  $table->setObjId($this->import_dc_object->getId());
177  $table->setDescription($a_rec['description']);
178  $table->setAddPerm($a_rec['add_perm']);
179  $table->setEditPerm($a_rec['edit_perm']);
180  $table->setDeletePerm($a_rec['delete_perm']);
181  $table->setEditByOwner($a_rec['edit_by_owner']);
182  $table->setLimited($a_rec['limited']);
183  $table->setLimitStart($a_rec['limit_start']);
184  $table->setLimitEnd($a_rec['limit_end']);
185  $table->setIsVisible($a_rec['is_visible']);
186  $table->setExportEnabled($a_rec['export_enabled']);
187  $table->setDefaultSortField($a_rec['default_sort_field_id']);
188  $table->setDefaultSortFieldOrder($a_rec['default_sort_field_order']);
189  $table->setPublicCommentsEnabled($a_rec['public_comments']);
190  $table->setViewOwnRecordsPerm($a_rec['view_own_records_perm']);
191  if ($this->count_imported_tables > 0) {
192  $table->doCreate(false); // false => Do not create views! They are imported later
193  } else {
194  $table->doUpdate();
195  $this->count_imported_tables ++;
196  // Delete views from maintable because we want to import them from the xml data
197  $set = $this->db->query('SELECT * FROM il_dcl_view WHERE table_id = ' . $this->db->quote($table->getId(), 'integer'));
198  $view_ids = array();
199  while ($row = $this->db->fetchObject($set)) {
200  $view_ids[] = $row->id;
201  }
202  if (count($view_ids)) {
203  $this->db->manipulate("DELETE FROM il_dcl_viewdefinition WHERE view_id IN (" . implode(',', $view_ids) . ")");
204  }
205  $this->db->manipulate("DELETE FROM il_dcl_view WHERE table_id = " . $this->db->quote($table->getId(), 'integer'));
206  }
207  $a_mapping->addMapping('Modules/DataCollection', 'il_dcl_table', $a_rec['id'], $table->getId());
208  break;
209  case 'il_dcl_field':
210  $new_table_id = $a_mapping->getMapping('Modules/DataCollection', 'il_dcl_table', $a_rec['table_id']);
211  if ($new_table_id) {
212  $field = new ilDataCollectionField();
213  $field->setTableId($new_table_id);
214  $field->setDatatypeId($a_rec['datatype_id']);
215  $field->setTitle($a_rec['title']);
216  $field->setDescription($a_rec['description']);
217  $field->setRequired($a_rec['required']);
218  $field->setUnique($a_rec['is_unique']);
219  $field->setLocked($a_rec['is_locked']);
220  $field->doCreate();
221  $a_mapping->addMapping('Modules/DataCollection', 'il_dcl_field', $a_rec['id'], $field->getId());
222  // Check if this field was used as default order by, if so, update to new id
223  $table = ilDataCollectionCache::getTableCache($new_table_id);
224  if ($table && $table->getDefaultSortField() == $a_rec['id']) {
225  $table->setDefaultSortField($field->getId());
226  $table->doUpdate();
227  }
228  }
229  break;
230  case 'il_dcl_record':
231  $new_table_id = $a_mapping->getMapping('Modules/DataCollection', 'il_dcl_table', $a_rec['table_id']);
232  if ($new_table_id) {
233  $record = new ilDataCollectionRecord();
234  $record->setTableId($new_table_id);
235  $datetime = new ilDateTime(time(), IL_CAL_UNIX);
236  $record->setCreateDate($datetime);
237  $record->setLastUpdate($datetime);
238  $record->setOwner($this->user->getId());
239  $record->setLastEditBy($this->user->getId());
240  $record->doCreate();
241  $a_mapping->addMapping('Modules/DataCollection', 'il_dcl_record', $a_rec['id'], $record->getId());
242  }
243  break;
244  case 'il_dcl_view':
245  $new_table_id = $a_mapping->getMapping('Modules/DataCollection', 'il_dcl_table', $a_rec['table_id']);
246  if ($new_table_id) {
247  if ($a_rec['type'] == 0 && $a_rec['formtype'] == 0) {
248  // RecordViewViewDefinition: Create a new RecordViewViewdefinition. Note that the associated Page object is NOT created.
249  // Creation of the Page object is handled by the import of Services/COPage
250  $definition = new ilDataCollectionRecordViewViewdefinition();
251  $definition->setTableId($new_table_id);
252  $definition->create(true); // DO not create DB entries for page object
253  // This mapping is needed for the import handled by Services/COPage
254  $a_mapping->addMapping('Services/COPage', 'pg', 'dclf:' . $a_rec['id'], 'dclf:' . $definition->getId());
255  $a_mapping->addMapping('Modules/DataCollection', 'il_dcl_view', $a_rec['id'], $definition->getId());
256  } else {
257  // Other definitions - grab next ID from il_dcl_view
258  $view_id = $this->db->nextId("il_dcl_view");
259  $sql = "INSERT INTO il_dcl_view (id, table_id, type, formtype) VALUES (" . $this->db->quote($view_id, "integer") . ", "
260  . $this->db->quote($new_table_id, "integer") . ", " . $this->db->quote($a_rec['type'], "integer") . ", "
261  . $this->db->quote($a_rec['formtype'], "integer") . ")";
262  $this->db->manipulate($sql);
263  $a_mapping->addMapping('Modules/DataCollection', 'il_dcl_view', $a_rec['id'], $view_id);
264  }
265  }
266  break;
267  case 'il_dcl_viewdefinition':
268  $new_view_id = $a_mapping->getMapping('Modules/DataCollection', 'il_dcl_view', $a_rec['view_id']);
269  $new_field_id = $a_mapping->getMapping('Modules/DataCollection', 'il_dcl_field', $a_rec['field']);
270  $field = ($new_field_id) ? $new_field_id : $a_rec['field'];
271  if ($new_view_id) {
272  $sql =
273  'INSERT INTO il_dcl_viewdefinition (view_id, field, field_order, is_set) VALUES (' . $this->db->quote($new_view_id, 'integer')
274  . ', ' . $this->db->quote($field, 'text') . ', ' . $this->db->quote($a_rec['field_order'], 'integer') . ', '
275  . $this->db->quote($a_rec['is_set'], 'integer') . ')';
276  $this->db->manipulate($sql);
277  }
278  break;
279  case 'il_dcl_field_prop':
280  $new_field_id = $a_mapping->getMapping('Modules/DataCollection', 'il_dcl_field', $a_rec['field_id']);
281  if ($new_field_id) {
282  $prop = new ilDataCollectionFieldProp();
283  $prop->setFieldId($new_field_id);
284  $prop->setDatatypePropertyId($a_rec['datatype_prop_id']);
285  // For field references, we need to get the new field id of the referenced field
286  // If the field_id does not yet exist (e.g. referenced table not yet created), store temp info and fix before finishing import
287  $value = $a_rec['value'];
289  $fix_refs = false;
290  if (in_array($prop->getDatatypePropertyId(), $refs)) {
291  $new_field_id = $a_mapping->getMapping('Modules/DataCollection', 'il_dcl_field', $a_rec['value']);
292  if ($new_field_id === false) {
293  $value = NULL;
294  $fix_refs = true;
295  }
296  }
297  $prop->setValue($value);
298  $prop->doCreate();
299  $a_mapping->addMapping('Modules/DataCollection', 'il_dcl_field_prop', $a_rec['id'], $prop->getId());
300  if ($fix_refs) {
301  $this->import_temp_refs_props[$prop->getId()] = $a_rec['value'];
302  }
303  }
304  break;
305  case 'il_dcl_record_field':
306  $record_id = $a_mapping->getMapping('Modules/DataCollection', 'il_dcl_record', $a_rec['record_id']);
307  $field_id = $a_mapping->getMapping('Modules/DataCollection', 'il_dcl_field', $a_rec['field_id']);
308  if ($record_id && $field_id) {
309  $record = ilDataCollectionCache::getRecordCache($record_id);
310  $field = ilDataCollectionCache::getFieldCache($field_id);
311  $record_field = new ilDataCollectionRecordField($record, $field);
312  $a_mapping->addMapping('Modules/DataCollection', 'il_dcl_record_field', $a_rec['id'], $record_field->getId());
313  $this->import_record_field_cache[$record_field->getId()] = $record_field;
314  }
315  break;
316  case 'il_dcl_stloc1_value':
317  case 'il_dcl_stloc2_value':
318  case 'il_dcl_stloc3_value':
319  $new_record_field_id = $a_mapping->getMapping('Modules/DataCollection', 'il_dcl_record_field', $a_rec['record_field_id']);
320  if ($new_record_field_id) {
322  $record_field = $this->import_record_field_cache[$new_record_field_id];
323  if (is_object($record_field)) {
324  // Need to rewrite internal references and lookup new objects if MOB or File
325  // For some fieldtypes it's better to reset the value, e.g. ILIAS_REF
326  switch ($record_field->getField()->getDatatypeId()) {
328  // Check if we got a mapping from old object
329  $new_mob_id = $a_mapping->getMapping('Services/MediaObjects', 'mob', $a_rec['value']);
330  $value = ($new_mob_id) ? (int)$new_mob_id : NULL;
331  $this->import_temp_new_mob_ids[] = $new_mob_id;
332  break;
334  $new_file_id = $a_mapping->getMapping('Modules/File', 'file', $a_rec['value']);
335  $value = ($new_file_id) ? (int)$new_file_id : NULL;
336  break;
338  case ilDataCollectioNDatatype::INPUTFORMAT_REFERENCELIST:
339  // If we are referencing to a record from a table that is not yet created, return value is always false because the record does exist neither
340  // Solution: Temporary store all references and fix them before finishing the import.
341  $new_record_id = $a_mapping->getMapping('Modules/DataCollection', 'il_dcl_record', $a_rec['value']);
342  if ($new_record_id === false) {
343  $this->import_temp_refs[$new_record_field_id] = $a_rec['value'];
344  }
345  $value = ($new_record_id) ? (int)$new_record_id : NULL;
346  break;
348  $value = NULL;
349  break;
350  default:
351  $value = $a_rec['value'];
352  if ($a_entity == 'il_dcl_stloc3_value' && (is_null($value) || empty($value))) {
353  $value = '0000-00-00 00:00:00';
354  }
355  }
356  $record_field->setValue($value, true);
357  $record_field->doUpdate();
358  }
359  }
360  break;
361  }
362  }
363 
364 
370  public function beforeFinishImport(ilImportMapping $a_mapping) {
371  foreach ($this->import_temp_new_mob_ids as $new_mob_id) {
372  ilObjMediaObject::_saveUsage($new_mob_id, "dcl:html", $this->import_dc_object->getId());
373  }
374  foreach ($this->import_temp_refs as $record_field_id => $old_record_id) {
375  $new_record_id = $a_mapping->getMapping('Modules/DataCollection', 'il_dcl_record', $old_record_id);
376  $value = ($new_record_id) ? (int)$new_record_id : NULL;
378  $record_field = $this->import_record_field_cache[$record_field_id];
379  $record_field->setValue($value, true);
380  $record_field->doUpdate();
381  }
382  foreach ($this->import_temp_refs_props as $field_prop_id => $old_field_id) {
383  $new_field_id = $a_mapping->getMapping('Modules/DataCollection', 'il_dcl_field', $old_field_id);
384  $value = ($new_field_id) ? (int)$new_field_id : NULL;
385  $field_prop = new ilDataCollectionFieldProp($field_prop_id);
386  $field_prop->setValue($value);
387  $field_prop->doUpdate();
388  }
389  }
390 
391 
400  protected function getTypes($a_entity, $a_version) {
401  switch ($a_entity) {
402  case 'dcl':
403  return array(
404  "id" => "integer",
405  "title" => "text",
406  "description" => "text",
407  'main_table_id' => 'integer',
408  'is_online' => 'integer',
409  'rating' => 'integer',
410  'public_notes' => 'integer',
411  'approval' => 'integer',
412  'notification' => 'integer',
413  );
414  case 'il_dcl_table':
415  return array(
416  'id' => 'integer',
417  'obj_id' => 'integer',
418  'title' => 'text',
419  'add_perm' => 'integer',
420  'edit_perm' => 'integer',
421  'delete_perm' => 'integer',
422  'edit_by_owner' => 'integer',
423  'limited' => 'integer',
424  'limit_start' => 'text',
425  'limit_end' => 'text',
426  'is_visible' => 'integer',
427  'export_enabled' => 'integer',
428  'default_sort_field_id' => 'text',
429  'default_sort_field_order' => 'text',
430  'description' => 'text',
431  'public_comments' => 'integer',
432  'view_own_records_perm' => 'integer',
433  );
434  case 'il_dcl_field':
435  return array(
436  'id' => 'integer',
437  'table_id' => 'integer',
438  'title' => 'text',
439  'description' => 'text',
440  'datatype_id' => 'integer',
441  'required' => 'integer',
442  'is_unique' => 'integer',
443  'is_locked' => 'integer',
444  );
445  case 'il_dcl_field_prop':
446  return array(
447  'id' => 'integer',
448  'field_id' => 'integer',
449  'datatype_prop_id' => 'integer',
450  'value' => 'integer',
451  );
452  case 'il_dcl_record':
453  return array(
454  'id' => 'integer',
455  'table_id' => 'integer',
456  );
457  case 'il_dcl_record_field':
458  return array(
459  'id' => 'integer',
460  'record_id' => 'integer',
461  'field_id' => 'integer',
462  );
463  case 'il_dcl_stloc1_value':
464  return array(
465  'id' => 'integer',
466  'record_field_id' => 'integer',
467  'value' => 'text',
468  );
469  case 'il_dcl_stloc2_value':
470  return array(
471  'id' => 'integer',
472  'record_field_id' => 'integer',
473  'value' => 'text',
474  );
475  case 'il_dcl_stloc3_value':
476  return array(
477  'id' => 'integer',
478  'record_field_id' => 'integer',
479  'value' => 'text',
480  );
481  case 'il_dcl_view':
482  return array(
483  'id' => 'integer',
484  'table_id' => 'integer',
485  'type' => 'integer',
486  'formtype' => 'integer',
487  );
488  case 'il_dcl_viewdefinition':
489  return array(
490  'view_id' => 'integer',
491  'field' => 'string',
492  'field_order' => 'integer',
493  'is_set' => 'integer',
494  );
495  default:
496  return array();
497  }
498  }
499 
500 
511  protected function getDependencies($a_entity, $a_version, $a_rec, $a_ids) {
512  if (!$a_rec && !$a_ids) {
513  return false;
514  }
515  switch ($a_entity) {
516  case 'dcl':
517  $set = $this->db->query('SELECT * FROM il_dcl_table WHERE obj_id = ' . $this->db->quote($a_rec['id'], 'integer') . ' ORDER BY id');
518  $ids = $this->buildCache('il_dcl_table', $set);
519 
520  return array(
521  'il_dcl_table' => array( 'ids' => $ids ),
522  );
523  break;
524  case 'il_dcl_table':
525  $set = $this->db->query('SELECT * FROM il_dcl_record WHERE table_id = ' . $this->db->quote($a_rec['id'], 'integer'));
526  $ids_records = $this->buildCache('il_dcl_record', $set);
527  $set = $this->db->query('SELECT * FROM il_dcl_field WHERE table_id = ' . $this->db->quote($a_rec['id'], 'integer'));
528  $ids_fields = $this->buildCache('il_dcl_field', $set);
529  $set = $this->db->query('SELECT * FROM il_dcl_view WHERE table_id = ' . $this->db->quote($a_rec['id'], 'integer'));
530  $ids_views = $this->buildCache('il_dcl_view', $set);
531 
532  return array(
533  'il_dcl_field' => array( 'ids' => $ids_fields ),
534  'il_dcl_record' => array( 'ids' => $ids_records ),
535  'il_dcl_view' => array( 'ids' => $ids_views ),
536  );
537  case 'il_dcl_field':
538  $set = $this->db->query('SELECT * FROM il_dcl_field_prop WHERE field_id = ' . $this->db->quote($a_rec['id'], 'integer'));
539  $ids = $this->buildCache('il_dcl_field_prop', $set);
540 
541  return array(
542  'il_dcl_field_prop' => array( 'ids' => $ids ),
543  );
544  case 'il_dcl_record':
545  $sql = 'SELECT rf.*, d.storage_location FROM il_dcl_record_field AS rf' . ' INNER JOIN il_dcl_field AS f ON (f.id = rf.field_id)'
546  . ' INNER JOIN il_dcl_datatype AS d ON (f.datatype_id = d.id) ' . ' WHERE rf.record_id = '
547  . $this->db->quote($a_rec['id'], 'integer');
548  $set = $this->db->query($sql);
549  $ids = $this->buildCache('il_dcl_record_field', $set);
550 
551  $set = $this->db->query($sql);
552  while ($rec = $this->db->fetchObject($set)) {
553  $this->record_field_ids_2_storage[$rec->id] = $rec->storage_location;
554  }
555  // Also build a cache of all values, no matter in which table they are (il_dcl_stloc(1|2|3)_value)
556  $sql =
557  'SELECT rf.id AS record_field_id, st1.value AS value1, st2.value AS value2, st3.value AS value3 FROM il_dcl_record_field AS rf '
558  . 'LEFT JOIN il_dcl_stloc1_value AS st1 ON (st1.record_field_id = rf.id) '
559  . 'LEFT JOIN il_dcl_stloc2_value AS st2 ON (st2.record_field_id = rf.id) '
560  . 'LEFT JOIN il_dcl_stloc3_value AS st3 ON (st3.record_field_id = rf.id) ' . 'WHERE rf.record_id = '
561  . $this->db->quote($a_rec['id'], 'integer');
562  $set = $this->db->query($sql);
563 
564  while ($rec = $this->db->fetchObject($set)) {
565  $stloc = $this->record_field_ids_2_storage[$rec->record_field_id];
566  $value = "value{$stloc}";
567  // Save reocrd field id. Internal ID is not used currently
568  $this->caches["il_dcl_stloc{$stloc}_value"][$rec->record_field_id] = array(
569  'record_field_id' => $rec->record_field_id,
570  'value' => $rec->{$value}
571  );
572  }
573 
574  return array(
575  'il_dcl_record_field' => array( 'ids' => $ids )
576  );
577  case 'il_dcl_view':
578  $set = $this->db->query('SELECT * FROM il_dcl_viewdefinition WHERE view_id = ' . $this->db->quote($a_rec['id'], 'integer'));
579  $ids = $this->buildCache('il_dcl_viewdefinition', $set);
580 
581  return array(
582  'il_dcl_viewdefinition' => array( 'ids' => $ids )
583  );
584  case 'il_dcl_record_field':
585  $record_field_id = $a_rec['id'];
586  $storage_loc = $this->record_field_ids_2_storage[$record_field_id];
587 
588  return array(
589  "il_dcl_stloc{$storage_loc}_value" => array( 'ids' => array( $record_field_id ) )
590  );
591  }
592 
593  return false;
594  }
595 
596 
604  public function readData($a_entity, $a_version, $a_ids) {
605  $this->data = array();
606  if (!is_array($a_ids)) {
607  $a_ids = array( $a_ids );
608  }
609  $this->_readData($a_entity, $a_ids);
610  }
611 
612 
619  protected function _readData($a_entity, $a_ids) {
620  switch ($a_entity) {
621  case 'dcl':
622  foreach ($a_ids as $dcl_id) {
623  if (ilObject::_lookupType($dcl_id) == 'dcl') {
624  $obj = new ilObjDataCollection($dcl_id, false);
625  $data = array(
626  'id' => $dcl_id,
627  'title' => $obj->getTitle(),
628  'description' => $obj->getDescription(),
629  'main_table_id' => $obj->getMainTableId(),
630  'is_online' => $obj->getOnline(),
631  'rating' => $obj->getRating(),
632  'public_notes' => $obj->getPublicNotes(),
633  'approval' => $obj->getApproval(),
634  'notification' => $obj->getNotification(),
635  );
636  $this->caches['dcl'][$dcl_id] = $data;
637  $this->data[] = $data;
638  }
639  }
640  break;
641  default:
642  $data = $this->getCache($a_entity);
643  foreach ($a_ids as $id) {
644  $this->data[] = $data[$id];
645  }
646  }
647  }
648 
649 
659  protected function buildCache($a_entity, $set) {
660  $fields = array_keys($this->getTypes($a_entity, ''));
661  $ids = array();
662  while ($rec = $this->db->fetchObject($set)) {
663  $data = array();
664  foreach ($fields as $field) {
665  $data[$field] = $rec->{$field};
666  }
667  // il_dcl_viewdefinition is the only table that has no internal id, so we build primary from view_id AND field columns
668  $id = ($a_entity == 'il_dcl_viewdefinition') ? $rec->view_id . '_' . $rec->field : $rec->id;
669  $this->caches[$a_entity][$id] = $data;
670  $ids[] = $id;
671  }
672 
673  return $ids;
674  }
675 }