Ganteng Doang Upload Shell Gak Bisa


Linux server.jmdstrack.com 3.10.0-1160.119.1.el7.tuxcare.els10.x86_64 #1 SMP Fri Oct 11 21:40:41 UTC 2024 x86_64
/ home/ jmdstrac/ public_html/ devices/ src/

/home/jmdstrac/public_html/devices/src/CommonDBRelation.php

<?php

/**
 * ---------------------------------------------------------------------
 *
 * GLPI - Gestionnaire Libre de Parc Informatique
 *
 * http://glpi-project.org
 *
 * @copyright 2015-2023 Teclib' and contributors.
 * @copyright 2003-2014 by the INDEPNET Development Team.
 * @licence   https://www.gnu.org/licenses/gpl-3.0.html
 *
 * ---------------------------------------------------------------------
 *
 * LICENSE
 *
 * This file is part of GLPI.
 *
 * 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 3 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, see <https://www.gnu.org/licenses/>.
 *
 * ---------------------------------------------------------------------
 */

/// Common DataBase Relation Table Manager Class
abstract class CommonDBRelation extends CommonDBConnexity
{
   // Item 1 information
   // * definition
    public static $itemtype_1; // Type ref or field name (must start with itemtype)
    public static $items_id_1; // Field name
   // * entity inheritance
    public static $take_entity_1          = true;
   // * rights
    public static $checkItem_1_Rights     = self::HAVE_SAME_RIGHT_ON_ITEM;
    public static $mustBeAttached_1       = true;
   // * log
    public static $logs_for_item_1        = true;
    public static $log_history_1_add      = Log::HISTORY_ADD_RELATION;
    public static $log_history_1_update   = Log::HISTORY_UPDATE_RELATION;
    public static $log_history_1_delete   = Log::HISTORY_DEL_RELATION;
    public static $log_history_1_lock     = Log::HISTORY_LOCK_RELATION;
    public static $log_history_1_unlock   = Log::HISTORY_UNLOCK_RELATION;

   // Item 2 information
   // * definition
    public static $itemtype_2; // Type ref or field name (must start with itemtype)
    public static $items_id_2; // Field name
   // * entity inheritance
    public static $take_entity_2          = false;
   // * rights
    public static $checkItem_2_Rights     = self::HAVE_SAME_RIGHT_ON_ITEM;
    public static $mustBeAttached_2       = true;
   // * log
    public static $logs_for_item_2        = true;
    public static $log_history_2_add      = Log::HISTORY_ADD_RELATION;
    public static $log_history_2_update   = Log::HISTORY_UPDATE_RELATION;
    public static $log_history_2_delete   = Log::HISTORY_DEL_RELATION;
    public static $log_history_2_lock     = Log::HISTORY_LOCK_RELATION;
    public static $log_history_2_unlock   = Log::HISTORY_UNLOCK_RELATION;

   // Relation between items to check
   /// If both items must be checked for rights (default is only one)
    public static $checkAlwaysBothItems   = false;
   /// If both items must be in viewable each other entities
    public static $check_entity_coherency = true;

    public $no_form_page                  = true;

    /**
     * Search option number to use in parent item log.
     * Value is defined during logging process and unset after it.
     * @var int
     */
    protected $_force_log_option;

    /**
     * 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
     **/
    public static function getSQLCriteriaToSearchForItem($itemtype, $items_id)
    {
        global $DB;

        $table = static::getTable();

        $conditions = [];
        $fields     = [
            static::getIndexName(),
            static::$items_id_1 . ' AS items_id_1',
            static::$items_id_2 . ' AS items_id_2'
        ];

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

        $request = false;
        if (preg_match('/^itemtype/', static::$itemtype_1)) {
            $fields[] = static::$itemtype_1 . ' AS itemtype_1';
            $where1[$table . '.' . static::$itemtype_1] = $itemtype;
            $request = true;
        } else {
            $fields[] = new \QueryExpression("'" . static::$itemtype_1 . "' AS itemtype_1");
            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 = [
            $table . '.' . static::$items_id_2 => $items_id
        ];
        $request = false;
        if (preg_match('/^itemtype/', static::$itemtype_2)) {
            $fields[] = static::$itemtype_2 . ' AS itemtype_2';
            $where2[$table . '.' . static::$itemtype_2] = $itemtype;
            $request = true;
        } else {
            $fields[] = new \QueryExpression("'" . static::$itemtype_2 . "' AS itemtype_2");
            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'   => $table,
                'WHERE'  => ['OR' => $conditions]
            ];
            return $criteria;
        }
        return null;
    }


    /**
     * @since 0.84
     *
     * @param $item            CommonDBTM object
     * @param $relations_id    (default NULL)
     **/
    public static function getOpposite(CommonDBTM $item, &$relations_id = null)
    {
        return static::getOppositeByTypeAndID($item->getType(), $item->getID(), $relations_id);
    }


