commondbrelation.class.php 61.4 KB
Newer Older
remi's avatar
remi committed
1
<?php
2 3 4
/**
 * ---------------------------------------------------------------------
 * GLPI - Gestionnaire Libre de Parc Informatique
5
 * Copyright (C) 2015-2018 Teclib' and contributors.
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
 *
 * http://glpi-project.org
 *
 * based on GLPI - Gestionnaire Libre de Parc Informatique
 * Copyright (C) 2003-2014 by the INDEPNET Development Team.
 *
 * ---------------------------------------------------------------------
 *
 * LICENSE
 *
 * This file is part of GLPI.
 *
 * GLPI 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.
 *
 * GLPI 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 GLPI. If not, see <http://www.gnu.org/licenses/>.
 * ---------------------------------------------------------------------
remi's avatar
remi committed
31 32
 */

yllen's avatar
yllen committed
33
if (!defined('GLPI_ROOT')) {
Stefan Weil's avatar
Stefan Weil committed
34
   die("Sorry. You can't access this file directly");
remi's avatar
remi committed
35 36 37
}

/// Common DataBase Relation Table Manager Class
38
abstract class CommonDBRelation extends CommonDBConnexity {
remi's avatar
remi committed
39

yllen's avatar
CS  
yllen committed
40
   // Item 1 information
41
   // * definition
42 43
   static public $itemtype_1; // Type ref or field name (must start with itemtype)
   static public $items_id_1; // Field name
44
   // * entity inheritance
45
   static public $take_entity_1          = true;
46
   // * rights
47
   static public $checkItem_1_Rights     = self::HAVE_SAME_RIGHT_ON_ITEM;
48 49
   static public $mustBeAttached_1       = true;
   // * log
50
   static public $logs_for_item_1        = true;
51 52 53
   static public $log_history_1_add      = Log::HISTORY_ADD_RELATION;
   static public $log_history_1_update   = Log::HISTORY_UPDATE_RELATION;
   static public $log_history_1_delete   = Log::HISTORY_DEL_RELATION;
54 55
   static public $log_history_1_lock     = Log::HISTORY_LOCK_RELATION;
   static public $log_history_1_unlock   = Log::HISTORY_UNLOCK_RELATION;
56

yllen's avatar
CS  
yllen committed
57
   // Item 2 information
58
   // * definition
webmyster's avatar
webmyster committed
59 60
   static public $itemtype_2; // Type ref or field name (must start with itemtype)
   static public $items_id_2; // Field name
61
   // * entity inheritance
62
   static public $take_entity_2          = false;
63
   // * rights
webmyster's avatar
webmyster committed
64
   static public $checkItem_2_Rights     = self::HAVE_SAME_RIGHT_ON_ITEM;
65 66
   static public $mustBeAttached_2       = true;
   // * log
67
   static public $logs_for_item_2        = true;
68 69 70
   static public $log_history_2_add      = Log::HISTORY_ADD_RELATION;
   static public $log_history_2_update   = Log::HISTORY_UPDATE_RELATION;
   static public $log_history_2_delete   = Log::HISTORY_DEL_RELATION;
71 72
   static public $log_history_2_lock     = Log::HISTORY_LOCK_RELATION;
   static public $log_history_2_unlock   = Log::HISTORY_UNLOCK_RELATION;
webmyster's avatar
webmyster committed
73

74
   // Relation between items to check
webmyster's avatar
webmyster committed
75 76
   /// If both items must be checked for rights (default is only one)
   static public $checkAlwaysBothItems   = false;
77
   /// If both items must be in viewable each other entities
webmyster's avatar
webmyster committed
78 79
   static public $check_entity_coherency = true;

yllen's avatar
yllen committed
80
   public $no_form_page                  = true;
yllen's avatar
yllen committed
81

82

83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
   /**
    * Get request cirteria to search for an item
    *
    * @since 9.4
    *
    * @param string  $itemtype Item type
    * @param integer $items_id Item ID
    *
    * @return array|null
   **/
   static function getSQLCriteriaToSearchForItem($itemtype, $items_id) {
      global $DB;

      $conditions = [];
      $fields     = [
         static::getIndexName(),
         static::$items_id_1 . ' AS items_id_1',
Johan Cwiklinski's avatar
Johan Cwiklinski committed
100
         static::$items_id_2 . ' AS items_id_2'
101 102 103 104 105 106 107 108 109
      ];

      // Check item 1 type
      $where1 = [
         static::$items_id_1  => $items_id
      ];

      $request = false;
      if (preg_match('/^itemtype/', static::$itemtype_1)) {
cconard96's avatar
cconard96 committed
110
         $fields[] = static::$itemtype_1 . ' AS itemtype_1';
111 112 113
         $where1[static::$itemtype_1] = $itemtype;
         $request = true;
      } else {
cconard96's avatar
cconard96 committed
114
         $fields[] = new \QueryExpression("'" . static::$itemtype_1 . "' AS itemtype_1");
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
         if (($itemtype ==  static::$itemtype_1)
             || is_subclass_of($itemtype, static::$itemtype_1)) {
            $request = true;
         }
      }
      if ($request === true) {
         $conditions[] = $where1;
         $it = new \DBMysqlIterator($DB);
         $fields[]     = new \QueryExpression(
            'IF('.$it->analyseCrit($where1).', 1, 0) AS is_1'
         );
      } else {
         $fields[] = new \QueryExpression('0 AS is_1');
      }

      // Check item 2 type
      $where2 = [
         static::$items_id_2 => $items_id
      ];
      $request = false;
      if (preg_match('/^itemtype/', static::$itemtype_2)) {
cconard96's avatar
cconard96 committed
136
         $fields[] = static::$itemtype_2 . ' AS itemtype_2';
137 138 139
         $where2[static::$itemtype_2] = $itemtype;
         $request = true;
      } else {
cconard96's avatar
cconard96 committed
140
         $fields[] = new \QueryExpression("'" . static::$itemtype_2 . "' AS itemtype_2");
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
         if (($itemtype ==  static::$itemtype_2)
             || is_subclass_of($itemtype, static::$itemtype_2)) {
            $request = true;
         }
      }
      if ($request === true) {
         $conditions[] = $where2;
         $it = new \DBMysqlIterator($DB);
         $fields[]     = new \QueryExpression(
            'IF('.$it->analyseCrit($where2).', 1, 0) AS is_2'
         );

      } else {
         $fields[] = new \QueryExpression('0 AS is_2');
      }

      if (count($conditions) != 0) {
         $criteria = [
            'SELECT' => $fields,
            'FROM'   => static::getTable(),
            'WHERE'  => ['OR' => $conditions]
         ];
         return $criteria;
      }
      return null;
   }


yllen's avatar
CS  
yllen committed
169
   /**
Anael Mobilia's avatar
Anael Mobilia committed
170
    * @since 0.84
yllen's avatar
CS  
yllen committed
171 172
    *
    * @param $item            CommonDBTM object
173
    * @param $relations_id    (default NULL)
yllen's avatar
CS  
yllen committed
174
   **/
175
   static function getOpposite(CommonDBTM $item, &$relations_id = null) {
176 177 178
      return static::getOppositeByTypeAndID($item->getType(), $item->getID(), $relations_id);
   }

moyooo's avatar
moyooo committed
179

180
   /**
Anael Mobilia's avatar
Anael Mobilia committed
181
    * @since 0.84
182
    *
Cédric Anne's avatar
Cédric Anne committed
183 184 185
    * @param string       $itemtype        Type of the item to search for its opposite
    * @param integer      $items_id        ID of the item to search for its opposite
    * @param integer|null $relations_id
186
    **/
187
   static function getOppositeByTypeAndID($itemtype, $items_id, &$relations_id = null) {
188 189
      global $DB;

190
      if ($items_id < 0) {
191 192 193
         return false;
      }

194
      $criteria = self::getSQLCriteriaToSearchForItem($itemtype, $items_id);
195

196 197 198 199
      if ($criteria !== null) {
         $iterator = $DB->request($criteria);
         if (count($iterator) == 1) {
            $line = $iterator->next();
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
            if ($line['is_1'] == $line['is_2']) {
               return false;
            }
            if ($line['is_1'] == 0) {
               $opposites_id = $line['items_id_1'];
               $oppositetype = $line['itemtype_1'];
            }
            if ($line['is_2'] == 0) {
               $opposites_id = $line['items_id_2'];
               $oppositetype = $line['itemtype_2'];
            }
            if ((isset($oppositetype)) && (isset($opposites_id))) {
               $opposite = getItemForItemtype($oppositetype);
               if ($opposite !== false) {
                  if ($opposite->getFromDB($opposites_id)) {
                     if (!is_null($relations_id)) {
                        $relations_id = $line[static::getIndexName()];
                     }
                     return $opposite;
                  }
                  unset($opposite);
               }
            }
         }
      }
      return false;
   }


yllen's avatar
CS  
yllen committed
229
   /**
Anael Mobilia's avatar
Anael Mobilia committed
230
    * @since 0.84
yllen's avatar
CS  
yllen committed
231 232 233 234 235
    *
    * @param $number
    *
    * @return boolean
   **/
236
   function getOnePeer($number) {
yllen's avatar
CS  
yllen committed
237

238
      if ($number == 0) {
239 240
         $itemtype = static::$itemtype_1;
         $items_id = static::$items_id_1;
241
      } else if ($number == 1) {
242 243 244 245 246 247 248 249
         $itemtype = static::$itemtype_2;
         $items_id = static::$items_id_2;
      } else {
         return false;
      }
      return $this->getConnexityItem($itemtype, $items_id);
   }

yllen's avatar
CS  
yllen committed
250

251
   /**
252 253
    * Get link object between 2 items
    *
Anael Mobilia's avatar
Anael Mobilia committed
254
    * @since 0.84
yllen's avatar
CS  
yllen committed
255
    *
256 257 258
    * @param $item1 object 1
    * @param $item2 object 2
    *
259
    * @return boolean
260
   **/
moyooo's avatar
moyooo committed
261
   function getFromDBForItems(CommonDBTM $item1, CommonDBTM $item2) {
yllen's avatar
CS  
yllen committed
262

263 264
      // Check items ID
      if (($item1->getID() < 0) || ($item2->getID() < 0)) {
265
         return false;
yllen's avatar
CS  
yllen committed
266 267
      }

268
      $wheres = [];
269 270
      $wheres[static::$items_id_1] = $item1->getID();
      $wheres[static::$items_id_2] = $item2->getID();
yllen's avatar
CS  
yllen committed
271

272 273
      // Check item 1 type
      if (preg_match('/^itemtype/', static::$itemtype_1)) {
274
         $wheres[static::$itemtype_1] = $item1->getType();
275
      } else if (!is_a($item1, static::$itemtype_1)) {
276
         return false;
yllen's avatar
CS  
yllen committed
277
      }
278 279 280

      // Check item 1 type
      if (preg_match('/^itemtype/', static::$itemtype_2)) {
281
         $wheres[static::$itemtype_2] = $item2->getType();
282
      } else if (!is_a($item2, static::$itemtype_2)) {
283 284
         return false;
      }
285
      return $this->getFromDBByCrit($wheres);
286
   }
yllen's avatar
yllen committed
287

yllen's avatar
CS  
yllen committed
288

yllen's avatar
yllen committed
289 290 291 292 293
   /**
    * Get search function for the class
    *
    * @return array of search option
   **/
294
   function rawSearchOptions() {
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
      $tab = [];

      $tab[] = [
         'id'                 => 'common',
         'name'               => __('Characteristics')
      ];

      $tab[] = [
         'id'                 => '2',
         'table'              => $this->getTable(),
         'field'              => 'id',
         'name'               => __('ID'),
         'massiveaction'      => false,
         'datatype'           => 'number'
      ];
moyooo's avatar
moyooo committed
310

webmyster's avatar
webmyster committed
311
      if (!preg_match('/^itemtype/', static::$itemtype_1)) {
312 313 314 315
         $tab[] = [
            'id'                 => '3',
            'table'              => getTableForItemType(static::$itemtype_1),
            'field'              => static::$items_id_1,
316
            'name'               => call_user_func([static::$itemtype_1, 'getTypeName']),
317 318 319
            'datatype'           => 'text',
            'massiveaction'      => false
         ];
webmyster's avatar
webmyster committed
320 321 322
      }

      if (!preg_match('/^itemtype/', static::$itemtype_2)) {
323 324 325 326
         $tab[] = [
            'id'                 => '4',
            'table'              => getTableForItemType(static::$itemtype_2),
            'field'              => static::$items_id_2,
327
            'name'               => call_user_func([static::$itemtype_2, 'getTypeName']),
328 329 330
            'datatype'           => 'text',
            'massiveaction'      => false
         ];
webmyster's avatar
webmyster committed
331
      }
Walid Nouh's avatar
Walid Nouh committed
332 333 334

      return $tab;
   }
yllen's avatar
yllen committed
335

yllen's avatar
yllen committed
336

337
   /**
moyooo's avatar
moyooo committed
338
    * Specific check for check attach for relation 2
339
    *
Anael Mobilia's avatar
Anael Mobilia committed
340
    * @since 0.84
341 342 343 344
    *
    * @param $input Array of data to be added
    *
    * @return boolean
yllen's avatar
CS  
yllen committed
345
   **/
moyooo's avatar
moyooo committed
346 347
   function isAttach2Valid(Array &$input) {
      return false;
348 349
   }

yllen's avatar
CS  
yllen committed
350

moyooo's avatar
moyooo committed
351 352 353
   /**
    * Specific check for check attach for relation 1
    *
Anael Mobilia's avatar
Anael Mobilia committed
354
    * @since 0.84
moyooo's avatar
moyooo committed
355 356 357 358
    *
    * @param $input Array of data to be added
    *
    * @return boolean
yllen's avatar
CS  
yllen committed
359
   **/
moyooo's avatar
moyooo committed
360 361 362
   function isAttach1Valid(Array &$input) {
      return false;
   }
363

yllen's avatar
CS  
yllen committed
364

yllen's avatar
CS  
yllen committed
365
   /**
Anael Mobilia's avatar
Anael Mobilia committed
366
    * @since 0.84
yllen's avatar
CS  
yllen committed
367 368
    *
    * @param $method
yllen's avatar
CS  
yllen committed
369
    * @param $forceCheckBoth boolean force check both items(false by default)
yllen's avatar
CS  
yllen committed
370 371 372
    *
    * @return boolean
   **/
373
   static function canRelation($method, $forceCheckBoth = false) {
moyooo's avatar
moyooo committed
374

375
      $can1 = static::canConnexity($method, static::$checkItem_1_Rights, static::$itemtype_1,
yllen's avatar
CS  
yllen committed
376
                                   static::$items_id_1);
377
      $can2 = static::canConnexity($method, static::$checkItem_2_Rights, static::$itemtype_2,
yllen's avatar
CS  
yllen committed
378
                                   static::$items_id_2);
379

moyooo's avatar
moyooo committed
380
      /// Check only one if SAME RIGHT for both items and not force checkBoth
yllen's avatar
CS  
yllen committed
381 382 383
      if (((static::HAVE_SAME_RIGHT_ON_ITEM == static::$checkItem_1_Rights)
           && (static::HAVE_SAME_RIGHT_ON_ITEM == static::$checkItem_2_Rights))
          && !$forceCheckBoth) {
moyooo's avatar
moyooo committed
384 385 386
         if ($can1) {
            // Can view the second one ?
            if (!static::canConnexity($method, static::HAVE_VIEW_RIGHT_ON_ITEM, static::$itemtype_2,
yllen's avatar
CS  
yllen committed
387
                                      static::$items_id_2)) {
moyooo's avatar
moyooo committed
388 389
               return false;
            }
moyooo's avatar
moyooo committed
390
            return true;
moyooo's avatar
moyooo committed
391 392 393
         } else if ($can2) {
            // Can view the first one ?
            if (!static::canConnexity($method, static::HAVE_VIEW_RIGHT_ON_ITEM, static::$itemtype_1,
yllen's avatar
CS  
yllen committed
394
                                      static::$items_id_1)) {
moyooo's avatar
moyooo committed
395 396
               return false;
            }
moyooo's avatar
moyooo committed
397
            return true;
moyooo's avatar
moyooo committed
398 399 400 401
         } else {
            // No item have right
            return false;
         }
moyooo's avatar
moyooo committed
402
      }
moyooo's avatar
moyooo committed
403

moyooo's avatar
moyooo committed
404
      return ($can1 && $can2);
405

moyooo's avatar
moyooo committed
406
   }
remi's avatar
remi committed
407

408

yllen's avatar
CS  
yllen committed
409
   /**
Anael Mobilia's avatar
Anael Mobilia committed
410
    * @since 0.84
yllen's avatar
CS  
yllen committed
411 412 413
    *
    * @param $method
    * @param $methodNotItem
yllen's avatar
CS  
yllen committed
414 415
    * @param $check_entity            (true by default)
    * @param $forceCheckBoth boolean  force check both items (false by default)
yllen's avatar
CS  
yllen committed
416 417 418
    *
    * @return boolean
   **/
419
   function canRelationItem($method, $methodNotItem, $check_entity = true, $forceCheckBoth = false) {
420

421
      $OneWriteIsEnough = (!$forceCheckBoth
moyooo's avatar
moyooo committed
422
                           && ((static::HAVE_SAME_RIGHT_ON_ITEM == static::$checkItem_1_Rights)
yllen's avatar
CS  
yllen committed
423
                               || (static::HAVE_SAME_RIGHT_ON_ITEM == static::$checkItem_2_Rights)));
yllen's avatar
yllen committed
424

425
      try {
426
         $item1 = null;
427 428 429 430 431 432 433 434
         $can1  = $this->canConnexityItem($method, $methodNotItem, static::$checkItem_1_Rights,
                                          static::$itemtype_1, static::$items_id_1, $item1);
         if ($OneWriteIsEnough) {
            $view1 = $this->canConnexityItem($method, $methodNotItem,
                                             static::HAVE_VIEW_RIGHT_ON_ITEM, static::$itemtype_1,
                                             static::$items_id_1, $item1);
         }
      } catch (CommonDBConnexityItemNotFound $e) {
moyooo's avatar
moyooo committed
435
         if (static::$mustBeAttached_1 && !static::isAttach1Valid($this->fields)) {
436 437 438 439 440 441
            return false;
         }
         $can1         = true;
         $view1        = true;
         $check_entity = false; // If no item, then, we cannot check entities
      }
442

443
      try {
444
         $item2 = null;
445 446
         $can2  = $this->canConnexityItem($method, $methodNotItem, static::$checkItem_2_Rights,
                                          static::$itemtype_2, static::$items_id_2, $item2);
447 448 449 450 451
         if ($OneWriteIsEnough) {
            $view2 = $this->canConnexityItem($method, $methodNotItem,
                                             static::HAVE_VIEW_RIGHT_ON_ITEM, static::$itemtype_2,
                                             static::$items_id_2, $item2);
         }
452
      } catch (CommonDBConnexityItemNotFound $e) {
moyooo's avatar
moyooo committed
453
         if (static::$mustBeAttached_2 && !static::isAttach2Valid($this->fields)) {
454 455 456 457 458
            return false;
         }
         $can2         = true;
         $view2        = true;
         $check_entity = false; // If no item, then, we cannot check entities
459
      }
460

461 462 463 464
      if ($OneWriteIsEnough) {
         if ((!$can1 && !$can2)
             || ($can1 && !$view2)
             || ($can2 && !$view1)) {
moyooo's avatar
moyooo committed
465 466 467
            return false;
         }
      } else {
468
         if (!$can1 || !$can2) {
moyooo's avatar
moyooo committed
469 470
            return false;
         }
remi's avatar
remi committed
471
      }
472

473
      // Check coherency of entities
474
      if ($check_entity && static::$check_entity_coherency) {
475 476

         // If one of both extremity is not valid => not allowed !
477
         // (default is only to check on create and update not for view and delete)
478
         if ((!$item1 instanceof CommonDBTM)
webmyster's avatar
webmyster committed
479
             || (!$item2 instanceof CommonDBTM)) {
480 481
            return false;
         }
482
         if ($item1->isEntityAssign() && $item2->isEntityAssign()) {
moyooo's avatar
moyooo committed
483 484
            $entity1 = $item1->getEntityID();
            $entity2 = $item2->getEntityID();
485

moyooo's avatar
moyooo committed
486 487 488 489
            if ($entity1 == $entity2) {
               return true;
            }
            if (($item1->isRecursive())
yllen's avatar
CS  
yllen committed
490
                && in_array($entity1, getAncestorsOf("glpi_entities", $entity2))) {
moyooo's avatar
moyooo committed
491 492 493
               return true;
            }
            if (($item2->isRecursive())
yllen's avatar
CS  
yllen committed
494
                && in_array($entity2, getAncestorsOf("glpi_entities", $entity1))) {
moyooo's avatar
moyooo committed
495 496 497
               return true;
            }
            return false;
498 499 500
         }
      }

501 502
      return true;
   }
yllen's avatar
yllen committed
503

moyooo's avatar
moyooo committed
504

yllen's avatar
CS  
yllen committed
505
   /**
Anael Mobilia's avatar
Anael Mobilia committed
506
    * @since 0.84
yllen's avatar
CS  
yllen committed
507
   **/
508
   static function canCreate() {
moyooo's avatar
moyooo committed
509 510 511 512

      if ((static::$rightname) && (!Session::haveRight(static::$rightname, CREATE))) {
         return false;
      }
513
      return static::canRelation('canUpdate', static::$checkAlwaysBothItems);
514
   }
515

moyooo's avatar
moyooo committed
516

yllen's avatar
CS  
yllen committed
517
   /**
Anael Mobilia's avatar
Anael Mobilia committed
518
    * @since 0.84
yllen's avatar
CS  
yllen committed
519
   **/
520
   static function canView() {
moyooo's avatar
moyooo committed
521 522 523
      if ((static::$rightname) && (!Session::haveRight(static::$rightname, READ))) {
         return false;
      }
moyooo's avatar
moyooo committed
524
      // Always both checks for view
moyooo's avatar
moyooo committed
525
      return static::canRelation('canView', true);
526
   }
remi's avatar
remi committed
527

yllen's avatar
CS  
yllen committed
528 529

