921 lines
29 KiB
PHP
921 lines
29 KiB
PHP
<?php
|
|
/**
|
|
* ---------------------------------------------------------------------
|
|
* GLPI - Gestionnaire Libre de Parc Informatique
|
|
* Copyright (C) 2015-2020 Teclib' and contributors.
|
|
*
|
|
* http://glpi-project.org
|
|
*
|
|
* based on GLPI - Gestionnaire Libre de Parc Informatique
|
|
* Copyright (C) 2003-2014 by the INDEPNET Development Team.
|
|
*
|
|
* ---------------------------------------------------------------------
|
|
*
|
|
* LICENSE
|
|
*
|
|
* This file is part of GLPI.
|
|
*
|
|
* GLPI is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* GLPI is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with GLPI. If not, see <http://www.gnu.org/licenses/>.
|
|
* ---------------------------------------------------------------------
|
|
*/
|
|
|
|
if (!defined('GLPI_ROOT')) {
|
|
die("Sorry. You can't access this file directly");
|
|
}
|
|
|
|
/**
|
|
* CommonTreeDropdown Class
|
|
*
|
|
* Hierarchical and cross entities
|
|
**/
|
|
abstract class CommonTreeDropdown extends CommonDropdown {
|
|
|
|
public $can_be_translated = false;
|
|
|
|
|
|
function getAdditionalFields() {
|
|
|
|
return [['name' => $this->getForeignKeyField(),
|
|
'label' => __('As child of'),
|
|
'type' => 'parent',
|
|
'list' => false]];
|
|
}
|
|
|
|
|
|
function defineTabs($options = []) {
|
|
|
|
$ong = [];
|
|
$this->addDefaultFormTab($ong);
|
|
$this->addImpactTab($ong, $options);
|
|
|
|
$this->addStandardTab($this->getType(), $ong, $options);
|
|
if ($this->dohistory) {
|
|
$this->addStandardTab('Log', $ong, $options);
|
|
}
|
|
|
|
if (DropdownTranslation::canBeTranslated($this)) {
|
|
$this->addStandardTab('DropdownTranslation', $ong, $options);
|
|
}
|
|
|
|
return $ong;
|
|
}
|
|
|
|
|
|
function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) {
|
|
|
|
if (!$withtemplate
|
|
&& ($item->getType() == $this->getType())) {
|
|
$nb = 0;
|
|
if ($_SESSION['glpishow_count_on_tabs']) {
|
|
$nb = countElementsInTable($this->getTable(),
|
|
[$this->getForeignKeyField() => $item->getID()]);
|
|
}
|
|
return self::createTabEntry($this->getTypeName(Session::getPluralNumber()), $nb);
|
|
}
|
|
return '';
|
|
}
|
|
|
|
|
|
static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) {
|
|
|
|
if ($item instanceof CommonTreeDropdown) {
|
|
$item->showChildren();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Compute completename based on parent one
|
|
*
|
|
* @param $parentCompleteName string parent complete name (need to be stripslashes / comes from DB)
|
|
* @param $thisName string item name (need to be addslashes : comes from input)
|
|
**/
|
|
static function getCompleteNameFromParents($parentCompleteName, $thisName) {
|
|
return addslashes($parentCompleteName). " > ".$thisName;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param $input
|
|
**/
|
|
function adaptTreeFieldsFromUpdateOrAdd($input) {
|
|
|
|
$parent = clone $this;
|
|
// Update case input['name'] not set :
|
|
if (!isset($input['name']) && isset($this->fields['name'])) {
|
|
$input['name'] = addslashes($this->fields['name']);
|
|
}
|
|
// leading/ending space will break findID/import
|
|
$input['name'] = trim($input['name']);
|
|
|
|
if (isset($input[$this->getForeignKeyField()])
|
|
&& !$this->isNewID($input[$this->getForeignKeyField()])
|
|
&& $parent->getFromDB($input[$this->getForeignKeyField()])) {
|
|
$input['level'] = $parent->fields['level']+1;
|
|
// Sometimes (internet address), the complete name may be different ...
|
|
/* if ($input[$this->getForeignKeyField()]==0) { // Root entity case
|
|
$input['completename'] = $input['name'];
|
|
} else {*/
|
|
$input['completename'] = self::getCompleteNameFromParents($parent->fields['completename'],
|
|
$input['name']);
|
|
// }
|
|
} else {
|
|
$input[$this->getForeignKeyField()] = 0;
|
|
$input['level'] = 1;
|
|
$input['completename'] = $input['name'];
|
|
}
|
|
return $input;
|
|
}
|
|
|
|
|
|
function prepareInputForAdd($input) {
|
|
return $this->adaptTreeFieldsFromUpdateOrAdd($input);
|
|
}
|
|
|
|
|
|
function pre_deleteItem() {
|
|
global $DB;
|
|
|
|
// Not set in case of massive delete : use parent
|
|
if (isset($this->input['_replace_by']) && $this->input['_replace_by']) {
|
|
$parent = $this->input['_replace_by'];
|
|
} else {
|
|
$parent = $this->fields[$this->getForeignKeyField()];
|
|
}
|
|
|
|
$this->cleanParentsSons();
|
|
$tmp = clone $this;
|
|
|
|
$result = $DB->request(
|
|
[
|
|
'SELECT' => 'id',
|
|
'FROM' => $this->getTable(),
|
|
'WHERE' => [$this->getForeignKeyField() => $this->fields['id']]
|
|
]
|
|
);
|
|
|
|
foreach ($result as $data) {
|
|
$data[$this->getForeignKeyField()] = $parent;
|
|
$tmp->update($data);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
function prepareInputForUpdate($input) {
|
|
global $GLPI_CACHE;
|
|
|
|
if (isset($input[$this->getForeignKeyField()])) {
|
|
// Can't move a parent under a child
|
|
if (in_array($input[$this->getForeignKeyField()],
|
|
getSonsOf($this->getTable(), $input['id']))) {
|
|
return false;
|
|
}
|
|
// Parent changes => clear ancestors and update its level and completename
|
|
if ($input[$this->getForeignKeyField()] != $this->fields[$this->getForeignKeyField()]) {
|
|
$input["ancestors_cache"] = '';
|
|
if (Toolbox::useCache()) {
|
|
$ckey = 'ancestors_cache_' . $this->getTable() . '_' . $this->getID();
|
|
$GLPI_CACHE->delete($ckey);
|
|
}
|
|
return $this->adaptTreeFieldsFromUpdateOrAdd($input);
|
|
}
|
|
}
|
|
|
|
// Name changes => update its completename (and its level : side effect ...)
|
|
if ((isset($input['name'])) && ($input['name'] != $this->fields['name'])) {
|
|
return $this->adaptTreeFieldsFromUpdateOrAdd($input);
|
|
}
|
|
return $input;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param $ID
|
|
* @param $updateName
|
|
* @param $changeParent
|
|
**/
|
|
function regenerateTreeUnderID($ID, $updateName, $changeParent) {
|
|
global $DB, $GLPI_CACHE;
|
|
|
|
//drop from sons cache when needed
|
|
if ($changeParent && Toolbox::useCache()) {
|
|
$ckey = 'ancestors_cache_' . $this->getTable() . '_' . $ID;
|
|
$GLPI_CACHE->delete($ckey);
|
|
}
|
|
|
|
if (($updateName) || ($changeParent)) {
|
|
$currentNode = clone $this;
|
|
|
|
if ($currentNode->getFromDB($ID)) {
|
|
$currentNodeCompleteName = $currentNode->getField("completename");
|
|
$nextNodeLevel = ($currentNode->getField("level") + 1);
|
|
} else {
|
|
$nextNodeLevel = 1;
|
|
}
|
|
|
|
$query = [
|
|
'SELECT' => ['id', 'name'],
|
|
'FROM' => $this->getTable(),
|
|
'WHERE' => [$this->getForeignKeyField() => $ID]
|
|
];
|
|
if (Session::haveTranslations($this->getType(), 'completename')) {
|
|
DropdownTranslation::regenerateAllCompletenameTranslationsFor($this->getType(), $ID);
|
|
}
|
|
|
|
foreach ($DB->request($query) as $data) {
|
|
$update = [];
|
|
|
|
if ($updateName || $changeParent) {
|
|
if (isset($currentNodeCompleteName)) {
|
|
$update['completename'] = self::getCompleteNameFromParents(
|
|
$currentNodeCompleteName,
|
|
addslashes($data["name"])
|
|
);
|
|
} else {
|
|
$update['completename'] = addslashes($data["name"]);
|
|
}
|
|
}
|
|
|
|
if ($changeParent) {
|
|
// We have to reset the ancestors as only these changes (ie : not the children).
|
|
$update['ancestors_cache'] = 'NULL';
|
|
// And we must update the level of the current node ...
|
|
$update['level'] = $nextNodeLevel;
|
|
}
|
|
$DB->update(
|
|
$this->getTable(),
|
|
$update,
|
|
['id' => $data['id']]
|
|
);
|
|
// Translations :
|
|
if (Session::haveTranslations($this->getType(), 'completename')) {
|
|
DropdownTranslation::regenerateAllCompletenameTranslationsFor($this->getType(), $data['id']);
|
|
}
|
|
|
|
$this->regenerateTreeUnderID($data["id"], $updateName, $changeParent);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Clean sons of all parents from caches
|
|
*
|
|
* @param null|integer $id Parent id to clean. Default to current id
|
|
* @param boolean $cache Whether to clean cache (defaults to true)
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function cleanParentsSons($id = null, $cache = true) {
|
|
global $DB, $GLPI_CACHE;
|
|
|
|
if ($id === null) {
|
|
$id = $this->getID();
|
|
}
|
|
|
|
$ancestors = getAncestorsOf($this->getTable(), $id);
|
|
if ($id != $this->getID()) {
|
|
$ancestors[$id] = "$id";
|
|
}
|
|
if (!count($ancestors)) {
|
|
return;
|
|
}
|
|
|
|
$DB->update(
|
|
$this->getTable(), [
|
|
'sons_cache' => 'NULL'
|
|
], [
|
|
'id' => $ancestors
|
|
]
|
|
);
|
|
|
|
//drop from sons cache when needed
|
|
if ($cache && Toolbox::useCache()) {
|
|
foreach ($ancestors as $ancestor) {
|
|
$ckey = 'sons_cache_' . $this->getTable() . '_' . $ancestor;
|
|
if ($GLPI_CACHE->has($ckey)) {
|
|
$sons = $GLPI_CACHE->get($ckey);
|
|
if (isset($sons[$this->getID()])) {
|
|
unset($sons[$this->getID()]);
|
|
$GLPI_CACHE->set($ckey, $sons);
|
|
}
|
|
} else {
|
|
// If cache key does not exists in current context (UI using APCu), it may exists
|
|
// in another context (CLI using filesystem). So we force deletion of cache in all contexts
|
|
// to be sure to not use a stale value.
|
|
$GLPI_CACHE->delete($ckey);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Add new son in its parent in cache
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function addSonInParents() {
|
|
global $GLPI_CACHE;
|
|
|
|
//add sons cache when needed
|
|
if (Toolbox::useCache()) {
|
|
$ancestors = getAncestorsOf($this->getTable(), $this->getID());
|
|
foreach ($ancestors as $ancestor) {
|
|
$ckey = 'sons_cache_' . $this->getTable() . '_' . $ancestor;
|
|
if ($GLPI_CACHE->has($ckey)) {
|
|
$sons = $GLPI_CACHE->get($ckey);
|
|
if (!isset($sons[$this->getID()])) {
|
|
$sons[$this->getID()] = $this->getID();
|
|
$GLPI_CACHE->set($ckey, $sons);
|
|
}
|
|
} else {
|
|
// If cache key does not exists in current context (UI using APCu), it may exists
|
|
// in another context (CLI using filesystem). So we force deletion of cache in all contexts
|
|
// to be sure to not use a stale value.
|
|
$GLPI_CACHE->delete($ckey);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function post_addItem() {
|
|
|
|
$parent = $this->fields[$this->getForeignKeyField()];
|
|
//do not clean APCu, it will be updated
|
|
$this->cleanParentsSons(null, false);
|
|
$this->addSonInParents();
|
|
if ($parent && $this->dohistory) {
|
|
$changes = [
|
|
0,
|
|
'',
|
|
addslashes($this->getNameID()),
|
|
];
|
|
Log::history($parent, $this->getType(), $changes, $this->getType(),
|
|
Log::HISTORY_ADD_SUBITEM);
|
|
}
|
|
}
|
|
|
|
|
|
function post_updateItem($history = 1) {
|
|
|
|
$ID = $this->getID();
|
|
$changeParent = in_array($this->getForeignKeyField(), $this->updates);
|
|
$this->regenerateTreeUnderID($ID, in_array('name', $this->updates), $changeParent);
|
|
|
|
if ($changeParent) {
|
|
$oldParentID = $this->oldvalues[$this->getForeignKeyField()];
|
|
$newParentID = $this->fields[$this->getForeignKeyField()];
|
|
$oldParentNameID = '';
|
|
$newParentNameID = '';
|
|
|
|
$parent = clone $this;
|
|
if ($oldParentID > 0) {
|
|
$this->cleanParentsSons($oldParentID);
|
|
if ($history) {
|
|
if ($parent->getFromDB($oldParentID)) {
|
|
$oldParentNameID = $parent->getNameID();
|
|
}
|
|
$changes = [
|
|
'0',
|
|
addslashes($this->getNameID()),
|
|
'',
|
|
];
|
|
Log::history($oldParentID, $this->getType(), $changes, $this->getType(),
|
|
Log::HISTORY_DELETE_SUBITEM);
|
|
}
|
|
}
|
|
|
|
if ($newParentID > 0) {
|
|
$this->cleanParentsSons(null, false);
|
|
$this->addSonInParents();
|
|
if ($history) {
|
|
if ($parent->getFromDB($newParentID)) {
|
|
$newParentNameID = $parent->getNameID();
|
|
}
|
|
$changes = [
|
|
'0',
|
|
'',
|
|
addslashes($this->getNameID()),
|
|
];
|
|
Log::history($newParentID, $this->getType(), $changes, $this->getType(),
|
|
Log::HISTORY_ADD_SUBITEM);
|
|
}
|
|
}
|
|
|
|
if ($history) {
|
|
$changes = [
|
|
'0',
|
|
$oldParentNameID,
|
|
$newParentNameID,
|
|
];
|
|
Log::history($ID, $this->getType(), $changes, $this->getType(),
|
|
Log::HISTORY_UPDATE_SUBITEM);
|
|
}
|
|
getAncestorsOf(getTableForItemType($this->getType()), $ID);
|
|
}
|
|
}
|
|
|
|
|
|
function post_deleteFromDB() {
|
|
|
|
$parent = $this->fields[$this->getForeignKeyField()];
|
|
if ($parent && $this->dohistory) {
|
|
$changes = [
|
|
'0',
|
|
addslashes($this->getNameID()),
|
|
'',
|
|
];
|
|
Log::history($parent, $this->getType(), $changes, $this->getType(),
|
|
Log::HISTORY_DELETE_SUBITEM);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the this for all the current item and all its parent
|
|
*
|
|
* @return string
|
|
**/
|
|
function getTreeLink() {
|
|
|
|
$link = '';
|
|
if ($this->fields[$this->getForeignKeyField()]) {
|
|
$papa = clone $this;
|
|
|
|
if ($papa->getFromDB($this->fields[$this->getForeignKeyField()])) {
|
|
$link = $papa->getTreeLink() . " > ";
|
|
}
|
|
|
|
}
|
|
return $link . $this->getLink();
|
|
}
|
|
|
|
|
|
/**
|
|
* Print the HTML array children of a TreeDropdown
|
|
*
|
|
* @return void
|
|
*/
|
|
function showChildren() {
|
|
global $DB;
|
|
|
|
$ID = $this->getID();
|
|
$this->check($ID, READ);
|
|
$fields = array_filter(
|
|
$this->getAdditionalFields(),
|
|
function ($field) {
|
|
return isset($field['list']) && $field['list'];
|
|
}
|
|
);
|
|
$nb = count($fields);
|
|
$entity_assign = $this->isEntityAssign();
|
|
|
|
// Minimal form for quick input.
|
|
if (static::canCreate()) {
|
|
$link = $this->getFormURL();
|
|
echo "<div class='firstbloc'>";
|
|
echo "<form action='".$link."' method='post'>";
|
|
echo "<table class='tab_cadre_fixe'>";
|
|
echo "<tr><th colspan='3'>".__('New child heading')."</th></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td>".__('Name')."</td><td>";
|
|
Html::autocompletionTextField($this, "name", ['value' => '']);
|
|
|
|
if ($entity_assign
|
|
&& ($this->getForeignKeyField() != 'entities_id')) {
|
|
echo "<input type='hidden' name='entities_id' value='".$_SESSION['glpiactive_entity']."'>";
|
|
}
|
|
|
|
if ($entity_assign && $this->isRecursive()) {
|
|
echo "<input type='hidden' name='is_recursive' value='1'>";
|
|
}
|
|
echo "<input type='hidden' name='".$this->getForeignKeyField()."' value='$ID'></td>";
|
|
echo "<td><input type='submit' name='add' value=\""._sx('button', 'Add')."\" class='submit'>";
|
|
echo "</td></tr>\n";
|
|
echo "</table>";
|
|
Html::closeForm();
|
|
echo "</div>\n";
|
|
}
|
|
|
|
echo "<div class='spaced'>";
|
|
echo "<table class='tab_cadre_fixehov'>";
|
|
echo "<tr class='noHover'><th colspan='".($nb+3)."'>".sprintf(__('Sons of %s'),
|
|
$this->getTreeLink());
|
|
echo "</th></tr>";
|
|
|
|
$header = "<tr><th>".__('Name')."</th>";
|
|
if ($entity_assign) {
|
|
$header .= "<th>".Entity::getTypeName(1)."</th>";
|
|
}
|
|
foreach ($fields as $field) {
|
|
$header .= "<th>".$field['label']."</th>";
|
|
}
|
|
$header .= "<th>".__('Comments')."</th>";
|
|
$header .= "</tr>\n";
|
|
echo $header;
|
|
|
|
$fk = $this->getForeignKeyField();
|
|
|
|
$result = $DB->request(
|
|
[
|
|
'FROM' => $this->getTable(),
|
|
'WHERE' => [$fk => $ID],
|
|
'ORDER' => 'name',
|
|
]
|
|
);
|
|
|
|
$nb = 0;
|
|
foreach ($result as $data) {
|
|
$nb++;
|
|
echo "<tr class='tab_bg_1'><td>";
|
|
if ((($fk == 'entities_id') && in_array($data['id'], $_SESSION['glpiactiveentities']))
|
|
|| !$entity_assign
|
|
|| (($fk != 'entities_id') && in_array($data['entities_id'], $_SESSION['glpiactiveentities']))) {
|
|
echo "<a href='".$this->getFormURL();
|
|
echo '?id='.$data['id']."'>".$data['name']."</a>";
|
|
} else {
|
|
echo $data['name'];
|
|
}
|
|
echo "</td>";
|
|
if ($entity_assign) {
|
|
echo "<td>".Dropdown::getDropdownName("glpi_entities", $data["entities_id"])."</td>";
|
|
}
|
|
|
|
foreach ($fields as $field) {
|
|
echo "<td>";
|
|
switch ($field['type']) {
|
|
case 'UserDropdown' :
|
|
echo getUserName($data[$field['name']]);
|
|
break;
|
|
|
|
case 'bool' :
|
|
echo Dropdown::getYesNo($data[$field['name']]);
|
|
break;
|
|
|
|
case 'dropdownValue' :
|
|
echo Dropdown::getDropdownName(getTableNameForForeignKeyField($field['name']),
|
|
$data[$field['name']]);
|
|
break;
|
|
|
|
default:
|
|
echo $data[$field['name']];
|
|
}
|
|
echo "</td>";
|
|
}
|
|
echo "<td>".$data['comment']."</td>";
|
|
echo "</tr>\n";
|
|
}
|
|
if ($nb) {
|
|
echo $header;
|
|
}
|
|
echo "</table></div>\n";
|
|
}
|
|
|
|
|
|
function getSpecificMassiveActions($checkitem = null) {
|
|
|
|
$isadmin = static::canUpdate();
|
|
$actions = parent::getSpecificMassiveActions($checkitem);
|
|
|
|
if ($isadmin) {
|
|
$actions[__CLASS__.MassiveAction::CLASS_ACTION_SEPARATOR.'move_under']
|
|
= "<i class='ma-icon fas fa-sitemap'></i>".
|
|
_x('button', 'Move under');
|
|
}
|
|
|
|
return $actions;
|
|
}
|
|
|
|
|
|
static function showMassiveActionsSubForm(MassiveAction $ma) {
|
|
|
|
switch ($ma->getAction()) {
|
|
case 'move_under' :
|
|
$itemtype = $ma->getItemType(true);
|
|
echo __('As child of');
|
|
Dropdown::show($itemtype, ['name' => 'parent',
|
|
'comments' => 0,
|
|
'entity' => $_SESSION['glpiactive_entity'],
|
|
'entity_sons' => $_SESSION['glpiactive_entity_recursive']]);
|
|
echo "<br><br><input type='submit' name='massiveaction' class='submit' value='".
|
|
_sx('button', 'Move')."'>\n";
|
|
return true;
|
|
|
|
}
|
|
return parent::showMassiveActionsSubForm($ma);
|
|
}
|
|
|
|
|
|
static function processMassiveActionsForOneItemtype(MassiveAction $ma, CommonDBTM $item,
|
|
array $ids) {
|
|
|
|
$input = $ma->getInput();
|
|
|
|
switch ($ma->getAction()) {
|
|
case 'move_under' :
|
|
if (isset($input['parent'])) {
|
|
$fk = $item->getForeignKeyField();
|
|
$parent = clone $item;
|
|
if (!$parent->getFromDB($input['parent'])) {
|
|
$ma->itemDone($item->getType(), $ids, MassiveAction::ACTION_KO);
|
|
$ma->addMessage($parent->getErrorMessage(ERROR_NOT_FOUND));
|
|
return;
|
|
}
|
|
foreach ($ids as $id) {
|
|
if ($item->can($id, UPDATE)) {
|
|
// Check if parent is not a child of the original one
|
|
if (!in_array($parent->getID(), getSonsOf($item->getTable(),
|
|
$item->getID()))) {
|
|
if ($item->update(['id' => $id,
|
|
$fk => $parent->getID()])) {
|
|
$ma->itemDone($item->getType(), $id, MassiveAction::ACTION_OK);
|
|
} else {
|
|
$ma->itemDone($item->getType(), $id, MassiveAction::ACTION_KO);
|
|
$ma->addMessage($item->getErrorMessage(ERROR_ON_ACTION));
|
|
}
|
|
} else {
|
|
$ma->itemDone($item->getType(), $id, MassiveAction::ACTION_KO);
|
|
$ma->addMessage($item->getErrorMessage(ERROR_COMPAT));
|
|
}
|
|
} else {
|
|
$ma->itemDone($item->getType(), $id, MassiveAction::ACTION_NORIGHT);
|
|
$ma->addMessage($item->getErrorMessage(ERROR_RIGHT));
|
|
}
|
|
}
|
|
} else {
|
|
$ma->itemDone($item->getType(), $ids, MassiveAction::ACTION_KO);
|
|
$ma->addMessage($parent->getErrorMessage(ERROR_COMPAT));
|
|
}
|
|
return;
|
|
}
|
|
parent::processMassiveActionsForOneItemtype($ma, $item, $ids);
|
|
}
|
|
|
|
|
|
function rawSearchOptions() {
|
|
$tab = [];
|
|
|
|
$tab[] = [
|
|
'id' => 'common',
|
|
'name' => __('Characteristics')
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '1',
|
|
'table' => $this->getTable(),
|
|
'field' => 'completename',
|
|
'name' => __('Complete name'),
|
|
'datatype' => 'itemlink',
|
|
'massiveaction' => false
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '2',
|
|
'table' => $this->getTable(),
|
|
'field' => 'id',
|
|
'name' => __('ID'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'number'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '14',
|
|
'table' => $this->getTable(),
|
|
'field' => 'name',
|
|
'name' => __('Name'),
|
|
'datatype' => 'itemlink',
|
|
'autocomplete' => true,
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '13',
|
|
'table' => $this->getTable(),
|
|
'field' => 'completename',
|
|
'name' => __('Father'),
|
|
'datatype' => 'dropdown',
|
|
'massiveaction' => false,
|
|
// Add virtual condition to relink table
|
|
'joinparams' => ['condition' => "AND 1=1"]
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '16',
|
|
'table' => $this->getTable(),
|
|
'field' => 'comment',
|
|
'name' => __('Comments'),
|
|
'datatype' => 'text'
|
|
];
|
|
|
|
if ($this->isEntityAssign()) {
|
|
$tab[] = [
|
|
'id' => '80',
|
|
'table' => 'glpi_entities',
|
|
'field' => 'completename',
|
|
'name' => Entity::getTypeName(1),
|
|
'massiveaction' => false,
|
|
'datatype' => 'dropdown'
|
|
];
|
|
}
|
|
|
|
if ($this->maybeRecursive()) {
|
|
$tab[] = [
|
|
'id' => '86',
|
|
'table' => $this->getTable(),
|
|
'field' => 'is_recursive',
|
|
'name' => __('Child entities'),
|
|
'datatype' => 'bool'
|
|
];
|
|
}
|
|
|
|
if ($this->isField('date_mod')) {
|
|
$tab[] = [
|
|
'id' => '19',
|
|
'table' => $this->getTable(),
|
|
'field' => 'date_mod',
|
|
'name' => __('Last update'),
|
|
'datatype' => 'datetime',
|
|
'massiveaction' => false
|
|
];
|
|
}
|
|
|
|
if ($this->isField('date_creation')) {
|
|
$tab[] = [
|
|
'id' => '121',
|
|
'table' => $this->getTable(),
|
|
'field' => 'date_creation',
|
|
'name' => __('Creation date'),
|
|
'datatype' => 'datetime',
|
|
'massiveaction' => false
|
|
];
|
|
}
|
|
|
|
// add objectlock search options
|
|
$tab = array_merge($tab, ObjectLock::rawSearchOptionsToAdd(get_class($this)));
|
|
|
|
return $tab;
|
|
}
|
|
|
|
|
|
function haveChildren() {
|
|
|
|
$fk = $this->getForeignKeyField();
|
|
$id = $this->fields['id'];
|
|
|
|
return (countElementsInTable($this->getTable(), [$fk => $id]) > 0);
|
|
}
|
|
|
|
|
|
/**
|
|
* reformat text field describing a tree (such as completename)
|
|
*
|
|
* @param $value string
|
|
*
|
|
* @return string
|
|
**/
|
|
static function cleanTreeText($value) {
|
|
|
|
$tmp = explode('>', $value);
|
|
foreach ($tmp as $k => $v) {
|
|
$v = trim($v);
|
|
if (empty($v)) {
|
|
unset($tmp[$k]);
|
|
} else {
|
|
$tmp[$k] = $v;
|
|
}
|
|
}
|
|
return implode(' > ', $tmp);
|
|
}
|
|
|
|
|
|
function findID(array &$input) {
|
|
global $DB;
|
|
|
|
if (isset($input['completename'])) {
|
|
// Clean data
|
|
$input['completename'] = self::cleanTreeText($input['completename']);
|
|
}
|
|
|
|
if (isset($input['completename']) && !empty($input['completename'])) {
|
|
$criteria = [
|
|
'SELECT' => 'id',
|
|
'FROM' => $this->getTable(),
|
|
'WHERE' => [
|
|
'completename' => $input['completename']
|
|
]
|
|
];
|
|
if ($this->isEntityAssign()) {
|
|
$criteria['WHERE'] = $criteria['WHERE'] + getEntitiesRestrictCriteria(
|
|
$this->getTable(),
|
|
'',
|
|
$input['entities_id'],
|
|
$this->maybeRecursive()
|
|
);
|
|
}
|
|
// Check twin :
|
|
$iterator = $DB->request($criteria);
|
|
if (count($iterator)) {
|
|
$result = $iterator->next();
|
|
return $result['id'];
|
|
}
|
|
} else if (isset($input['name']) && !empty($input['name'])) {
|
|
$fk = $this->getForeignKeyField();
|
|
|
|
$criteria = [
|
|
'SELECT' => 'id',
|
|
'FROM' => $this->getTable(),
|
|
'WHERE' => [
|
|
'name' => $input['name'],
|
|
$fk => (isset($input[$fk]) ? $input[$fk] : 0)
|
|
]
|
|
];
|
|
if ($this->isEntityAssign()) {
|
|
$criteria['WHERE'] = $criteria['WHERE'] + getEntitiesRestrictCriteria(
|
|
$this->getTable(),
|
|
'',
|
|
$input['entities_id'],
|
|
$this->maybeRecursive()
|
|
);
|
|
}
|
|
// Check twin :
|
|
$iterator = $DB->request($criteria);
|
|
if (count($iterator)) {
|
|
$result = $iterator->next();
|
|
return $result['id'];
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
function import(array $input) {
|
|
|
|
if (isset($input['name'])) {
|
|
return parent::import($input);
|
|
}
|
|
|
|
if (!isset($input['completename']) || empty($input['completename'])) {
|
|
return -1;
|
|
}
|
|
|
|
// Import a full tree from completename
|
|
$names = explode('>', $input['completename']);
|
|
$fk = $this->getForeignKeyField();
|
|
$i = count($names);
|
|
$parent = 0;
|
|
|
|
foreach ($names as $name) {
|
|
$i--;
|
|
$name = trim($name);
|
|
if (empty($name)) {
|
|
// Skip empty name (completename starting/endind with >, double >, ...)
|
|
continue;
|
|
}
|
|
|
|
$tmp = [
|
|
'name' => $name,
|
|
$fk => $parent,
|
|
];
|
|
|
|
if (isset($input['is_recursive'])) {
|
|
$tmp['is_recursive'] = $input['is_recursive'];
|
|
}
|
|
if (isset($input['entities_id'])) {
|
|
$tmp['entities_id'] = $input['entities_id'];
|
|
}
|
|
|
|
if (!$i) {
|
|
// Other fields (comment, ...) only for last node of the tree
|
|
foreach ($input as $key => $val) {
|
|
if ($key != 'completename') {
|
|
$tmp[$key] = $val;
|
|
}
|
|
}
|
|
}
|
|
|
|
$parent = parent::import($tmp);
|
|
}
|
|
return $parent;
|
|
}
|
|
|
|
|
|
static function getIcon() {
|
|
return "fas fa-sitemap";
|
|
}
|
|
}
|