    /**
     * @since 0.84
     *
     * @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
     **/
    public static function getOppositeByTypeAndID($itemtype, $items_id, &$relations_id = null)
    {
        global $DB;

        if ($items_id < 0) {
            return false;
        }

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

        if ($criteria !== null) {
            $iterator = $DB->request($criteria);
            if (count($iterator) == 1) {
                $line = $iterator->current();
                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;
    }


    /**
     * @since 0.84
     *
     * @param $number
     *
     * @return boolean
     **/
    public function getOnePeer($number)
    {

        if ($number == 0) {
            $itemtype = static::$itemtype_1;
            $items_id = static::$items_id_1;
        } else if ($number == 1) {
            $itemtype = static::$itemtype_2;
            $items_id = static::$items_id_2;
        } else {
            return false;
        }
        return $this->getConnexityItem($itemtype, $items_id);
    }


    /**
     * Get link object between 2 items
     *
     * @since 0.84
     *
     * @param CommonDBTM $item1 object 1
     * @param CommonDBTM $item2 object 2
     *
     * @return boolean
     **/
    public function getFromDBForItems(CommonDBTM $item1, CommonDBTM $item2)
    {

       // Check items ID
        if (($item1->getID() < 0) || ($item2->getID() < 0)) {
            return false;
        }

        $wheres = [];
        $wheres[static::$items_id_1] = $item1->getID();
        $wheres[static::$items_id_2] = $item2->getID();

       // Check item 1 type
        if (preg_match('/^itemtype/', static::$itemtype_1)) {
            $wheres[static::$itemtype_1] = $item1->getType();
        } else if (!is_a($item1, static::$itemtype_1)) {
            return false;
        }

       // Check item 1 type
        if (preg_match('/^itemtype/', static::$itemtype_2)) {
            $wheres[static::$itemtype_2] = $item2->getType();
        } else if (!is_a($item2, static::$itemtype_2)) {
            return false;
        }
        return $this->getFromDBByCrit($wheres);
    }


    /**
     * Get search function for the class
     *
     * @return array of search option
     **/
    public function rawSearchOptions()
    {
        $tab = [];

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

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

        $itemtype1 = static::$itemtype_1;
        if (!preg_match('/^itemtype/', $itemtype1)) {
            $tab[] = [
                'id'                 => '3',
                'table'              => getTableForItemType($itemtype1),
                'field'              => $itemtype1::getIndexName(),
                'linkfield'          => static::$items_id_1,
                'name'               => call_user_func([$itemtype1, 'getTypeName']),
                'datatype'           => 'text',
                'massiveaction'      => false
            ];
        }

        $itemtype2 = static::$itemtype_2;
        if (!preg_match('/^itemtype/', $itemtype2)) {
            $tab[] = [
                'id'                 => '4',
                'table'              => getTableForItemType($itemtype2),
                'field'              => $itemtype2::getIndexName(),
                'linkfield'          => static::$items_id_2,
                'name'               => call_user_func([$itemtype2, 'getTypeName']),
                'datatype'           => 'text',
                'massiveaction'      => false
            ];
        }

        return $tab;
    }


    /**
     * Specific check for check attach for relation 2
     *
     * @since 0.84
     *
     * @param $input Array of data to be added
     *
     * @return boolean
     **/
    public function isAttach2Valid(array &$input)
    {
        return false;
    }


    /**
     * Specific check for check attach for relation 1
     *
     * @since 0.84
     *
     * @param $input Array of data to be added
     *
     * @return boolean
     **/
    public function isAttach1Valid(array &$input)
    {
        return false;
    }


    /**
     * @since 0.84
     *
     * @param $method
     * @param $forceCheckBoth boolean force check both items(false by default)
     *
     * @return boolean
     **/
    public static function canRelation($method, $forceCheckBoth = false)
    {

        $can1 = static::canConnexity(
            $method,
            static::$checkItem_1_Rights,
            static::$itemtype_1,
            static::$items_id_1
        );
        $can2 = static::canConnexity(
            $method,
            static::$checkItem_2_Rights,
            static::$itemtype_2,
            static::$items_id_2
        );

       /// Check only one if SAME RIGHT for both items and not force checkBoth
        if (
            ((static::HAVE_SAME_RIGHT_ON_ITEM == static::$checkItem_1_Rights)
            && (static::HAVE_SAME_RIGHT_ON_ITEM == static::$checkItem_2_Rights))
            && !$forceCheckBoth
        ) {
            if ($can1) {
               // Can view the second one ?
                if (
                    !static::canConnexity(
                        $method,
                        static::HAVE_VIEW_RIGHT_ON_ITEM,
                        static::$itemtype_2,
                        static::$items_id_2
                    )
                ) {
                    return false;
                }
                return true;
            } else if ($can2) {
               // Can view the first one ?
                if (
                    !static::canConnexity(
                        $method,
                        static::HAVE_VIEW_RIGHT_ON_ITEM,
                        static::$itemtype_1,
                        static::$items_id_1
                    )
                ) {
                    return false;
                }
                return true;
            } else {
               // No item have right
                return false;
            }
        }

        return ($can1 && $can2);
    }


    /**
     * @since 0.84
     *
     * @param $method
     * @param $methodNotItem
     * @param $check_entity            (true by default)
     * @param $forceCheckBoth boolean  force check both items (false by default)
     *
     * @return boolean
     **/
    public function canRelationItem($method, $methodNotItem, $check_entity = true, $forceCheckBoth = false)
    {

        $OneWriteIsEnough = (!$forceCheckBoth
                           && ((static::HAVE_SAME_RIGHT_ON_ITEM == static::$checkItem_1_Rights)
                               || (static::HAVE_SAME_RIGHT_ON_ITEM == static::$checkItem_2_Rights)));

        $view1 = false;
        $view2 = false;

        try {
            $item1 = null;
            $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) {
            if (static::$mustBeAttached_1 && !$this->isAttach1Valid($this->fields)) {
                return false;
            }
            $can1         = true;
            $view1        = true;
            $check_entity = false; // If no item, then, we cannot check entities
        }

        try {
            $item2 = null;
            $can2  = $this->canConnexityItem(
                $method,
                $methodNotItem,
                static::$checkItem_2_Rights,
                static::$itemtype_2,
                static::$items_id_2,
                $item2
            );
            if ($OneWriteIsEnough) {
                $view2 = $this->canConnexityItem(
                    $method,
                    $methodNotItem,
                    static::HAVE_VIEW_RIGHT_ON_ITEM,
                    static::$itemtype_2,
                    static::$items_id_2,
                    $item2
                );
            }
        } catch (CommonDBConnexityItemNotFound $e) {
            if (static::$mustBeAttached_2 && !$this->isAttach2Valid($this->fields)) {
                return false;
            }
            $can2         = true;
            $view2        = true;
            $check_entity = false; // If no item, then, we cannot check entities
        }

        if ($OneWriteIsEnough) {
            if (
                (!$can1 && !$can2)
                || ($can1 && !$view2)
                || ($can2 && !$view1)
            ) {
                return false;
            }
        } else {
            if (!$can1 || !$can2) {
                return false;
            }
        }

       // Check coherency of entities
        if ($check_entity && static::$check_entity_coherency) {
           // If one of both extremity is not valid => not allowed !
           // (default is only to check on create and update not for view and delete)
            if (
                (!$item1 instanceof CommonDBTM)
                || (!$item2 instanceof CommonDBTM)
            ) {
                return false;
            }
            if ($item1->isEntityAssign() && $item2->isEntityAssign()) {
                $entity1 = $item1->getEntityID();
                $entity2 = $item2->getEntityID();

                if ($entity1 == $entity2) {
                    return true;
                }
                if (
                    ($item1->isRecursive())
                    && in_array($entity1, getAncestorsOf("glpi_entities", $entity2))
                ) {
                    return true;
                }
                if (
                    ($item2->isRecursive())
                    && in_array($entity2, getAncestorsOf("glpi_entities", $entity1))
                ) {
                    return true;
                }
                return false;
            }
        }

        return true;
    }


    /**
     * @since 0.84
     **/
    public static function canCreate()
    {

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


    /**
     * @since 0.84
     **/
    public static function canView()
    {
        if ((static::$rightname) && (!Session::haveRight(static::$rightname, READ))) {
            return false;
        }
       // Always both checks for view
        return static::canRelation('canView', true);
    }


    /**
     * @since 0.84
     **/
    public static function canUpdate()
    {
        if ((static::$rightname) && (!Session::haveRight(static::$rightname, UPDATE))) {
            return false;
        }
        return static::canRelation('canUpdate', static::$checkAlwaysBothItems);
    }


    /**
     * @since 0.84
     **/
    public static function canDelete()
    {
        if ((static::$rightname) && (!Session::haveRight(static::$rightname, DELETE))) {
            return false;
        }
        return static::canRelation('canUpdate', static::$checkAlwaysBothItems);
    }


    /**
     * @since 0.85
     **/
    public static function canPurge()
    {
        if ((static::$rightname) && (!Session::haveRight(static::$rightname, PURGE))) {
            return false;
        }
        return static::canRelation('canUpdate', static::$checkAlwaysBothItems);
    }


    /**
     * @since 0.84
     **/
    public function canCreateItem()
    {
        return $this->canRelationItem(
            'canUpdateItem',
            'canUpdate',
            true,
            static::$checkAlwaysBothItems
        );
    }


    /**
     * @since 0.84
     **/
    public function canViewItem()
    {
        return $this->canRelationItem('canViewItem', 'canView', false, true);
    }


    /**
     * @since 0.84
     **/
    public function canUpdateItem()
    {

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


    /**
     * @since 0.84
     **/
    public function canDeleteItem()
    {

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


    /**
     * @since 9.3.2
     */
    public function canPurgeItem()
    {

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


    public function addNeededInfoToInput($input)
    {

       // 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);

            $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,
                    $completeinput
                );
            } else if (static::$take_entity_2) {
                $itemToGetEntity = static::getItemFromArray(
                    static::$itemtype_2,
                    static::$items_id_2,
                    $completeinput
                );
            }

           // 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());
            } else {
               // No entity link : set default values
                $input['entities_id']  = Session::getActiveEntity();
                $input['is_recursive'] = 0;
            }
        }
        return $input;
    }


    public function prepareInputForAdd($input)
    {

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

        return $this->addNeededInfoToInput($input);
    }


    public function prepareInputForUpdate($input)
    {

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

       // True if item changed
        if (
            !$this->checkAttachedItemChangesAllowed($input, [static::$itemtype_1,
                static::$items_id_1,
                static::$itemtype_2,
                static::$items_id_2
            ])
        ) {
            return false;
        }

        return parent::addNeededInfoToInput($input);
    }


    /**
     * Get the history name of first item
     *
     * @since 0.84
     *
     * @param CommonDBTM $item    CommonDBTM object   the other item (ie. : $item2)
     * @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)
     *
     * @return string The name of the entry for the database (ie. : correctly slashed)
     **/
    public function getHistoryNameForItem1(CommonDBTM $item, $case)
    {

        return $item->getNameID(['forceid'    => true,
            'additional' => true
        ]);
    }


    /**
     * Get the history name of second item
     *
     * @since 0.84
     *
     * @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)
     *
     * @return string the name of the entry for the database (ie. : correctly slashed)
     **/
    public function getHistoryNameForItem2(CommonDBTM $item, $case)
    {

        return $item->getNameID(['forceid'    => true,
            'additional' => true
        ]);
    }


    public function post_addItem()
    {

        if (
            (isset($this->input['_no_history']) && $this->input['_no_history'])
            || (!static::$logs_for_item_1
              && !static::$logs_for_item_2)
        ) {
            return;
        }

        $item1 = $this->getConnexityItem(static::$itemtype_1, static::$items_id_1);
        $item2 = $this->getConnexityItem(static::$itemtype_2, static::$items_id_2);

        if ($item1 instanceof CommonDBTM && $item2 instanceof CommonDBTM) {
            if (
                $item1->dohistory
                && static::$logs_for_item_1
            ) {
                $changes = [
                    (isset($this->_force_log_option) ? $this->_force_log_option : 0),
                    '',
                    addslashes($this->getHistoryNameForItem1($item2, 'add')),
                ];
                Log::history(
                    $item1->getID(),
                    $item1->getType(),
                    $changes,
                    $item2->getType(),
                    static::$log_history_1_add
                );
            }

            if ($item2->dohistory && static::$logs_for_item_2) {
                $changes = [
                    '0',
                    '',
                    addslashes($this->getHistoryNameForItem2($item1, 'add')),
                ];
                Log::history(
                    $item2->getID(),
                    $item2->getType(),
                    $changes,
                    $item1->getType(),
                    static::$log_history_2_add
                );
            }
        }
    }

    public function post_updateItem($history = 1)
    {

        if (
            (isset($this->input['_no_history']) && $this->input['_no_history'])
            || (!static::$logs_for_item_1
              && !static::$logs_for_item_2)
        ) {
            return;
        }

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

        $new1 = $items_1['new'];
        if (isset($items_1['previous'])) {
            $previous1 = $items_1['previous'];
        } else {
            $previous1 = $items_1['new'];
        }

        $new2 = $items_2['new'];
        if (isset($items_2['previous'])) {
            $previous2 = $items_2['previous'];
        } else {
            $previous2 = $items_2['new'];
        }

        $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]);

        foreach (array_keys($oldvalues) as $field) {
            $changes = $this->getHistoryChangeWhenUpdateField($field);
            if ((!is_array($changes)) || (count($changes) != 3)) {
                continue;
            }
           /// TODO clean management of it
            if (
                $new1 && $new1->dohistory
                && static::$logs_for_item_1
            ) {
                Log::history(
                    $new1->getID(),
                    $new1->getType(),
                    $changes,
                    get_called_class() . '#' . $field,
                    static::$log_history_1_update
                );
            }
            if (
                $new2 && $new2->dohistory
                && static::$logs_for_item_2
            ) {
                Log::history(
                    $new2->getID(),
                    $new2->getType(),
                    $changes,
                    get_called_class() . '#' . $field,
                    static::$log_history_2_update
                );
            }
        }

        if (isset($items_1['previous']) || isset($items_2['previous'])) {
            if (
                $previous2
                && $previous1 && $previous1->dohistory
                && static::$logs_for_item_1
            ) {
                $changes[0] = '0';
                $changes[1] = addslashes($this->getHistoryNameForItem1(
                    $previous2,
                    'update item previous'
                ));
                $changes[2] = "";
                Log::history(
                    $previous1->getID(),
                    $previous1->getType(),
                    $changes,
                    $previous2->getType(),
                    static::$log_history_1_delete
                );
            }

            if (
                $previous1
                && $previous2 && $previous2->dohistory
                && static::$logs_for_item_2
            ) {
                $changes[0] = '0';
                $changes[1] = addslashes($this->getHistoryNameForItem2(
                    $previous1,
                    'update item previous'
                ));
                $changes[2] = "";
                Log::history(
                    $previous2->getID(),
                    $previous2->getType(),
                    $changes,
                    $previous1->getType(),
                    static::$log_history_2_delete
                );
            }

            if (
                $new2
                && $new1 && $new1->dohistory
                && static::$logs_for_item_1
            ) {
                $changes[0] = '0';
                $changes[1] = "";
                $changes[2] = addslashes($this->getHistoryNameForItem1($new2, 'update item next'));
                Log::history(
                    $new1->getID(),
                    $new1->getType(),
                    $changes,
                    $new2->getType(),
                    static::$log_history_1_add
                );
            }

            if (
                $new1
                && $new2 && $new2->dohistory
                && static::$logs_for_item_2
            ) {
                $changes[0] = '0';
                $changes[1] = "";
                $changes[2] = addslashes($this->getHistoryNameForItem2($new1, 'update item next'));
                Log::history(
                    $new2->getID(),
                    $new2->getType(),
                    $changes,
                    $new1->getType(),
                    static::$log_history_2_add
                );
            }
        }
    }