   /**
Anael Mobilia's avatar
Anael Mobilia committed
530
    * @since 0.84
yllen's avatar
CS  
yllen committed
531
   **/
532
   static function canUpdate() {
moyooo's avatar
moyooo committed
533 534 535
      if ((static::$rightname) && (!Session::haveRight(static::$rightname, UPDATE))) {
         return false;
      }
moyooo's avatar
moyooo committed
536
      return static::canRelation('canUpdate', static::$checkAlwaysBothItems);
537 538
   }

yllen's avatar
CS  
yllen committed
539 540

   /**
Anael Mobilia's avatar
Anael Mobilia committed
541
    * @since 0.84
yllen's avatar
CS  
yllen committed
542
   **/
543
   static function canDelete() {
moyooo's avatar
moyooo committed
544 545 546 547 548 549 550 551
      if ((static::$rightname) && (!Session::haveRight(static::$rightname, DELETE))) {
         return false;
      }
      return static::canRelation('canUpdate', static::$checkAlwaysBothItems);
   }


   /**
Anael Mobilia's avatar
Anael Mobilia committed
552
    * @since 0.85
moyooo's avatar
moyooo committed
553 554 555 556 557
    **/
   static function canPurge() {
      if ((static::$rightname) && (!Session::haveRight(static::$rightname, PURGE))) {
         return false;
      }
558
      return static::canRelation('canUpdate', static::$checkAlwaysBothItems);
559
   }
remi's avatar
remi committed
560

yllen's avatar
CS  
yllen committed
561 562

