%PDF- %PDF-
Direktori : /var/www/projetos/suporte.iigd.com.br/src/ |
Current File : /var/www/projetos/suporte.iigd.com.br/src/CommonDBChild.php |
<?php /** * --------------------------------------------------------------------- * * GLPI - Gestionnaire Libre de Parc Informatique * * http://glpi-project.org * * @copyright 2015-2024 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/>. * * --------------------------------------------------------------------- */ use Glpi\Plugin\Hooks; /// Common DataBase Relation Table Manager Class abstract class CommonDBChild extends CommonDBConnexity { // Mapping between DB fields // * definition public static $itemtype; // Class name or field name (start with itemtype) for link to Parent public static $items_id; // Field name // * rights public static $checkParentRights = self::HAVE_SAME_RIGHT_ON_ITEM; public static $mustBeAttached = true; // * log public static $logs_for_parent = true; public static $log_history_add = Log::HISTORY_ADD_SUBITEM; public static $log_history_update = Log::HISTORY_UPDATE_SUBITEM; public static $log_history_delete = Log::HISTORY_DELETE_SUBITEM; public static $log_history_lock = Log::HISTORY_LOCK_SUBITEM; public static $log_history_unlock = Log::HISTORY_UNLOCK_SUBITEM; /** * 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) { $table = static::getTable(); $criteria = [ 'SELECT' => [ static::getIndexName(), static::$items_id . ' AS items_id' ], 'FROM' => $table, 'WHERE' => [ $table . '.' . static::$items_id => $items_id ] ]; // Check item 1 type $request = false; if (preg_match('/^itemtype/', static::$itemtype)) { $criteria['SELECT'][] = static::$itemtype . ' AS itemtype'; $criteria['WHERE'][$table . '.' . static::$itemtype] = $itemtype; $request = true; } else { $criteria['SELECT'][] = new \QueryExpression("'" . static::$itemtype . "' AS itemtype"); if ( ($itemtype == static::$itemtype) || is_subclass_of($itemtype, static::$itemtype) ) { $request = true; } } if ($request === true) { return $criteria; } return null; } /** * @since 0.84 **/ public static function canCreate() { if ((static::$rightname) && (!Session::haveRight(static::$rightname, CREATE))) { return false; } return static::canChild('canUpdate'); } /** * @since 0.84 **/ public static function canView() { if ((static::$rightname) && (!Session::haveRight(static::$rightname, READ))) { return false; } return static::canChild('canView'); } /** * @since 0.84 **/ public static function canUpdate() { if ((static::$rightname) && (!Session::haveRight(static::$rightname, UPDATE))) { return false; } return static::canChild('canUpdate'); } /** * @since 0.84 **/ public static function canDelete() { if ((static::$rightname) && (!Session::haveRight(static::$rightname, DELETE))) { return false; } return static::canChild('canUpdate'); } /** * @since 0.85 **/ public static function canPurge() { if ((static::$rightname) && (!Session::haveRight(static::$rightname, PURGE))) { return false; } return static::canChild('canUpdate'); } /** * @since 0.84 **/ public function canCreateItem() { return $this->canChildItem('canUpdateItem', 'canUpdate'); } /** * @since 0.84 **/ public function canViewItem() { return $this->canChildItem('canViewItem', 'canView'); } /** * @since 0.84 **/ public function canUpdateItem() { return $this->canChildItem('canUpdateItem', 'canUpdate'); } /** * @since 0.84 **/ public function canDeleteItem() { return $this->canChildItem('canUpdateItem', 'canUpdate'); } /** * @since 0.84 * * @param $method **/ public static function canChild($method) { return static::canConnexity( $method, static::$checkParentRights, static::$itemtype, static::$items_id ); } /** * @since 0.84 * * @param $methodItem * @param $methodNotItem * * @return boolean **/ public function canChildItem($methodItem, $methodNotItem) { try { return $this->canConnexityItem( $methodItem, $methodNotItem, static::$checkParentRights, static::$itemtype, static::$items_id ); } catch (CommonDBConnexityItemNotFound $e) { return !static::$mustBeAttached; } } /** * Get the item associated with the current object. Rely on CommonDBConnexity::getItemFromArray() * * @since 0.84 * * @param $getFromDB (true by default) * @param $getEmpty (true by default) * * @return object of the concerned item or false on error **/ public function getItem($getFromDB = true, $getEmpty = true) { return $this->getConnexityItem( static::$itemtype, static::$items_id, $getFromDB, $getEmpty ); } /** * \brief recursively display the items of this * * @param array $recursiveItems items of the current elements (see recursivelyGetItems()) * @param string $elementToDisplay what to display : 'Type', 'Name', 'Link' * @param bool $display display html or return html **/ public static function displayRecursiveItems(array $recursiveItems, $elementToDisplay, bool $display = true) { if ((!is_array($recursiveItems)) || (count($recursiveItems) == 0)) { echo __('Item not linked to an object'); return; } switch ($elementToDisplay) { case 'Type': $masterItem = $recursiveItems[count($recursiveItems) - 1]; if ($display) { echo $masterItem->getTypeName(1); } else { return $masterItem->getTypeName(1); } break; case 'Name': case 'Link': $items_elements = []; foreach ($recursiveItems as $item) { if ($elementToDisplay == 'Name') { $items_elements[] = $item->getName(); } else { $items_elements[] = $item->getLink(); } } if ($display) { echo implode(' < ', $items_elements); } else { return implode(' < ', $items_elements); } break; } } /** * Get all the items associated with the current object by recursive requests * * @since 0.84 * * @return array **/ public function recursivelyGetItems() { $item = $this->getItem(); if ($item !== false) { if ($item instanceof CommonDBChild) { return array_merge([$item], $item->recursivelyGetItems()); } return [$item]; } return []; } /** * Get the ID of entity assigned to the object * * @return integer ID of the entity **/ public function getEntityID() { // Case of Duplicate Entity info to child if (parent::isEntityAssign()) { return parent::getEntityID(); } $item = $this->getItem(); if (($item !== false) && ($item->isEntityAssign())) { return $item->getEntityID(); } return -1; } public function isEntityAssign() { // Case of Duplicate Entity info to child if (parent::isEntityAssign()) { return true; } $item = $this->getItem(false); if ($item !== false) { return $item->isEntityAssign(); } return false; } /** * Is the object may be recursive * * @return boolean **/ public function maybeRecursive() { // Case of Duplicate Entity info to child if (parent::maybeRecursive()) { return true; } $item = $this->getItem(false); if ($item !== false) { return $item->maybeRecursive(); } return false; } /** * Is the object recursive * * @return boolean **/ public function isRecursive() { // Case of Duplicate Entity info to child if (parent::maybeRecursive()) { return parent::isRecursive(); } $item = $this->getItem(); if ($item !== false) { return $item->isRecursive(); } return false; } 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); // Set the item to allow parent::prepareinputforadd to get the right item ... if ( $itemToGetEntity = static::getItemFromArray( static::$itemtype, static::$items_id, $completeinput ) ) { 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'] = 0; $input['is_recursive'] = 0; } } } return $input; } public function prepareInputForAdd($input) { if (!is_array($input)) { return false; } // Check item exists if ( static::$mustBeAttached && !$this->getItemFromArray(static::$itemtype, static::$items_id, $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, static::$items_id ]) ) { return false; } return parent::addNeededInfoToInput($input); } /** * Get the history name of item * * @param CommonDBTM $item the other item * @param string $case : can be overwrite by object * - 'add' when this CommonDBChild 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 CommonDBChild is remove (from an item) * * @return string the name of the entry for the database (ie. : correctly slashed) **/ public function getHistoryNameForItem(CommonDBTM $item, $case) { return $this->getNameID(['forceid' => true, 'additional' => true ]); } /** * Actions done after the ADD of the item in the database * * @return void **/ public function post_addItem() { $item = $this->getItem(); if ($item === false) { return; } if ( $item->dohistory && !(isset($this->input['_no_history']) && $this->input['_no_history']) && static::$logs_for_parent ) { $changes = [ '0', '', $this->getHistoryNameForItem($item, 'add'), ]; Log::history( $item->getID(), $item->getType(), $changes, $this->getType(), static::$log_history_add ); } parent::post_addItem(); } /** * Actions done after the UPDATE of the item in the database * * @since 0.84 * * @param integer|boolean $history store changes history ? * * @return void **/ public function post_updateItem($history = true) { if ( !((isset($this->input['_no_history']) && $this->input['_no_history'])) && static::$logs_for_parent ) { $items_for_log = $this->getItemsForLog(static::$itemtype, static::$items_id); // Whatever case : we log the changes $oldvalues = $this->oldvalues; unset($oldvalues[static::$itemtype]); unset($oldvalues[static::$items_id]); $item = $items_for_log['new']; if ( ($item !== false) && $item->dohistory ) { foreach (array_keys($oldvalues) as $field) { if (in_array($field, $this->getNonLoggedFields())) { continue; } $changes = $this->getHistoryChangeWhenUpdateField($field); if ((!is_array($changes)) || (count($changes) != 3)) { continue; } Log::history( $item->getID(), $item->getType(), $changes, $this->getType(), static::$log_history_update ); } } if (isset($items_for_log['previous'])) { // Have updated the connexity relation $prevItem = $items_for_log['previous']; $newItem = $items_for_log['new']; if ( ($prevItem !== false) && $prevItem->dohistory ) { $changes[0] = '0'; $changes[1] = addslashes($this->getHistoryNameForItem($prevItem, 'update item previous')); $changes[2] = ''; Log::history( $prevItem->getID(), $prevItem->getType(), $changes, $this->getType(), static::$log_history_delete ); } if ( ($newItem !== false) && $newItem->dohistory ) { $changes[0] = '0'; $changes[1] = ''; $changes[2] = addslashes($this->getHistoryNameForItem($newItem, 'update item next')); Log::history( $newItem->getID(), $newItem->getType(), $changes, $this->getType(), static::$log_history_add ); } } } parent::post_updateItem($history); } /** * Actions done after the DELETE of the item in the database * * @return void **/ public function post_deleteFromDB() { if ( (isset($this->input['_no_history']) && $this->input['_no_history']) || !static::$logs_for_parent ) { return; } $item = $this->getItem(); if ( ($item !== false) && $item->dohistory ) { $changes = [ '0', ]; if (static::$log_history_delete == Log::HISTORY_LOG_SIMPLE_MESSAGE) { $changes[1] = ''; $changes[2] = addslashes($this->getHistoryNameForItem($item, 'delete')); } else { $changes[1] = addslashes($this->getHistoryNameForItem($item, 'delete')); $changes[2] = ''; } Log::history( $item->getID(), $item->getType(), $changes, $this->getType(), static::$log_history_delete ); } } /** * Actions done when item flag deleted is set to an item * * @since 0.84 * * @return void **/ public function cleanDBonMarkDeleted() { if ( (isset($this->input['_no_history']) && $this->input['_no_history']) || !static::$logs_for_parent ) { return; } if ( $this->useDeletedToLockIfDynamic() && $this->isDynamic() ) { $item = $this->getItem(); if ( ($item !== false) && $item->dohistory ) { $changes = [ '0', addslashes($this->getHistoryNameForItem($item, 'lock')), '', ]; Log::history( $item->getID(), $item->getType(), $changes, $this->getType(), static::$log_history_lock ); } } } /** * Actions done after the restore of the item * * @since 0.84 * * @return void **/ public function post_restoreItem() { if ( (isset($this->input['_no_history']) && $this->input['_no_history']) || !static::$logs_for_parent ) { return; } if ( $this->useDeletedToLockIfDynamic() && $this->isDynamic() ) { $item = $this->getItem(); if ( ($item !== false) && $item->dohistory ) { $changes = [ '0', '', addslashes($this->getHistoryNameForItem($item, 'unlock')), ]; Log::history( $item->getID(), $item->getType(), $changes, $this->getType(), static::$log_history_unlock ); } } } /** * get the Javascript "code" to add to the form when clicking on "+" * * @since 0.84 * * @see showAddChildButtonForItemForm() * * @param string $field_name the name of the HTML field inside Item's form * @param string $child_count_js_var the name of the javascript variable containing current child * number of items * * @return string **/ public static function getJSCodeToAddForItemChild($field_name, $child_count_js_var) { return "<input type=\'text\' size=\'40\' " . "name=\'" . $field_name . "[-'+$child_count_js_var+']\'>"; } /** * display the field of a given child * * @since 0.84 * * @see showChildsForItemForm() * * @param boolean $canedit true if we can edit the child * @param string $field_name the name of the HTML field inside Item's form * @param integer $id id of the child * * @return string|void **/ public function showChildForItemForm($canedit, $field_name, $id, bool $display = true) { if ($this->isNewID($this->getID())) { $value = ''; } else { $value = $this->getName(); } $field_name = $field_name . "[$id]"; if ($canedit) { $out = "<input type='text' size='40' name='$field_name' value='$value' class='form-select'>"; } else { $out = "<input type='hidden' name='$field_name' value='$value'>$value"; } if ($display) { echo $out; } else { return $out; } } /** * We can add several single CommonDBChild to a given Item. In such case, we display a "+" * button and the fields already entered * This method display the "+" button * * @since 0.84 * * @todo study if we cannot use these methods for the user emails * @see showChildsForItemForm(CommonDBTM $item, $field_name) * * @param CommonDBTM $item the item on which to add the current CommenDBChild * @param string $field_name the name of the HTML field inside Item's form * @param boolean|null $canedit boolean to force rights, NULL to use default behaviour * @param boolean $display true display or false to return the button HTML code * * * @return void|false|string the button HTML code if $display is true, void otherwise **/ public static function showAddChildButtonForItemForm( CommonDBTM $item, $field_name, $canedit = null, $display = true ) { $items_id = $item->getID(); if (is_null($canedit)) { if ($item->isNewItem()) { if (!$item->canCreate()) { return false; } $canedit = $item->canUpdate(); } else { if (!$item->can($items_id, READ)) { return false; } $canedit = $item->can($items_id, UPDATE); } } $result = ''; if ($canedit) { $lower_name = strtolower(get_called_class()); $child_count_js_var = 'nb' . $lower_name . 's'; $div_id = "add_" . $lower_name . "_to_" . $item->getType() . "_" . $items_id; // Beware : -1 is for the first element added ... $result = " <script type='text/javascript'>var $child_count_js_var=2; </script>"; $result .= "<span id='add" . $lower_name . "button' class='fa fa-plus pointer'" . " title=\"" . __s('Add') . "\"" . "\" onClick=\"var row = " . Html::jsGetElementByID($div_id) . "; row.append('<br>" . static::getJSCodeToAddForItemChild($field_name, $child_count_js_var) . "'); $child_count_js_var++;\" ><span class='sr-only'>" . __s('Add') . "</span></span>"; } if ($display) { echo $result; } else { return $result; } } /** * We can add several single CommonDBChild to a given Item. In such case, we display a "+" * button and the fields already entered. * This method display the fields * * @since 0.84 * * @todo study if we cannot use these methods for the user emails * @see showAddChildButtonForItemForm() * * @param CommonDBTM $item the item on which to add the current CommenDBChild * @param string $field_name the name of the HTML field inside Item's form * @param boolean|null $canedit boolean to force rights, NULL to use default behaviour * * @return void|boolean (display) Returns false if there is a rights error. **/ public static function showChildsForItemForm(CommonDBTM $item, $field_name, $canedit = null, bool $display = true) { /** @var \DBmysql $DB */ global $DB; $items_id = $item->getID(); $result = ''; if (is_null($canedit)) { if ($item->isNewItem()) { if (!$item->canCreate()) { return false; } $canedit = $item->canUpdate(); } else { if (!$item->can($items_id, READ)) { return false; } $canedit = $item->can($items_id, UPDATE); } } $lower_name = strtolower(get_called_class()); $div_id = "add_" . $lower_name . "_to_" . $item->getType() . "_" . $items_id; $query = [ 'FROM' => static::getTable(), 'WHERE' => [ static::$items_id => $item->getID() ] ]; if (preg_match('/^itemtype/', static::$itemtype)) { $query['WHERE']['itemtype'] = $item->getType(); } $current_item = new static(); if ($current_item->maybeDeleted()) { $query['WHERE']['is_deleted'] = 0; } $iterator = $DB->request($query); $count = 0; foreach ($iterator as $data) { $current_item->fields = $data; if ($count) { $result .= '<br>'; } $count++; $result .= $current_item->showChildForItemForm($canedit, $field_name, $current_item->getID(), false); } if ($canedit) { $result .= "<div id='$div_id'>"; // No Child display field if ($count == 0) { $current_item->getEmpty(); $result .= $current_item->showChildForItemForm($canedit, $field_name, -1, false); } $result .= "</div>"; } if ($display) { echo $result; } else { return $result; } } /** * Affect a CommonDBChild to a given item. By default, unaffect it * * @param $id integer the id of the CommonDBChild to affect * @param $items_id integer the id of the new item (default 0) * @param $itemtype string the type of the new item (default '') * * @return boolean : true on success **/ public function affectChild($id, $items_id = 0, $itemtype = '') { $input = [static::getIndexName() => $id, static::$items_id => $items_id ]; if (preg_match('/^itemtype/', static::$itemtype)) { $input[static::$itemtype] = $itemtype; } return $this->update($input); } final public static function getItemField($itemtype): string { if (is_subclass_of($itemtype, 'Rule')) { $itemtype = 'Rule'; } if (isset(static::$items_id) && getItemtypeForForeignKeyField(static::$items_id) == $itemtype) { return static::$items_id; } if (isset(static::$itemtype) && preg_match('/^itemtype/', static::$itemtype)) { return static::$items_id; } throw new \RuntimeException('Cannot guess field for itemtype ' . $itemtype . ' on ' . static::class); } protected function autoinventoryInformation() { echo "<td>" . __('Automatic inventory') . "</td>"; echo "<td>"; if ($this->fields['id'] && $this->fields['is_dynamic']) { ob_start(); Plugin::doHook(Hooks::AUTOINVENTORY_INFORMATION, $this); $info = ob_get_clean(); if (empty($info)) { $info = __('Yes'); } echo $info; } else { echo __('No'); } echo "</td>"; } }