    public function cleanDBonMarkDeleted()
    {

        if (
            (isset($this->input['_no_history']) && $this->input['_no_history'])
            || (!static::$logs_for_item_1
              && !static::$logs_for_item_2)
        ) {
            return;
        }

        if (
            $this->useDeletedToLockIfDynamic()
            && $this->isDynamic()
        ) {
            $item1 = $this->getConnexityItem(static::$itemtype_1, static::$items_id_1);
            $item2 = $this->getConnexityItem(static::$itemtype_2, static::$items_id_2);

            if ($item1 instanceof CommonDBTM && $item2 instanceof CommonDBTM) {
                if (
                    $item1->dohistory
                    && static::$logs_for_item_1
                ) {
                    $changes = [
                        '0',
                        addslashes($this->getHistoryNameForItem1($item2, 'lock')),
                        '',
                    ];

                    Log::history(
                        $item1->getID(),
                        $item1->getType(),
                        $changes,
                        $item2->getType(),
                        static::$log_history_1_lock
                    );
                }

                if (
                    $item2->dohistory
                    && static::$logs_for_item_2
                ) {
                    $changes = [
                        '0',
                        addslashes($this->getHistoryNameForItem2($item1, 'lock')),
                        '',
                    ];
                    Log::history(
                        $item2->getID(),
                        $item2->getType(),
                        $changes,
                        $item1->getType(),
                        static::$log_history_2_lock
                    );
                }
            }
        }
    }