   /**
Anael Mobilia's avatar
Anael Mobilia committed
563
    * @since 0.84
yllen's avatar
CS  
yllen committed
564
   **/
565
   function canCreateItem() {
yllen's avatar
CS  
yllen committed
566 567 568

      return $this->canRelationItem('canUpdateItem', 'canUpdate', true,
                                    static::$checkAlwaysBothItems);
569
   }
yllen's avatar
yllen committed
570

yllen's avatar
CS  
yllen committed
571 572

   /**
Anael Mobilia's avatar
Anael Mobilia committed
573
    * @since 0.84
yllen's avatar
CS  
yllen committed
574
   **/
575
   function canViewItem() {
moyooo's avatar
moyooo committed
576
      return $this->canRelationItem('canViewItem', 'canView', false, true);
577
   }
yllen's avatar
yllen committed
578

yllen's avatar
CS  
yllen committed
579 580

   /**
Anael Mobilia's avatar
Anael Mobilia committed
581
    * @since 0.84
yllen's avatar
CS  
yllen committed
582
   **/
583
   function canUpdateItem() {
yllen's avatar
CS  
yllen committed
584 585 586

      return $this->canRelationItem('canUpdateItem', 'canUpdate', true,
                                    static::$checkAlwaysBothItems);
587 588
   }

yllen's avatar
CS  
yllen committed
589 590