    public function post_restoreItem()
    {

        if (
            (isset($this->input['_no_history']) && $this->input['_no_history'])
            || (!static::$logs_for_item_1
              && !static::$logs_for_item_2)
        ) {
            return;
        }

        if (
            $this->useDeletedToLockIfDynamic()
            && $this->isDynamic()
        ) {
            $item1 = $this->getConnexityItem(static::$itemtype_1, static::$items_id_1);
            $item2 = $this->getConnexityItem(static::$itemtype_2, static::$items_id_2);

            if ($item1 instanceof CommonDBTM && $item2 instanceof CommonDBTM) {
                if (
                    $item1->dohistory
                    && static::$logs_for_item_1
                ) {
                    $changes = [
                        '0',
                        '',
                        addslashes($this->getHistoryNameForItem1($item2, 'unlock')),
                    ];
                    Log::history(
                        $item1->getID(),
                        $item1->getType(),
                        $changes,
                        $item2->getType(),
                        static::$log_history_1_unlock
                    );
                }

                if (
                    $item2->dohistory
                    && static::$logs_for_item_2
                ) {
                    $changes = [
                        '0',
                        '',
                        addslashes($this->getHistoryNameForItem2($item1, 'unlock')),
                    ];
                    Log::history(
                        $item2->getID(),
                        $item2->getType(),
                        $changes,
                        $item1->getType(),
                        static::$log_history_2_unlock
                    );
                }
            }
        }
    }

    public function post_deleteFromDB()
    {

        if (
            (isset($this->input['_no_history']) && $this->input['_no_history'])
            || (!static::$logs_for_item_1
              && !static::$logs_for_item_2)
        ) {
            return;
        }

        $item1 = $this->getConnexityItem(static::$itemtype_1, static::$items_id_1);
        $item2 = $this->getConnexityItem(static::$itemtype_2, static::$items_id_2);

        if ($item1 instanceof CommonDBTM && $item2 instanceof CommonDBTM) {
            if (
                $item1->dohistory
                && static::$logs_for_item_1
            ) {
                $changes = [
                    '0',
                    addslashes($this->getHistoryNameForItem1($item2, 'delete')),
                    '',
                ];
                Log::history(
                    $item1->getID(),
                    $item1->getType(),
                    $changes,
                    $item2->getType(),
                    static::$log_history_1_delete
                );
            }

            if (
                $item2->dohistory
                && static::$logs_for_item_2
            ) {
                $changes = [
                    '0',
                    addslashes($this->getHistoryNameForItem2($item1, 'delete')),
                    '',
                ];
                Log::history(
                    $item2->getID(),
                    $item2->getType(),
                    $changes,
                    $item1->getType(),
                    static::$log_history_2_delete
                );
            }
        }
    }


    /**
     * @since 0.84
     *
     * @param string               $itemtype
     * @param HTMLTableBase        $base      HTMLTableBase object
     * @param HTMLTableSuperHeader $super     HTMLTableSuperHeader object (default NULL)
     * @param HTMLTableHeader      $father    HTMLTableHeader object (default NULL)
     * @param array                $options
     **/
    public static function getHTMLTableHeader(
        $itemtype,
        HTMLTableBase $base,
        HTMLTableSuperHeader $super = null,
        HTMLTableHeader $father = null,
        array $options = []
    ) {

        if (isset($options[get_called_class() . '_side'])) {
            $side = $options[get_called_class() . '_side'];
        } else {
            $side = 0;
        }
        $oppositetype = '';
        if (
            ($side == 1)
            || ($itemtype == static::$itemtype_1)
        ) {
            $oppositetype = static::$itemtype_2;
        }
        if (
            ($side == 2)
            || ($itemtype == static::$itemtype_2)
        ) {
            $oppositetype = static::$itemtype_1;
        }
        if (
            class_exists($oppositetype)
            && method_exists($oppositetype, 'getHTMLTableHeader')
        ) {
            $oppositetype::getHTMLTableHeader(get_called_class(), $base, $super, $father, $options);
        }
    }


    /**
     * @since 0.84
     *
     * @param HTMLTableRow  $row      HTMLTableRow object (default NULL)
     * @param CommonDBTM    $item     CommonDBTM object (default NULL)
     * @param HTMLTableCell $father   HTMLTableCell object (default NULL)
     * @param array         $options
     **/
    public static function getHTMLTableCellsForItem(
        HTMLTableRow $row = null,
        CommonDBTM $item = null,
        HTMLTableCell $father = null,
        array $options = []
    ) {
        global $DB;

        if (empty($item)) {
            if (empty($father)) {
                return;
            }
            $item = $father->getItem();
        }

        $criteria = self::getSQLCriteriaToSearchForItem($item->getType(), $item->getID());
        if ($criteria !== null) {
            $relation = new static();
            $iterator = $DB->request($criteria);
            foreach ($iterator as $line) {
                if ($line['is_1'] != $line['is_2']) {
                    if ($line['is_1'] == 0) {
                        $options['items_id'] = $line['items_id_1'];
                        $oppositetype        = $line['itemtype_1'];
                    } else {
                        $options['items_id'] = $line['items_id_2'];
                        $oppositetype        = $line['itemtype_2'];
                    }
                    if (
                        class_exists($oppositetype)
                        && method_exists($oppositetype, 'getHTMLTableCellsForItem')
                        && $relation->getFromDB($line[static::getIndexName()])
                    ) {
                         $oppositetype::getHTMLTableCellsForItem($row, $relation, $father, $options);
                    }
                }
            }
        }
    }


    /**
     * Affect a CommonDBRelation to a given item. By default, unaffect it
     *
     * @param integer $id       the id of the CommonDBRelation to affect
     * @param integer $peer     the number of the peer (ie.: 0 or 1)
     * @param integer $items_id the id of the new item
     * @param string  $itemtype the type of the new item
     *
     * @return boolean : true on success
     **/
    public function affectRelation($id, $peer, $items_id = 0, $itemtype = '')
    {

        $input = [static::getIndexName() => $id];

        if ($peer == 0) {
            $input[static::$items_id_1] = $items_id;

            if (preg_match('/^itemtype/', static::$itemtype_1)) {
                $input[static::$itemtype_1] = $itemtype;
            }
        } else {
            $input[static::$items_id_2] = $items_id;
            if (preg_match('/^itemtype/', static::$itemtype_2)) {
                $input[static::$itemtype_2] = $itemtype;
            }
        }

        return $this->update($input);
    }


    /**
     * Get all specificities of the current itemtype concerning the massive actions
     *
     * @since 0.85
     *
     * @return array of the specificities:
     *        'select_items_options_1' Base options for item_1 select
     *        'select_items_options_2' Base options for item_2 select
     *        'can_remove_all_at_once' Is it possible to remove all links at once ?
     *        'only_remove_all_at_once' Do we only allow to remove all links at once ?
     *                                  (implies 'can_remove_all_at_once')
     *        'itemtypes'              array of kind of items in case of itemtype as one item
     *        'button_labels'          array of the labels of the button indexed by the action name
     *        'normalized'             array('add', 'remove') of arrays containing each action
     *        'check_both_items_if_same_type' to check if the link already exists, also care of both
     *                                        items are of the same type, then switch them
     *        'can_link_several_times' Is it possible to link items several times ?
     *        'update_id_different'    Do we update the link if it already exists (not used in case
     *                                 of 'can_link_several_times')
     **/
    public static function getRelationMassiveActionsSpecificities()
    {

        return ['select_items_options_1'        => [],
            'dropdown_method_1'             => 'dropdown',
            'select_items_options_2'        => [],
            'dropdown_method_2'             => 'dropdown',
            'can_remove_all_at_once'        => true,
            'only_remove_all_at_once'       => false,
            'itemtypes'                     => [],
            'button_labels'                 => ['add'    => _sx('button', 'Add'),
                'remove' => _sx(
                    'button',
                    'Delete permanently'
                )
            ],
            'normalized'                    => ['add'    => ['add'],
                'remove' => ['remove']
            ],
            'check_both_items_if_same_type' => false,
            'can_link_several_times'        => false,
            'update_if_different'           => false
        ];
    }


    /**
     * Display subForm of the massive action
     *
     * @param MassiveAction $ma           current massive action
     * @param integer       $peer_number  the number of the concerned peer
     *
     * @return void
     **/
    public static function showRelationMassiveActionsSubForm(MassiveAction $ma, $peer_number)
    {
    }


    /**
     * get the type of the item with the name of the action or the types of the input
     *
     * @since 0.85
     *
     * @param MassiveAction $ma current massive action
     *
     * @return number of the peer
     **/
    public static function getRelationMassiveActionsPeerForSubForm(MassiveAction $ma)
    {

        $items = $ma->getItems();
       // If direct itemtype, then, its easy to find !
        if (isset($items[static::$itemtype_1])) {
            return 2;
        }
        if (isset($items[static::$itemtype_2])) {
            return 1;
        }

       // Else, check if one of both peer is 'itemtype*'
        if (preg_match('/^itemtype/', static::$itemtype_1)) {
            return 2;
        }
        if (preg_match('/^itemtype/', static::$itemtype_2)) {
            return 1;
        }

       // Else we cannot define !
        return 0;
    }


    public static function showMassiveActionsSubForm(MassiveAction $ma)
    {

        $specificities = static::getRelationMassiveActionsSpecificities();
        $action        = $ma->getAction();

       // First, get normalized action : add or remove
        if (in_array($action, $specificities['normalized']['add'])) {
            $normalized_action = 'add';
        } else if (in_array($action, $specificities['normalized']['remove'])) {
            $normalized_action = 'remove';
        } else {
           // If we cannot get normalized action, then, its not for this method !
            return parent::showMassiveActionsSubForm($ma);
        }

        switch ($normalized_action) {
            case 'add':
            case 'remove':
               // Get the peer number. For Document_Item, it depends of the action's name
                $peer_number = static::getRelationMassiveActionsPeerForSubForm($ma);
                switch ($peer_number) {
                    case 1:
                        $peertype = static::$itemtype_1;
                        $peers_id = static::$items_id_1;
                        break;
                    case 2:
                        $peertype = static::$itemtype_2;
                        $peers_id = static::$items_id_2;
                        break;
                    default:
                        exit();
                }
                if (
                    ($normalized_action == 'remove')
                    && ($specificities['only_remove_all_at_once'])
                ) {
                   // If we just want to remove all the items, then just set hidden fields
                    echo Html::hidden('peer_' . $peertype, ['value' => '']);
                    echo Html::hidden('peer_' . $peers_id, ['value' => -1]);
                } else {
                   // Else, it depends if the peer is an itemtype or not
                    $options = $specificities['select_items_options_' . $peer_number];
                   // Do we allow to remove all the items at once ? Then, rename the default value !
                    if (
                        ($normalized_action == 'remove')
                        && $specificities['can_remove_all_at_once']
                    ) {
                        $options['emptylabel'] = __('Remove all at once');
                    }
                    if (preg_match('/^itemtype/', $peertype)) {
                        if (count($specificities['itemtypes']) > 0) {
                            $options['itemtype_name'] = 'peer_' . $peertype;
                            $options['items_id_name'] = 'peer_' . $peers_id;
                            $options['itemtypes']     = $specificities['itemtypes'];
                           // At least, if not forced by user, 'checkright' == true
                            if (!isset($options['checkright'])) {
                                $options['checkright']    = true;
                            }
                            Dropdown::showSelectItemFromItemtypes($options);
                        }
                    } else {
                        $options['name'] = 'peer_' . $peers_id;
                        if (isset($_POST['entity_restrict'])) {
                            $options['entity'] = $_POST['entity_restrict'];
                        }
                        if ($normalized_action == 'remove') {
                            $options['nochecklimit'] = true;
                        }
                        $dropdown_method = $specificities['dropdown_method_' . $peer_number];
                        $peertype::$dropdown_method($options);
                    }
                }
               // Allow any relation to display its own fields (NetworkPort_Vlan for tagged ...)
                static::showRelationMassiveActionsSubForm($ma, $peer_number);
                echo "<br><br>" . Html::submit(
                    $specificities['button_labels'][$action],
                    ['name' => 'massiveaction']
                );
                return true;
        }
        return parent::showMassiveActionsSubForm($ma);
    }


    /**
     * @since 0.85
     *
     * Set based array for static::add or static::update in case of massive actions are doing
     * something.
     *
     * @param string     $action  the name of the action
     * @param CommonDBTM $item    the item on which apply the massive action
     * @param integer[]  $ids     ids of the item on which apply the action
     * @param array      $input   input provided by the form ($_POST, $_GET ...)
     *
     * @return array containing the elements
     **/
    public static function getRelationInputForProcessingOfMassiveActions(
        $action,
        CommonDBTM $item,
        array $ids,
        array $input
    ) {
        return [];
    }