   /**
Anael Mobilia's avatar
Anael Mobilia committed
591
    * @since 0.84
yllen's avatar
CS  
yllen committed
592
   **/
593
   function canDeleteItem() {
yllen's avatar
CS  
yllen committed
594 595 596

      return $this->canRelationItem('canUpdateItem', 'canUpdate', false,
                                    static::$checkAlwaysBothItems);
597
   }
yllen's avatar
yllen committed
598

yllen's avatar
CS  
yllen committed
599

Johan Cwiklinski's avatar
Johan Cwiklinski committed
600 601 602 603 604 605 606 607 608 609
   /**
    * @since 9.3.2
    */
   function canPurgeItem() {

      return $this->canRelationItem('canUpdateItem', 'canUpdate', false,
                                    static::$checkAlwaysBothItems);
   }


610
   /**
Anael Mobilia's avatar
Anael Mobilia committed
611
    * @since 0.84
612 613
   **/
   function addNeededInfoToInput($input) {
yllen's avatar
CS  
yllen committed
614

615 616 617 618
      // is entity missing and forwarding on ?
      if ($this->tryEntityForwarding() && !isset($input['entities_id'])) {
         // Merge both arrays to ensure all the fields are defined for the following checks
         $completeinput = array_merge($this->fields, $input);
yllen's avatar
CS  
yllen committed
619

620 621 622 623
         $itemToGetEntity = false;
         // Set the item to allow parent::prepareinputforadd to get the right item ...
         if (static::$take_entity_1) {
            $itemToGetEntity = static::getItemFromArray(static::$itemtype_1, static::$items_id_1,
yllen's avatar
CS  
yllen committed
624 625
                                                        $completeinput);
         } else if (static::$take_entity_2) {
626
            $itemToGetEntity = static::getItemFromArray(static::$itemtype_2, static::$items_id_2,
yllen's avatar
CS  
yllen committed
627
                                                        $completeinput);
628
         }
yllen's avatar
CS  
yllen committed
629

630 631 632 633 634 635
         // Set the item to allow parent::prepareinputforadd to get the right item ...
         if (($itemToGetEntity instanceof CommonDBTM)
            && $itemToGetEntity->isEntityForwardTo(get_called_class())) {

            $input['entities_id']  = $itemToGetEntity->getEntityID();
            $input['is_recursive'] = intval($itemToGetEntity->isRecursive());
yllen's avatar
yllen committed
636

637 638 639 640 641 642 643 644
         } else {
            // No entity link : set default values
            $input['entities_id']  = 0;
            $input['is_recursive'] = 0;
         }
      }
      return $input;
   }
yllen's avatar
CS  
yllen committed
645

yllen's avatar
CS  
yllen committed
646

yllen's avatar
CS  
yllen committed
647
   /**
Anael Mobilia's avatar
Anael Mobilia committed
648
    * @since 0.84
yllen's avatar
CS  
yllen committed
649 650 651
    *
    * @param $input
   **/
652 653 654 655 656
   function prepareInputForAdd($input) {

      if (!is_array($input)) {
         return false;
      }
yllen's avatar
CS  
yllen committed
657

658
      return $this->addNeededInfoToInput($input);
659 660 661 662
   }