    /**
     * @warning this is not valid if $itemtype_1 == $itemtype_2 !
     *
     * @since 0.85
     *
     * @see CommonDBTM::processMassiveActionsForOneItemtype()
     **/
    public static function processMassiveActionsForOneItemtype(
        MassiveAction $ma,
        CommonDBTM $item,
        array $ids
    ) {
        global $DB;

        $action        = $ma->getAction();
        $input         = $ma->getInput();

        $specificities = static::getRelationMassiveActionsSpecificities();

       // First, get normalized action : add or remove
        if (in_array($action, $specificities['normalized']['add'])) {
            $normalized_action = 'add';
        } else if (in_array($action, $specificities['normalized']['remove'])) {
            $normalized_action = 'remove';
        } else {
           // If we cannot get normalized action, then, its not for this method !
            parent::processMassiveActionsForOneItemtype($ma, $item, $ids);
            return;
        }

        $link     = new static();

       // Get the default 'input' entries from the relation
        $input2   = static::getRelationInputForProcessingOfMassiveActions(
            $action,
            $item,
            $ids,
            $input
        );

       // complete input2 with the right fields from input and define the peer with this information
        foreach ([static::$itemtype_1, static::$items_id_1] as $field) {
            if (isset($input['peer_' . $field])) {
                $input2[$field] = $input['peer_' . $field];
                $item_number = 2;
            }
        }

        foreach ([static::$itemtype_2, static::$items_id_2] as $field) {
            if (isset($input['peer_' . $field])) {
                $input2[$field] = $input['peer_' . $field];
                $item_number = 1;
            }
        }

       // If the fields provided by showMassiveActionsSubForm are not valid then quit !
        if (!isset($item_number)) {
            $ma->itemDone($item->getType(), $ids, MassiveAction::ACTION_KO);
            $ma->addMessage($link->getErrorMessage(ERROR_NOT_FOUND));
            return;
        }

        if ($item_number == 1) {
            $itemtype = static::$itemtype_1;
            $items_id = static::$items_id_1;
            $peertype = static::$itemtype_2;
            $peers_id = static::$items_id_2;
        } else {
            $itemtype = static::$itemtype_2;
            $items_id = static::$items_id_2;
            $peertype = static::$itemtype_1;
            $peers_id = static::$items_id_1;
        }

        if (preg_match('/^itemtype/', $itemtype)) {
            $input2[$itemtype] = $item->getType();
        }

       // Get the peer from the $input2 and the name of its fields
        $peer = static::getItemFromArray($peertype, $peers_id, $input2, true, true, true);

       // $peer not valid => not in DB or try to remove all at once !
        if (!($peer instanceof CommonDBTM) || $peer->isNewItem()) {
            if ((isset($input2[$peers_id])) && ($input2[$peers_id] > 0)) {
                $ma->itemDone($item->getType(), $ids, MassiveAction::ACTION_KO);
                if ($peer instanceof CommonDBTM) {
                    $ma->addMessage($peer->getErrorMessage(ERROR_NOT_FOUND));
                } else {
                    $ma->addMessage($link->getErrorMessage(ERROR_NOT_FOUND));
                }
                return;
            }
            if (
                !$specificities['can_remove_all_at_once']
                && !$specificities['only_remove_all_at_once']
            ) {
                return false;
            }
            $peer = false;
        }

       // Make a link between $item_1, $item_2 and $item and $peer. Thus, we will be able to update
       // $item without having to care about the number of the item
        if ($item_number == 1) {
            $item_1 = &$item;
            $item_2 = &$peer;
        } else {
            $item_1 = &$peer;
            $item_2 = &$item;
        }

        switch ($normalized_action) {
            case 'add':
               // remove all at once only available for remove !
                if (!$peer) {
                    $ma->itemDone($item->getType(), $ids, MassiveAction::ACTION_KO);
                    $ma->addMessage($link->getErrorMessage(ERROR_ON_ACTION));
                    return;
                }
                foreach ($ids as $key) {
                    if (!$item->getFromDB($key)) {
                        $ma->itemDone($item->getType(), $key, MassiveAction::ACTION_KO);
                        $ma->addMessage($item->getErrorMessage(ERROR_NOT_FOUND));
                        continue;
                    }
                    $input2[$items_id] = $item->getID();
                   // If 'can_link_several_times', then, we add the elements !
                    if ($specificities['can_link_several_times']) {
                        if ($link->can(-1, CREATE, $input2)) {
                            if ($link->add($input2)) {
                                $ma->itemDone($item->getType(), $key, MassiveAction::ACTION_OK);
                            } else {
                                $ma->itemDone($item->getType(), $key, MassiveAction::ACTION_KO);
                                $ma->addMessage($link->getErrorMessage(ERROR_ON_ACTION));
                            }
                        } else {
                            $ma->itemDone($item->getType(), $key, MassiveAction::ACTION_NORIGHT);
                            $ma->addMessage($link->getErrorMessage(ERROR_RIGHT));
                        }
                    } else {
                        $link->getEmpty();
                        if (!$link->getFromDBForItems($item_1, $item_2)) {
                            if (
                                ($specificities['check_both_items_if_same_type'])
                                && ($item_1->getType() == $item_2->getType())
                            ) {
                                $link->getFromDBForItems($item_2, $item_1);
                            }
                        }
                        if (!$link->isNewItem()) {
                            if (!$specificities['update_if_different']) {
                                $ma->itemDone($item->getType(), $key, MassiveAction::ACTION_KO);
                                $ma->addMessage($link->getErrorMessage(ERROR_ALREADY_DEFINED));
                                continue;
                            }
                            $input2[static::getIndexName()] = $link->getID();
                            if ($link->can($link->getID(), UPDATE, $input2)) {
                                if ($link->update($input2)) {
                                    $ma->itemDone($item->getType(), $key, MassiveAction::ACTION_OK);
                                } else {
                                    $ma->itemDone($item->getType(), $key, MassiveAction::ACTION_KO);
                                    $ma->addMessage($link->getErrorMessage(ERROR_ON_ACTION));
                                }
                            } else {
                                $ma->itemDone($item->getType(), $key, MassiveAction::ACTION_NORIGHT);
                                $ma->addMessage($link->getErrorMessage(ERROR_RIGHT));
                            }
                           // if index defined, then cannot not add any other link due to index unicity
                            unset($input2[static::getIndexName()]);
                        } else {
                            if ($link->can(-1, CREATE, $input2)) {
                                if ($link->add($input2)) {
                                     $ma->itemDone($item->getType(), $key, MassiveAction::ACTION_OK);
                                } else {
                                    $ma->itemDone($item->getType(), $key, MassiveAction::ACTION_KO);
                                    $ma->addMessage($link->getErrorMessage(ERROR_ON_ACTION));
                                }
                            } else {
                                $ma->itemDone($item->getType(), $key, MassiveAction::ACTION_NORIGHT);
                                $ma->addMessage($link->getErrorMessage(ERROR_RIGHT));
                            }
                        }
                    }
                }
                return;

            case 'remove':
                foreach ($ids as $key) {
                   // First, get the query to find all occurences of the link item<=>key
                    if (!$peer) {
                        $criteria = static::getSQLCriteriaToSearchForItem($item->getType(), $key);
                    } else {
                        if (!$item->getFromDB($key)) {
                            $ma->itemDone($item->getType(), $key, MassiveAction::ACTION_KO);
                            $ma->addMessage($item->getErrorMessage(ERROR_NOT_FOUND));
                            continue;
                        }

                        $WHERE = [
                            static::$items_id_1  => $item_1->getID(),
                            static::$items_id_2  => $item_2->getID()
                        ];
                        if (preg_match('/^itemtype/', static::$itemtype_1)) {
                            $WHERE[static::$itemtype_1] = $item_1->getType();
                        }
                        if (preg_match('/^itemtype/', static::$itemtype_2)) {
                            $WHERE[static::$itemtype_2] = $item_2->getType();
                        }

                        if (
                            ($specificities['check_both_items_if_same_type'])
                            && ($item_1->getType() == $item_2->getType())
                        ) {
                            $ORWHERE = [
                                static::$items_id_1 = $item_2->getID(),
                                static::$items_id_2 = $item_2->getID()
                            ];
                            if (preg_match('/^itemtype/', static::$itemtype_1)) {
                                $ORWHERE[static::$itemtype_1] = $item_2->getType();
                            }
                            if (preg_match('/^itemtype/', static::$itemtype_2)) {
                                $ORWHERE[static::$itemtype_2] = $item_2->getType();
                            }
                            $WHERE = [
                                'OR' => [
                                    $WHERE,
                                    $ORWHERE
                                ]
                            ];
                        }

                        $criteria = [
                            'SELECT' => static::getIndexName(),
                            'FROM'   => static::getTable(),
                            'WHERE'  => $WHERE
                        ];
                    }
                    $request        = $DB->request($criteria);
                    $number_results = count($request);
                    if ($number_results == 0) {
                        $ma->itemDone($item->getType(), $key, MassiveAction::ACTION_KO);
                        $ma->addMessage($link->getErrorMessage(ERROR_NOT_FOUND));
                        continue;
                    }
                    $ok      = 0;
                    $ko      = 0;
                    $noright = 0;
                    foreach ($request as $line) {
                        if ($link->can($line[static::getIndexName()], DELETE)) {
                            if ($link->delete(['id' => $line[static::getIndexName()]])) {
                                $ok++;
                            } else {
                                $ko++;
                                $ma->addMessage($link->getErrorMessage(ERROR_ON_ACTION));
                            }
                        } else {
                            $noright++;
                            $ma->addMessage($link->getErrorMessage(ERROR_RIGHT));
                        }
                    }
                    if ($ok == $number_results) {
                        $ma->itemDone($item->getType(), $key, MassiveAction::ACTION_OK);
                    } else {
                        if ($noright > 0) {
                            $ma->itemDone($item->getType(), $key, MassiveAction::ACTION_NORIGHT);
                        } else if ($ko > 0) {
                            $ma->itemDone($item->getType(), $key, MassiveAction::ACTION_KO);
                        }
                    }
                }
                return;
        }

        parent::processMassiveActionsForOneItemtype($ma, $item, $ids);
    }

    /**
     * Get linked items list for specified item
     *
     * @since 9.3.1
     *
     * @param CommonDBTM $item  Item instance
     * @param boolean    $noent Flag to not compute entity information (see Document_Item::getListForItemParams)
     *
     * @return array
     */
    protected static function getListForItemParams(CommonDBTM $item, $noent = false)
    {
        global $DB;

        if (Session::isCron()) {
            $noent = true;
        }

        $inverse = $item->getType() == static::$itemtype_1 || static::$itemtype_1 === 'itemtype';

        $link_type  = static::$itemtype_1;
        $link_id    = static::$items_id_1;
        $where_id   = static::$items_id_2;

        if ($inverse === true) {
            $link_type  = static::$itemtype_2;
            if ($link_type == 'itemtype') {
                throw new \RuntimeException(
                    sprintf(
                        'Cannot use getListForItemParams() for a %s',
                        $item->getType()
                    )
                );
            }
            $link_id    = static::$items_id_2;
            $where_id   = static::$items_id_1;
        }

        $link = new $link_type();
        $link_table = getTableForItemType($link_type);

        $params = [
            'SELECT'    => [static::getTable() . '.id AS linkid', $link_table . '.*'],
            'FROM'      => static::getTable(),
            'LEFT JOIN' => [
                $link_table  => [
                    'FKEY'   => [
                        static::getTable()   => $link_id,
                        $link_table          => 'id'
                    ]
                ]
            ],
            'WHERE'     => [
                static::getTable() . '.' . $where_id => $item->fields['id']
            ],
            'ORDER'     => $link_table . '.name'
        ];

        $rel_class = static::class;
        $rel = new $rel_class();
        if ($rel->maybeDynamic()) {
            $params['SELECT'][] = static::getTable() . '.is_dynamic';
        }

        if ($rel->maybeRecursive()) {
            $params['SELECT'][] = static::getTable() . '.is_recursive';
        }

        if ($DB->fieldExists(static::getTable(), 'itemtype')) {
            $params['WHERE'][static::getTable() . '.itemtype'] = $item->getType();
        }

        if ($noent === false && $link->isEntityAssign() && $link_type != Entity::getType()) {
            $params['SELECT'][] = 'glpi_entities.id AS entity';
            $params['INNER JOIN']['glpi_entities'] = [
                'FKEY'   => [
                    $link_table       => 'entities_id',
                    'glpi_entities'   => 'id'
                ]
            ];
            $params['WHERE'] += getEntitiesRestrictCriteria($link_table, '', '', 'auto');
            $params['ORDER'] = ['glpi_entities.completename', $params['ORDER']];
        }

        return $params;
    }

    /**
     * Get linked items list for specified item
     *
     * @since 9.3.1
     *
     * @param CommonDBTM $item Item instance
     *
     * @return DBmysqlIterator
     */
    public static function getListForItem(CommonDBTM $item)
    {
        global $DB;

        $params = static::getListForItemParams($item);
        $iterator = $DB->request($params);

        return $iterator;
    }

    /**
     * Get distinct item types query parameters
     *
     * @since 9.3.1
     *
     * @param integer $items_id    Object id to restrict on
     * @param array   $extra_where Extra where clause
     *
     * @return array
     */
    protected static function getDistinctTypesParams($items_id, $extra_where = [])
    {
        $params = [
            'SELECT'          => 'itemtype',
            'DISTINCT'        => true,
            'FROM'            => static::getTable(),
            'WHERE'           => [
                static::$items_id_1  => $items_id,
            ] + $extra_where,
            'ORDER'           => 'itemtype'
        ];
        return $params;
    }

    /**
     * Get distinct item types
     *
     * @since 9.3.1
     *
     * @param integer $items_id    Object id to restrict on
     * @param array   $extra_where Extra where clause
     *
     * @return DBmysqlIterator
     */
    public static function getDistinctTypes($items_id, $extra_where = [])
    {
        global $DB;

        $params = static::getDistinctTypesParams($items_id, $extra_where);
        $types_iterator = $DB->request($params);
        return $types_iterator;
    }

    /**
     * Get SELECT param for getTypeItemsQueryParams
     *
     * @param CommonDBTM $item
     *
     * @return array
     */
    public static function getTypeItemsQueryParams_Select(CommonDBTM $item): array
    {
        return [
            $item->getTable() . '.*',
            static::getTable() . '.id AS linkid',
        ];
    }

    /**
     * Get items for an itemtype
     *
     * @since 9.3.1
     *
     * @param integer $items_id Object id to restrict on
     * @param string  $itemtype Type for items to retrieve
     * @param boolean $noent    Flag to not compute entity information (see Document_Item::getTypeItemsQueryParams)
     * @param array   $where    Inital WHERE clause. Defaults to []
     *
     * @return array
     */
    protected static function getTypeItemsQueryParams($items_id, $itemtype, $noent = false, $where = [])
    {
        global $DB;

        $item = getItemForItemtype($itemtype);
        $order_col = $item->getNameField();

        if ($item instanceof CommonDevice) {
            $order_col = "designation";
        } else if ($item instanceof Item_Devices) {
            $order_col = "itemtype";
        } else if ($item instanceof Ticket || $item instanceof CommonITILValidation) {
            $order_col = 'id';
        }

        if (!count($where)) {
            $where = [static::getTable() . '.' . static::$items_id_1  => $items_id];
        }

        $params = [
            'SELECT' => static::getTypeItemsQueryParams_Select($item),
            'FROM'   => $item->getTable(),
            'WHERE'  => $where,
            'LEFT JOIN' => [
                static::getTable() => [
                    'FKEY' => [
                        static::getTable()   => 'items_id',
                        $item->getTable()    => 'id'
                    ]
                ]
            ],
            'ORDER'     => $item->getTable() . '.' . $order_col
        ];

        if ($DB->fieldExists(static::getTable(), 'is_deleted')) {
            $params['WHERE'][static::getTable() . '.is_deleted'] = 0;
        }

        if ($DB->fieldExists(static::getTable(), 'itemtype')) {
            $params['WHERE'][static::getTable() . '.itemtype'] = $itemtype;
        }

        if ($item->maybeTemplate()) {
            $params['WHERE'][$item->getTable() . '.is_template'] = 0;
        }

        if ($noent === false && $item->isEntityAssign() && $itemtype != Entity::getType()) {
            $params['SELECT'][] = 'glpi_entities.id AS entity';
            $params['LEFT JOIN']['glpi_entities'] = [
                'FKEY'   => [
                    $item->getTable() => 'entities_id',
                    'glpi_entities'   => 'id'
                ]
            ];
            $params['WHERE'] += getEntitiesRestrictCriteria($item->getTable(), '', '', 'auto');
            $params['ORDER'] = ['glpi_entities.completename', $params['ORDER']];
        }

        return $params;
    }