   /**
Anael Mobilia's avatar
Anael Mobilia committed
663
    * @since 0.84
664 665 666 667 668 669 670
   **/
   function prepareInputForUpdate($input) {

      if (!is_array($input)) {
         return false;
      }

671
      // True if item changed
672
      if (!parent::checkAttachedItemChangesAllowed($input, [static::$itemtype_1,
673 674
                                                                 static::$items_id_1,
                                                                 static::$itemtype_2,
675
                                                                 static::$items_id_2])) {
676
         return false;
677 678
      }

679
      return parent::addNeededInfoToInput($input);
680 681
   }

yllen's avatar
CS  
yllen committed
682

683
   /**
684
    * Get the history name of first item
685
    *
Anael Mobilia's avatar
Anael Mobilia committed
686
    * @since 0.84
yllen's avatar
CS  
yllen committed
687 688
    *
    * @param $item    CommonDBTM object   the other item (ie. : $item2)
yllen's avatar
yllen committed
689 690 691 692 693
    * @param $case : can be overwrite by object
    *              - 'add' when this CommonDBRelation is added (to and item)
    *              - 'update item previous' transfert : this is removed from the old item
    *              - 'update item next' transfert : this is added to the new item
    *              - 'delete' when this CommonDBRelation is remove (from an item)
694 695 696
    *
    * @return (string) the name of the entry for the database (ie. : correctly slashed)
   **/
yllen's avatar
yllen committed
697
   function getHistoryNameForItem1(CommonDBTM $item, $case) {
yllen's avatar
yllen committed
698

699 700
      return $item->getNameID(['forceid'    => true,
                                    'additional' => true]);
webmyster's avatar
webmyster committed
701 702 703
   }


704
   /**
705
    * Get the history name of second item
706
    *
Anael Mobilia's avatar
Anael Mobilia committed
707
    * @since 0.84
yllen's avatar
CS  
yllen committed
708
    *
Cédric Anne's avatar
Cédric Anne committed
709 710 711 712 713 714
    * @param CommonDBTM $item the other item (ie. : $item1)
    * @param string     $case : can be overwrite by object
    *                            - 'add' when this CommonDBRelation is added (to and item)
    *                            - 'update item previous' transfert : this is removed from the old item
    *                            - 'update item next' transfert : this is added to the new item
    *                            - 'delete' when this CommonDBRelation is remove (from an item)
715
    *
Cédric Anne's avatar
Cédric Anne committed
716
    * @return string the name of the entry for the database (ie. : correctly slashed)
717
   **/
yllen's avatar
yllen committed
718
   function getHistoryNameForItem2(CommonDBTM $item, $case) {
yllen's avatar
yllen committed
719

720 721
      return $item->getNameID(['forceid'    => true,
                                    'additional' => true]);
webmyster's avatar
webmyster committed
722 723 724
   }


725
   function post_addItem() {
yllen's avatar
yllen committed
726

yllen's avatar
CS  
yllen committed
727 728 729
      if ((isset($this->input['_no_history']) && $this->input['_no_history'])
          || (!static::$logs_for_item_1
              && !static::$logs_for_item_2)) {
730 731 732
         return;
      }

733 734
      $item1 = $this->getConnexityItem(static::$itemtype_1, static::$items_id_1);
      $item2 = $this->getConnexityItem(static::$itemtype_2, static::$items_id_2);
yllen's avatar
yllen committed
735

Cédric Anne's avatar
Cédric Anne committed
736
      if ($item1 instanceof CommonDBTM && $item2 instanceof CommonDBTM) {
yllen's avatar
CS  
yllen committed
737 738
         if ($item1->dohistory
             && static::$logs_for_item_1) {
739 740 741 742 743
            $changes = [
               (isset($this->_force_log_option) ? $this->_force_log_option : 0),
               '',
               addslashes($this->getHistoryNameForItem1($item2, 'add')),
            ];
744 745
            Log::history($item1->getID(), $item1->getType(), $changes, $item2->getType(),
                         static::$log_history_1_add);
remi's avatar
remi committed
746
         }
747

748
         if ($item2->dohistory && static::$logs_for_item_2) {
749 750 751 752 753
            $changes = [
               '0',
               '',
               addslashes($this->getHistoryNameForItem2($item1, 'add')),
            ];
754 755 756
            Log::history($item2->getID(), $item2->getType(), $changes, $item1->getType(),
                         static::$log_history_2_add);
         }
remi's avatar
remi committed
757 758 759
      }
   }

760
   function post_updateItem($history = 1) {
remi's avatar
remi committed
761

yllen's avatar
CS  
yllen committed
762 763 764
      if ((isset($this->input['_no_history']) && $this->input['_no_history'])
          || (!static::$logs_for_item_1
              && !static::$logs_for_item_2)) {
765 766 767
         return;
      }

768 769
      $items_1 = $this->getItemsForLog(static::$itemtype_1, static::$items_id_1);
      $items_2 = $this->getItemsForLog(static::$itemtype_2, static::$items_id_2);
770

771 772 773 774 775
      $new1 = $items_1['new'];
      if (isset($items_1['previous'])) {
         $previous1 = $items_1['previous'];
      } else {
         $previous1 = $items_1['new'];
776
      }
yllen's avatar
yllen committed
777

778 779 780 781 782 783 784
      $new2 = $items_2['new'];
      if (isset($items_2['previous'])) {
         $previous2 = $items_2['previous'];
      } else {
         $previous2 = $items_2['new'];
      }

785 786 787 788 789
      $oldvalues = $this->oldvalues;
      unset($oldvalues[static::$itemtype_1]);
      unset($oldvalues[static::$items_id_1]);
      unset($oldvalues[static::$itemtype_2]);
      unset($oldvalues[static::$items_id_2]);
yllen's avatar
yllen committed
790

Cédric Anne's avatar
Cédric Anne committed
791
      foreach (array_keys($oldvalues) as $field) {
792 793 794 795 796 797
         $changes = $this->getHistoryChangeWhenUpdateField($field);
         if ((!is_array($changes)) || (count($changes) != 3)) {
            continue;
         }
         /// TODO clean management of it
         if ($new1 && $new1->dohistory
798
             && static::$logs_for_item_1) {
799 800 801 802
            Log::history($new1->getID(), $new1->getType(), $changes,
                         get_called_class().'#'.$field, static::$log_history_1_update);
         }
         if ($new2 && $new2->dohistory
803
             && static::$logs_for_item_2) {
804 805
            Log::history($new2->getID(), $new2->getType(), $changes,
                         get_called_class().'#'.$field, static::$log_history_2_update);
806
         }
807
      }
808

809
      if (isset($items_1['previous']) || isset($items_2['previous'])) {
yllen's avatar
yllen committed
810

811 812
         if ($previous2
             && $previous1 && $previous1->dohistory
813
             && static::$logs_for_item_1) {
814
            $changes[0] = '0';
815
            $changes[1] = addslashes($this->getHistoryNameForItem1($previous2,
yllen's avatar
CS  
yllen committed
816
                                     'update item previous'));
817 818 819 820
            $changes[2] = "";
            Log::history($previous1->getID(), $previous1->getType(), $changes,
                         $previous2->getType(), static::$log_history_1_delete);
         }
821

822 823
         if ($previous1
             && $previous2 && $previous2->dohistory
824
             && static::$logs_for_item_2) {
825
            $changes[0] = '0';
826
            $changes[1] = addslashes($this->getHistoryNameForItem2($previous1,
yllen's avatar
CS  
yllen committed
827
                                     'update item previous'));
828 829 830 831
            $changes[2] = "";
            Log::history($previous2->getID(), $previous2->getType(), $changes,
                         $previous1->getType(), static::$log_history_2_delete);
         }
remi's avatar
remi committed
832

833 834
         if ($new2
             && $new1 && $new1->dohistory
835
             && static::$logs_for_item_1) {
836 837
            $changes[0] = '0';
            $changes[1] = "";
838
            $changes[2] = addslashes($this->getHistoryNameForItem1($new2, 'update item next'));
yllen's avatar
CS  
yllen committed
839 840
            Log::history($new1->getID(), $new1->getType(), $changes, $new2->getType(),
                         static::$log_history_1_add);
841
         }
yllen's avatar
yllen committed
842

843 844
         if ($new1
             && $new2 && $new2->dohistory
845
             && static::$logs_for_item_2) {
846 847
            $changes[0] = '0';
            $changes[1] = "";