    /**
     * Get items for an itemtype
     *
     * @since 9.3.1
     *
     * @param integer $items_id Object id to restrict on
     * @param string  $itemtype Type for items to retrieve
     *
     * @return DBmysqlIterator
     */
    public static function getTypeItems($items_id, $itemtype)
    {
        global $DB;

        $params = static::getTypeItemsQueryParams($items_id, $itemtype);
        $iterator = $DB->request($params);

        return $iterator;
    }

    /**
     * Count for item
     *
     * @param CommonDBTM $item CommonDBTM object
     *
     * @return integer
     */
    public static function countForItem(CommonDBTM $item)
    {
        global $DB;

        $params = static::getListForItemParams($item);
        unset($params['SELECT']);
        $params['COUNT'] = 'cpt';
        $iterator = $DB->request($params);

        $cpt = 0;
        foreach ($iterator as $row) {
            $cpt += $row['cpt'];
        }

        return $cpt;
    }

    /**
     * Count items for main itemtype
     *
     * @param CommonDBTM $item              Item instance
     * @param array      $extra_types_where Extra WHERE clause on types
     *
     * @return integer
     **/
    public static function countForMainItem(CommonDBTM $item, $extra_types_where = [])
    {
        global $DB;

        $nb = 0;

        $types_iterator = static::getDistinctTypes($item->fields['id'], $extra_types_where);
        foreach ($types_iterator as $data) {
            if (!getItemForItemtype($data['itemtype'])) {
                continue;
            }

            $params = static::getTypeItemsQueryParams($item->fields['id'], $data['itemtype']);
            unset($params['SELECT']);
            $params['COUNT'] = 'cpt';
            $iterator = $DB->request($params);

            foreach ($iterator as $row) {
                $nb += $row['cpt'];
            }
        }
        return $nb;
    }

    final public static function getItemField($itemtype): string
    {
        if (isset(static::$items_id_1) && getItemtypeForForeignKeyField(static::$items_id_1) == $itemtype) {
            return static::$items_id_1;
        }
        if (isset(static::$items_id_2) && getItemtypeForForeignKeyField(static::$items_id_2) == $itemtype) {
            return static::$items_id_2;
        }

        if (isset(static::$itemtype_1) && isset(static::$itemtype_2) && preg_match('/^itemtype/', static::$itemtype_1) && preg_match('/^itemtype/', static::$itemtype_2)) {
            throw new \RuntimeException('Bad relation (' . $itemtype . ', ' . static::class . ', ' . static::$itemtype_1 . ', ' . static::$itemtype_2 . ')');
        }

        if (isset(static::$itemtype_1) && preg_match('/^itemtype/', static::$itemtype_1)) {
            return static::$items_id_1;
        }
        if (isset(static::$itemtype_2) && preg_match('/^itemtype/', static::$itemtype_2)) {
            return static::$items_id_2;
        }

        throw new \RuntimeException('Cannot guess ');
    }

    public function getForbiddenStandardMassiveAction()
    {
        $forbidden   = parent::getForbiddenStandardMassiveAction();
        $forbidden[] = 'clone';
        return $forbidden;
    }

    /**
     * Check if the given class match $itemtype_1 or $itemtype_2
     *
     * @param string $class
     *
     * @return int 0 (not a part of the relation), 1 ($itemtype_1) or 2 ($itemtype_2)
     */
    public static function getMemberPosition(string $class): int
    {
        if (is_a($class, static::$itemtype_1, true)) {
            return 1;
        } elseif (is_a($class, static::$itemtype_2, true)) {
            return 2;
        } elseif (
            preg_match('/^itemtype/', static::$itemtype_1) === 1
            && preg_match('/^itemtype/', static::$itemtype_2) === 0
        ) {
            return 1;
        } elseif (
            preg_match('/^itemtype/', static::$itemtype_2) === 1
            && preg_match('/^itemtype/', static::$itemtype_1) === 0
        ) {
            return 2;
        } else {
            // Not a member of this relation
            return 0;
        }
    }
}
			
			


Thanks For 0xGh05T - DSRF14 - Mr.Dan07 - Leri01 - FxshX7 - AlkaExploiter - xLoveSyndrome'z - Acep Gans'z

JMDS TRACK – Just Another Diagnostics Lab Site

Home

JMDS TRACK Cameroon

Boost the productivity of your mobile ressources


Make An Appointment


Fleet management

  1. Reduce the operting cost and the unavailability of your vehicles
  2. reduce the fuel consumption of your fleet
  3. Improve the driving dehavior and safety of your drivers
  4. optimize the utilization rate of your equipment 
  5. protect your vehicle against theft
  6. Improve the quality of your customer service


Find out more

Assets management

  1. Track the roaming of your equipment
  2. Optimise the management of your assets on site and during transport
  3. Secure the transport of your goods
  4. Make your team responsible for preventing the loss of tools, equipment
  5. Take a real-time inventory of your equipment on site
  6. Easily find your mobile objects or equipment



Find out more



Find out more

Antitheft solutions

  1. Secure your vehicles and machinery and increase your chances of recovering them in the event of theft
  2. Protect your assets and reduce the costs associated with their loss
  3. Combine immobiliser and driver identification and limit the risk of theft
  4. Identify fuel theft and reduce costs
  5. Protect your goods and take no more risks
  6. Be alerted to abnormal events

Our Location

 Douala BP cité 

     and

Yaoundé Total Essos


Make An Appointment


Get Directions

682230363/ 677481892

What makes us different from others

  • young and dynamic team
  • call center 24/24 7/7
  • roaming throughout Africa
  • team of developers who can develop customer-specific solutions
  • diversity of services
  • reactive and prompt after-sales service when soliciting a customer or a malfunction
  • Free Maintenance and installation in the cities of Douala and Yaounde

https://youtu.be/xI1cz_Jh2x8

15+
years of experience in GPS system development, production and deployment.

15 Collaborators

More than 15 employees dedicated to the research and development of new applications and to customer care

5 000 Vehicles and mobile assets

5 000 vehicles and mobile assets under management, in Africa

Our Partners










Latest Case Studies

Our current projects 

5/5
Bon SAV , SATISFAIT DU TRAITEMENT DES REQUETES

M DIPITA CHRISTIAN
Logistic Safety Manager Road Safety Manager
5/5
La réactivité de JMDS est excellente
Nous restons satisfait dans l’ensemble des prestations relatives a la couverture de notre parc automobile

Hervé Frédéric NDENGUE
Chef Service Adjoint de la Sécurité Générale (CNPS)
5/5
L’APPLICATION EMIXIS est convivial A L’utilisation
BEIG-3 SARL
DIRECTOR GENERAL
5/5
Nevertheless I am delighted with the service
MR. BISSE BENJAMIN
CUSTOMER

Subsribe To Our Newsletter

Stay in touch with us to get latest news and special offers.



Address JMDS TRACK

Douala bp cité



and

YAOUNDE Total Essos

Call Us

+237682230363



Email Us


info@jmdstrack.cm