. * --------------------------------------------------------------------- */ if (!defined('GLPI_ROOT')) { die("Sorry. You can't access this file directly"); } /** * Search Class * * Generic class for Search Engine **/ class Search { // Default number of items displayed in global search const GLOBAL_DISPLAY_COUNT = 10; // EXPORT TYPE const GLOBAL_SEARCH = -1; const HTML_OUTPUT = 0; const SYLK_OUTPUT = 1; const PDF_OUTPUT_LANDSCAPE = 2; const CSV_OUTPUT = 3; const PDF_OUTPUT_PORTRAIT = 4; const LBBR = '#LBBR#'; const LBHR = '#LBHR#'; const SHORTSEP = '$#$'; const LONGSEP = '$$##$$'; const NULLVALUE = '__NULL__'; static $output_type = self::HTML_OUTPUT; static $search = []; /** * Display search engine for an type * * @param string $itemtype Item type to manage * * @return void **/ static function show($itemtype) { $params = self::manageParams($itemtype, $_GET); echo "
"; self::showGenericSearch($itemtype, $params); if ($params['as_map'] == 1) { self::showMap($itemtype, $params); } else { self::showList($itemtype, $params); } echo "
"; } /** * Display result table for search engine for an type * * @param string $itemtype Item type to manage * @param array $params Search params passed to prepareDatasForSearch function * * @return void **/ static function showList($itemtype, $params) { self::displayData(self::getDatas($itemtype, $params)); } /** * Display result table for search engine for an type as a map * * @param string $itemtype Item type to manage * @param array $params Search params passed to prepareDatasForSearch function * * @return void **/ static function showMap($itemtype, $params) { global $CFG_GLPI; if ($itemtype == 'Location') { $latitude = 21; $longitude = 20; } else if ($itemtype == 'Entity') { $latitude = 67; $longitude = 68; } else { $latitude = 998; $longitude = 999; } $params['criteria'][] = [ 'link' => 'AND NOT', 'field' => $latitude, 'searchtype' => 'contains', 'value' => 'NULL' ]; $params['criteria'][] = [ 'link' => 'AND NOT', 'field' => $longitude, 'searchtype' => 'contains', 'value' => 'NULL' ]; $data = self::getDatas($itemtype, $params); self::displayData($data); if ($data['data']['totalcount'] > 0) { $target = $data['search']['target']; $criteria = $data['search']['criteria']; array_pop($criteria); array_pop($criteria); $criteria[] = [ 'link' => 'AND', 'field' => ($itemtype == 'Location' || $itemtype == 'Entity') ? 1 : (($itemtype == 'Ticket') ? 83 : 3), 'searchtype' => 'equals', 'value' => 'CURLOCATION' ]; $globallinkto = Toolbox::append_params( [ 'criteria' => Toolbox::stripslashes_deep($criteria), 'metacriteria' => Toolbox::stripslashes_deep($data['search']['metacriteria']) ], '&' ); $parameters = "as_map=0&sort=".$data['search']['sort']."&order=".$data['search']['order'].'&'. $globallinkto; if (strpos($target, '?') == false) { $fulltarget = $target."?".$parameters; } else { $fulltarget = $target."&".$parameters; } $typename = class_exists($itemtype) ? $itemtype::getTypeName($data['data']['totalcount']) : ($itemtype == 'AllAssets' ? __('assets') : $itemtype); echo "

".__('Search results for localized items only')."

"; $js = "$(function() { var map = initMap($('#page'), 'map', 'full'); _loadMap(map, '$itemtype'); }); var _loadMap = function(map_elt, itemtype) { L.AwesomeMarkers.Icon.prototype.options.prefix = 'far'; var _micon = 'circle'; var stdMarker = L.AwesomeMarkers.icon({ icon: _micon, markerColor: 'blue' }); var aMarker = L.AwesomeMarkers.icon({ icon: _micon, markerColor: 'cadetblue' }); var bMarker = L.AwesomeMarkers.icon({ icon: _micon, markerColor: 'purple' }); var cMarker = L.AwesomeMarkers.icon({ icon: _micon, markerColor: 'darkpurple' }); var dMarker = L.AwesomeMarkers.icon({ icon: _micon, markerColor: 'red' }); var eMarker = L.AwesomeMarkers.icon({ icon: _micon, markerColor: 'darkred' }); //retrieve geojson data map_elt.spin(true); $.ajax({ dataType: 'json', method: 'POST', url: '{$CFG_GLPI['root_doc']}/ajax/map.php', data: { itemtype: itemtype, params: ".json_encode($params)." } }).done(function(data) { var _points = data.points; var _markers = L.markerClusterGroup({ iconCreateFunction: function(cluster) { var childCount = cluster.getChildCount(); var markers = cluster.getAllChildMarkers(); var n = 0; for (var i = 0; i < markers.length; i++) { n += markers[i].count; } var c = ' marker-cluster-'; if (n < 10) { c += 'small'; } else if (n < 100) { c += 'medium'; } else { c += 'large'; } return new L.DivIcon({ html: '
' + n + '
', className: 'marker-cluster' + c, iconSize: new L.Point(40, 40) }); } }); $.each(_points, function(index, point) { var _title = '' + point.title + '
".sprintf(__('%1$s %2$s'), 'COUNT', $typename)."'.replace(/COUNT/, point.count)+''; if (point.types) { $.each(point.types, function(tindex, type) { _title += '
".sprintf(__('%1$s %2$s'), 'COUNT', 'TYPE')."'.replace(/COUNT/, type.count).replace(/TYPE/, type.name); }); } var _icon = stdMarker; if (point.count < 10) { _icon = stdMarker; } else if (point.count < 100) { _icon = aMarker; } else if (point.count < 1000) { _icon = bMarker; } else if (point.count < 5000) { _icon = cMarker; } else if (point.count < 10000) { _icon = dMarker; } else { _icon = eMarker; } var _marker = L.marker([point.lat, point.lng], { icon: _icon, title: point.title }); _marker.count = point.count; _marker.bindPopup(_title); _markers.addLayer(_marker); }); map_elt.addLayer(_markers); map_elt.fitBounds( _markers.getBounds(), { padding: [50, 50], maxZoom: 12 } ); }).fail(function (response) { var _data = response.responseJSON; var _message = '".__s('An error occured loading data :(')."'; if (_data.message) { _message = _data.message; } var fail_info = L.control(); fail_info.onAdd = function (map) { this._div = L.DomUtil.create('div', 'fail_info'); this._div.innerHTML = _message + '
".__s('Reload')."'; return this._div; }; fail_info.addTo(map_elt); $('#reload_data').on('click', function() { $('.fail_info').remove(); _loadMap(map_elt); }); }).always(function() { //hide spinner map_elt.spin(false); }); } "; echo Html::scriptBlock($js); echo "
"; } } /** * Get data based on search parameters * * @since 0.85 * * @param string $itemtype Item type to manage * @param array $params Search params passed to prepareDatasForSearch function * @param array $forcedisplay Array of columns to display (default empty = empty use display pref and search criteria) * * @return array The data **/ static function getDatas($itemtype, $params, array $forcedisplay = []) { $data = self::prepareDatasForSearch($itemtype, $params, $forcedisplay); self::constructSQL($data); self::constructData($data); return $data; } /** * Prepare search criteria to be used for a search * * @since 0.85 * * @param string $itemtype Item type * @param array $params Array of parameters * may include sort, order, start, list_limit, deleted, criteria, metacriteria * @param array $forcedisplay Array of columns to display (default empty = empty use display pref and search criterias) * * @return array prepare to be used for a search (include criteria and others needed information) **/ static function prepareDatasForSearch($itemtype, array $params, array $forcedisplay = []) { global $CFG_GLPI; // Default values of parameters $p['criteria'] = []; $p['metacriteria'] = []; $p['sort'] = '1'; // $p['order'] = 'ASC';// $p['start'] = 0;// $p['is_deleted'] = 0; $p['export_all'] = 0; if (class_exists($itemtype)) { $p['target'] = $itemtype::getSearchURL(); } else { $p['target'] = Toolbox::getItemTypeSearchURL($itemtype); } $p['display_type'] = self::HTML_OUTPUT; $p['showmassiveactions'] = true; $p['dont_flush'] = false; $p['show_pager'] = true; $p['show_footer'] = true; $p['no_sort'] = false; $p['list_limit'] = $_SESSION['glpilist_limit']; $p['massiveactionparams'] = []; foreach ($params as $key => $val) { switch ($key) { case 'order': if (in_array($val, ['ASC', 'DESC'])) { $p[$key] = $val; } break; case 'sort': $p[$key] = intval($val); if ($p[$key] < 0) { $p[$key] = 1; } break; case 'is_deleted': if ($val == 1) { $p[$key] = '1'; } break; default: $p[$key] = $val; break; } } // Set display type for export if define if (isset($p['display_type'])) { // Limit to 10 element if ($p['display_type'] == self::GLOBAL_SEARCH) { $p['list_limit'] = self::GLOBAL_DISPLAY_COUNT; } } if ($p['export_all']) { $p['start'] = 0; } $data = []; $data['search'] = $p; $data['itemtype'] = $itemtype; // Instanciate an object to access method $data['item'] = null; if ($itemtype != 'AllAssets') { $data['item'] = getItemForItemtype($itemtype); } $data['display_type'] = $data['search']['display_type']; if (!$CFG_GLPI['allow_search_all']) { foreach ($p['criteria'] as $val) { if (isset($val['field']) && $val['field'] == 'all') { Html::displayRightError(); } } } if (!$CFG_GLPI['allow_search_view']) { foreach ($p['criteria'] as $val) { if (isset($val['field']) && $val['field'] == 'view') { Html::displayRightError(); } } } /// Get the items to display // Add searched items $forcetoview = false; if (is_array($forcedisplay) && count($forcedisplay)) { $forcetoview = true; } $data['search']['all_search'] = false; $data['search']['view_search'] = false; // If no research limit research to display item and compute number of item using simple request $data['search']['no_search'] = true; $data['toview'] = self::addDefaultToView($itemtype, $params); $data['meta_toview'] = []; if (!$forcetoview) { // Add items to display depending of personal prefs $displaypref = DisplayPreference::getForTypeUser($itemtype, Session::getLoginUserID()); if (count($displaypref)) { foreach ($displaypref as $val) { array_push($data['toview'], $val); } } } else { $data['toview'] = array_merge($data['toview'], $forcedisplay); } if (count($p['criteria']) > 0) { // use a recursive closure to push searchoption when using nested criteria $parse_criteria = function($criteria) use (&$parse_criteria, &$data) { foreach ($criteria as $criterion) { // recursive call if (isset($criterion['criteria'])) { $parse_criteria($criterion['criteria']); } else { // normal behavior if (isset($criterion['field']) && !in_array($criterion['field'], $data['toview'])) { if ($criterion['field'] != 'all' && $criterion['field'] != 'view' && (!isset($criterion['meta']) || !$criterion['meta'])) { array_push($data['toview'], $criterion['field']); } else if ($criterion['field'] == 'all') { $data['search']['all_search'] = true; } else if ($criterion['field'] == 'view') { $data['search']['view_search'] = true; } } if (isset($criterion['value']) && (strlen($criterion['value']) > 0)) { $data['search']['no_search'] = false; } } } }; // call the closure $parse_criteria($p['criteria']); } if (count($p['metacriteria'])) { $data['search']['no_search'] = false; } // Add order item if (!in_array($p['sort'], $data['toview'])) { array_push($data['toview'], $p['sort']); } // Special case for Ticket : put ID in front if ($itemtype == 'Ticket') { array_unshift($data['toview'], 2); } $limitsearchopt = self::getCleanedOptions($itemtype); // Clean and reorder toview $tmpview = []; foreach ($data['toview'] as $val) { if (isset($limitsearchopt[$val]) && !in_array($val, $tmpview)) { $tmpview[] = $val; } } $data['toview'] = $tmpview; $data['tocompute'] = $data['toview']; // Force item to display if ($forcetoview) { foreach ($data['toview'] as $val) { if (!in_array($val, $data['tocompute'])) { array_push($data['tocompute'], $val); } } } return $data; } /** * Construct SQL request depending of search parameters * * Add to data array a field sql containing an array of requests : * search : request to get items limited to wanted ones * count : to count all items based on search criterias * may be an array a request : need to add counts * maybe empty : use search one to count * * @since 0.85 * * @param array $data Array of search datas prepared to generate SQL * * @return void **/ static function constructSQL(array &$data) { global $CFG_GLPI, $DB; if (!isset($data['itemtype'])) { return false; } $data['sql']['count'] = []; $data['sql']['search'] = ''; $searchopt = &self::getOptions($data['itemtype']); $blacklist_tables = []; $orig_table = self::getOrigTableName($data['itemtype']); if (isset($CFG_GLPI['union_search_type'][$data['itemtype']])) { $itemtable = $CFG_GLPI['union_search_type'][$data['itemtype']]; $blacklist_tables[] = $orig_table; } else { $itemtable = $orig_table; } // hack for AllAssets if (isset($CFG_GLPI['union_search_type'][$data['itemtype']])) { $entity_restrict = true; } else { $entity_restrict = $data['item']->isEntityAssign() && $data['item']->isField('entities_id'); } // Construct the request //// 1 - SELECT // request currentuser for SQL supervision, not displayed $SELECT = "SELECT DISTINCT `$itemtable`.`id` AS id, '".Toolbox::addslashes_deep($_SESSION['glpiname'])."' AS currentuser, ".self::addDefaultSelect($data['itemtype']); // Add select for all toview item foreach ($data['toview'] as $val) { $SELECT .= self::addSelect($data['itemtype'], $val); } if (isset($data['search']['as_map']) && $data['search']['as_map'] == 1 && $data['itemtype'] != 'Entity') { $SELECT .= ' `glpi_locations`.`id` AS loc_id, '; } //// 2 - FROM AND LEFT JOIN // Set reference table $FROM = " FROM `$itemtable`"; // Init already linked tables array in order not to link a table several times $already_link_tables = []; // Put reference table array_push($already_link_tables, $itemtable); // Add default join $COMMONLEFTJOIN = self::addDefaultJoin($data['itemtype'], $itemtable, $already_link_tables); $FROM .= $COMMONLEFTJOIN; // Add all table for toview items foreach ($data['tocompute'] as $val) { if (!in_array($searchopt[$val]["table"], $blacklist_tables)) { $FROM .= self::addLeftJoin($data['itemtype'], $itemtable, $already_link_tables, $searchopt[$val]["table"], $searchopt[$val]["linkfield"], 0, 0, $searchopt[$val]["joinparams"], $searchopt[$val]["field"]); } } // Search all case : if ($data['search']['all_search']) { foreach ($searchopt as $key => $val) { // Do not search on Group Name if (is_array($val) && isset($val['table'])) { if (!in_array($searchopt[$key]["table"], $blacklist_tables)) { $FROM .= self::addLeftJoin($data['itemtype'], $itemtable, $already_link_tables, $searchopt[$key]["table"], $searchopt[$key]["linkfield"], 0, 0, $searchopt[$key]["joinparams"], $searchopt[$key]["field"]); } } } } //// 3 - WHERE // default string $COMMONWHERE = self::addDefaultWhere($data['itemtype']); $first = empty($COMMONWHERE); // Add deleted if item have it if ($data['item'] && $data['item']->maybeDeleted()) { $LINK = " AND "; if ($first) { $LINK = " "; $first = false; } $COMMONWHERE .= $LINK."`$itemtable`.`is_deleted` = ".(int)$data['search']['is_deleted']." "; } // Remove template items if ($data['item'] && $data['item']->maybeTemplate()) { $LINK = " AND "; if ($first) { $LINK = " "; $first = false; } $COMMONWHERE .= $LINK."`$itemtable`.`is_template` = 0 "; } // Add Restrict to current entities if ($entity_restrict) { $LINK = " AND "; if ($first) { $LINK = " "; $first = false; } if ($data['itemtype'] == 'Entity') { $COMMONWHERE .= getEntitiesRestrictRequest($LINK, $itemtable, 'id', '', true); } else if (isset($CFG_GLPI["union_search_type"][$data['itemtype']])) { // Will be replace below in Union/Recursivity Hack $COMMONWHERE .= $LINK." ENTITYRESTRICT "; } else { $COMMONWHERE .= getEntitiesRestrictRequest($LINK, $itemtable, '', '', $data['item']->maybeRecursive() && $data['item']->isField('is_recursive')); } } $WHERE = ""; $HAVING = ""; // Add search conditions // If there is search items if (count($data['search']['criteria'])) { $WHERE = self::constructCriteriaSQL($data['search']['criteria'], $data, $searchopt); $HAVING = self::constructCriteriaSQL($data['search']['criteria'], $data, $searchopt, true); // if criteria (with meta flag) need additional join/from sql self::constructAdditionalSqlForMetacriteria($data['search']['criteria'], $SELECT, $FROM, $already_link_tables, $data); } //// 4 - ORDER $ORDER = " ORDER BY `id` "; foreach ($data['tocompute'] as $val) { if ($data['search']['sort'] == $val) { $ORDER = self::addOrderBy( $data['itemtype'], $data['search']['sort'], $data['search']['order'] ); } } $SELECT = rtrim(trim($SELECT), ','); //// 7 - Manage GROUP BY $GROUPBY = ""; // Meta Search / Search All / Count tickets $criteria_with_meta = array_filter($data['search']['criteria'], function($criterion) { return isset($criterion['meta']) && $criterion['meta']; }); if ((count($data['search']['metacriteria'])) || count($criteria_with_meta) || !empty($HAVING) || $data['search']['all_search']) { $GROUPBY = " GROUP BY `$itemtable`.`id`"; } if (empty($GROUPBY)) { foreach ($data['toview'] as $val2) { if (!empty($GROUPBY)) { break; } if (isset($searchopt[$val2]["forcegroupby"])) { $GROUPBY = " GROUP BY `$itemtable`.`id`"; } } } $LIMIT = ""; $numrows = 0; //No search : count number of items using a simple count(ID) request and LIMIT search if ($data['search']['no_search']) { $LIMIT = " LIMIT ".(int)$data['search']['start'].", ".(int)$data['search']['list_limit']; // Force group by for all the type -> need to count only on table ID if (!isset($searchopt[1]['forcegroupby'])) { $count = "count(*)"; } else { $count = "count(DISTINCT `$itemtable`.`id`)"; } // request currentuser for SQL supervision, not displayed $query_num = "SELECT $count, '".Toolbox::addslashes_deep($_SESSION['glpiname'])."' AS currentuser FROM `$itemtable`". $COMMONLEFTJOIN; $first = true; if (!empty($COMMONWHERE)) { $LINK = " AND "; if ($first) { $LINK = " WHERE "; $first = false; } $query_num .= $LINK.$COMMONWHERE; } // Union Search : if (isset($CFG_GLPI["union_search_type"][$data['itemtype']])) { $tmpquery = $query_num; foreach ($CFG_GLPI[$CFG_GLPI["union_search_type"][$data['itemtype']]] as $ctype) { $ctable = $ctype::getTable(); if (($citem = getItemForItemtype($ctype)) && $citem->canView()) { // State case if ($data['itemtype'] == 'AllAssets') { $query_num = str_replace($CFG_GLPI["union_search_type"][$data['itemtype']], $ctable, $tmpquery); $query_num = str_replace($data['itemtype'], $ctype, $query_num); $query_num .= " AND `$ctable`.`id` IS NOT NULL "; // Add deleted if item have it if ($citem && $citem->maybeDeleted()) { $query_num .= " AND `$ctable`.`is_deleted` = 0 "; } // Remove template items if ($citem && $citem->maybeTemplate()) { $query_num .= " AND `$ctable`.`is_template` = 0 "; } } else {// Ref table case $reftable = $data['itemtype']::getTable(); if ($data['item'] && $data['item']->maybeDeleted()) { $tmpquery = str_replace("`".$CFG_GLPI["union_search_type"][$data['itemtype']]."`. `is_deleted`", "`$reftable`.`is_deleted`", $tmpquery); } $replace = "FROM `$reftable` INNER JOIN `$ctable` ON (`$reftable`.`items_id` =`$ctable`.`id` AND `$reftable`.`itemtype` = '$ctype')"; $query_num = str_replace("FROM `". $CFG_GLPI["union_search_type"][$data['itemtype']]."`", $replace, $tmpquery); $query_num = str_replace($CFG_GLPI["union_search_type"][$data['itemtype']], $ctable, $query_num); } $query_num = str_replace("ENTITYRESTRICT", getEntitiesRestrictRequest('', $ctable, '', '', $citem->maybeRecursive()), $query_num); $data['sql']['count'][] = $query_num; } } } else { $data['sql']['count'][] = $query_num; } } // If export_all reset LIMIT condition if ($data['search']['export_all']) { $LIMIT = ""; } if (!empty($WHERE) || !empty($COMMONWHERE)) { if (!empty($COMMONWHERE)) { $WHERE = ' WHERE '.$COMMONWHERE.(!empty($WHERE)?' AND ( '.$WHERE.' )':''); } else { $WHERE = ' WHERE '.$WHERE.' '; } $first = false; } if (!empty($HAVING)) { $HAVING = ' HAVING '.$HAVING; } // Create QUERY if (isset($CFG_GLPI["union_search_type"][$data['itemtype']])) { $first = true; $QUERY = ""; foreach ($CFG_GLPI[$CFG_GLPI["union_search_type"][$data['itemtype']]] as $ctype) { $ctable = $ctype::getTable(); if (($citem = getItemForItemtype($ctype)) && $citem->canView()) { if ($first) { $first = false; } else { $QUERY .= " UNION "; } $tmpquery = ""; // AllAssets case if ($data['itemtype'] == 'AllAssets') { $tmpquery = $SELECT.", '$ctype' AS TYPE ". $FROM. $WHERE; $tmpquery .= " AND `$ctable`.`id` IS NOT NULL "; // Add deleted if item have it if ($citem && $citem->maybeDeleted()) { $tmpquery .= " AND `$ctable`.`is_deleted` = 0 "; } // Remove template items if ($citem && $citem->maybeTemplate()) { $tmpquery .= " AND `$ctable`.`is_template` = 0 "; } $tmpquery.= $GROUPBY. $HAVING; // Replace 'asset_types' by itemtype table name $tmpquery = str_replace( $CFG_GLPI["union_search_type"][$data['itemtype']], $ctable, $tmpquery ); // Replace 'AllAssets' by itemtype // Use quoted value to prevent replacement of AllAssets in column identifiers $tmpquery = str_replace( $DB->quoteValue('AllAssets'), $DB->quoteValue($ctype), $tmpquery ); } else {// Ref table case $reftable = $data['itemtype']::getTable(); $tmpquery = $SELECT.", '$ctype' AS TYPE, `$reftable`.`id` AS refID, "." `$ctable`.`entities_id` AS ENTITY ". $FROM. $WHERE; if ($data['item']->maybeDeleted()) { $tmpquery = str_replace("`".$CFG_GLPI["union_search_type"][$data['itemtype']]."`. `is_deleted`", "`$reftable`.`is_deleted`", $tmpquery); } $replace = "FROM `$reftable`"." INNER JOIN `$ctable`"." ON (`$reftable`.`items_id`=`$ctable`.`id`"." AND `$reftable`.`itemtype` = '$ctype')"; $tmpquery = str_replace("FROM `". $CFG_GLPI["union_search_type"][$data['itemtype']]."`", $replace, $tmpquery); $tmpquery = str_replace($CFG_GLPI["union_search_type"][$data['itemtype']], $ctable, $tmpquery); $name_field = $ctype::getNameField(); $tmpquery = str_replace("`$ctable`.`name`", "`$ctable`.`$name_field`", $tmpquery); } $tmpquery = str_replace("ENTITYRESTRICT", getEntitiesRestrictRequest('', $ctable, '', '', $citem->maybeRecursive()), $tmpquery); // SOFTWARE HACK if ($ctype == 'Software') { $tmpquery = str_replace("`glpi_softwares`.`serial`", "''", $tmpquery); $tmpquery = str_replace("`glpi_softwares`.`otherserial`", "''", $tmpquery); } $QUERY .= $tmpquery; } } if (empty($QUERY)) { echo self::showError($data['display_type']); return; } $QUERY .= str_replace($CFG_GLPI["union_search_type"][$data['itemtype']].".", "", $ORDER) . $LIMIT; } else { $QUERY = $SELECT. $FROM. $WHERE. $GROUPBY. $HAVING. $ORDER. $LIMIT; } $data['sql']['search'] = $QUERY; } /** * Construct WHERE (or HAVING) part of the sql based on passed criteria * * @since 9.4 * * @param array $criteria list of search criterion, we should have these keys: * - link (optionnal): AND, OR, NOT AND, NOT OR * - field: id of the searchoption * - searchtype: how to match value (contains, equals, etc) * - value * @param array $data common array used by search engine, * contains all the search part (sql, criteria, params, itemtype etc) * TODO: should be a property of the class * @param array $searchopt Search options for the current itemtype * @param boolean $is_having Do we construct sql WHERE or HAVING part * * @return string the sql sub string */ static function constructCriteriaSQL($criteria = [], $data = [], $searchopt = [], $is_having = false) { $sql = ""; foreach ($criteria as $criterion) { if (!isset($criterion['criteria']) && (!isset($criterion['value']) || strlen($criterion['value']) <= 0)) { continue; } $itemtype = $data['itemtype']; $meta = false; if (isset($criterion['meta']) && $criterion['meta'] && isset($criterion['itemtype'])) { $itemtype = $criterion['itemtype']; $meta = true; } // common search if (!isset($criterion['field']) || ($criterion['field'] != "all" && $criterion['field'] != "view")) { $LINK = " "; $NOT = 0; $tmplink = ""; if (isset($criterion['link']) && in_array($criterion['link'], array_keys(self::getLogicalOperators()))) { if (strstr($criterion['link'], "NOT")) { $tmplink = " ".str_replace(" NOT", "", $criterion['link']); $NOT = 1; } else { $tmplink = " ".$criterion['link']; } } else { $tmplink = " AND "; } // Manage Link if not first item if (!empty($sql)) { $LINK = $tmplink; } if (isset($criterion['criteria']) && count($criterion['criteria'])) { $sub_sql = self::constructCriteriaSQL($criterion['criteria'], $data, $searchopt, $is_having); if (strlen($sub_sql)) { if ($NOT) { $sql .= "$LINK NOT($sub_sql)"; } else { $sql .= "$LINK ($sub_sql)"; } } } else if (isset($searchopt[$criterion['field']]["usehaving"]) || ($meta && "AND NOT" === $criterion['link'])) { if (!$is_having) { // the having part will be managed in a second pass continue; } $new_having = self::addHaving($LINK, $NOT, $itemtype, $criterion['field'], $criterion['searchtype'], $criterion['value']); if ($new_having !== false) { $sql .= $new_having; } } else { if ($is_having) { // the having part has been already managed in the first pass continue; } $new_where = self::addWhere($LINK, $NOT, $itemtype, $criterion['field'], $criterion['searchtype'], $criterion['value'], $meta); if ($new_where !== false) { $sql .= $new_where; } } } else if (isset($criterion['value']) && strlen($criterion['value']) > 0) { // view and all search $LINK = " OR "; $NOT = 0; $globallink = " AND "; if (isset($criterion['link'])) { switch ($criterion['link']) { case "AND" : $LINK = " OR "; $globallink = " AND "; break; case "AND NOT" : $LINK = " AND "; $NOT = 1; $globallink = " AND "; break; case "OR" : $LINK = " OR "; $globallink = " OR "; break; case "OR NOT" : $LINK = " AND "; $NOT = 1; $globallink = " OR "; break; } } else { $tmplink =" AND "; } // Manage Link if not first item if (!empty($sql)) { $sql .= $globallink; } $first2 = true; $items = []; if (isset($criterion['field']) && $criterion['field'] == "all") { $items = $searchopt; } else { // toview case : populate toview foreach ($data['toview'] as $key2 => $val2) { $items[$val2] = $searchopt[$val2]; } } $view_sql = ""; foreach ($items as $key2 => $val2) { if (isset($val2['nosearch']) && $val2['nosearch']) { continue; } if (is_array($val2)) { // Add Where clause if not to be done in HAVING CLAUSE if (!$is_having && !isset($val2["usehaving"])) { $tmplink = $LINK; if ($first2) { $tmplink = " "; } $new_where = self::addWhere($tmplink, $NOT, $itemtype, $key2, $criterion['searchtype'], $criterion['value'], $meta); if ($new_where !== false) { $first2 = false; $view_sql .= $new_where; } } } } if (strlen($view_sql)) { $sql.= " ($view_sql) "; } } } return $sql; } /** * Construct aditionnal SQL (select, joins, etc) for meta-criteria * * @since 9.4 * * @param array $criteria list of search criterion * @param string &$SELECT TODO: should be a class property (output parameter) * @param string &$FROM TODO: should be a class property (output parameter) * @param array &$already_link_tables TODO: should be a class property (output parameter) * @param array &$data TODO: should be a class property (output parameter) * * @return void */ static function constructAdditionalSqlForMetacriteria($criteria = [], &$SELECT = "", &$FROM = "", &$already_link_tables = [], &$data = []) { $data['meta_toview'] = []; foreach ($criteria as $criterion) { // manage sub criteria if (isset($criterion['criteria'])) { self::constructAdditionalSqlForMetacriteria( $criterion['criteria'], $SELECT, $FROM, $already_link_tables, $data ); continue; } // parse only criterion with meta flag if (!isset($criterion['itemtype']) || empty($criterion['itemtype']) || !isset($criterion['meta']) || !$criterion['meta'] || !isset($criterion['value']) || strlen($criterion['value']) <= 0) { continue; } $m_itemtype = $criterion['itemtype']; $metaopt = &self::getOptions($m_itemtype); $sopt = $metaopt[$criterion['field']]; //add toview for meta criterion $data['meta_toview'][$m_itemtype][] = $criterion['field']; $SELECT .= self::addSelect( $m_itemtype, $criterion['field'], true, // meta-criterion $m_itemtype ); if (!in_array($m_itemtype::getTable(), $already_link_tables)) { $FROM .= self::addMetaLeftJoin($data['itemtype'], $m_itemtype, $already_link_tables, $sopt["joinparams"]); } if (!in_array($sopt["table"]."_".$criterion['itemtype'], $already_link_tables)) { $FROM .= self::addLeftJoin($m_itemtype, $m_itemtype::getTable(), $already_link_tables, $sopt["table"], $sopt["linkfield"], 1, $m_itemtype, $sopt["joinparams"], $sopt["field"]); } } } /** * Retrieve datas from DB : construct data array containing columns definitions and rows datas * * add to data array a field data containing : * cols : columns definition * rows : rows data * * @since 0.85 * * @param array $data array of search data prepared to get data * @param boolean $onlycount If we just want to count results * * @return void **/ static function constructData(array &$data, $onlycount = false) { if (!isset($data['sql']) || !isset($data['sql']['search'])) { return false; } $data['data'] = []; // Use a ReadOnly connection if available and configured to be used $DBread = DBConnection::getReadConnection(); $DBread->query("SET SESSION group_concat_max_len = 16384;"); // directly increase group_concat_max_len to avoid double query if (count($data['search']['metacriteria'])) { foreach ($data['search']['metacriteria'] as $metacriterion) { if ($metacriterion['link'] == 'AND NOT' || $metacriterion['link'] == 'OR NOT') { $DBread->query("SET SESSION group_concat_max_len = 4194304;"); break; } } } $DBread->execution_time = true; $result = $DBread->query($data['sql']['search']); /// Check group concat limit : if warning : increase limit if ($result2 = $DBread->query('SHOW WARNINGS')) { if ($DBread->numrows($result2) > 0) { $res = $DBread->fetchAssoc($result2); if ($res['Code'] == 1260) { $DBread->query("SET SESSION group_concat_max_len = 8194304;"); $DBread->execution_time = true; $result = $DBread->query($data['sql']['search']); } if ($res['Code'] == 1116) { // too many tables echo self::showError($data['search']['display_type'], __("'All' criterion is not usable with this object list, ". "sql query fails (too many tables). ". "Please use 'Items seen' criterion instead")); return false; } } } if ($result) { $data['data']['execution_time'] = $DBread->execution_time; if (isset($data['search']['savedsearches_id'])) { SavedSearch::updateExecutionTime( (int)$data['search']['savedsearches_id'], $DBread->execution_time ); } $data['data']['totalcount'] = 0; // if real search or complete export : get numrows from request if (!$data['search']['no_search'] || $data['search']['export_all']) { $data['data']['totalcount'] = $DBread->numrows($result); } else { if (!isset($data['sql']['count']) || (count($data['sql']['count']) == 0)) { $data['data']['totalcount'] = $DBread->numrows($result); } else { foreach ($data['sql']['count'] as $sqlcount) { $result_num = $DBread->query($sqlcount); $data['data']['totalcount'] += $DBread->result($result_num, 0, 0); } } } if ($onlycount) { //we just want to coutn results; no need to continue process return; } // Search case $data['data']['begin'] = $data['search']['start']; $data['data']['end'] = min($data['data']['totalcount'], $data['search']['start']+$data['search']['list_limit'])-1; //map case if (isset($data['search']['as_map']) && $data['search']['as_map'] == 1) { $data['data']['end'] = $data['data']['totalcount']-1; } // No search Case if ($data['search']['no_search']) { $data['data']['begin'] = 0; $data['data']['end'] = min($data['data']['totalcount']-$data['search']['start'], $data['search']['list_limit'])-1; } // Export All case if ($data['search']['export_all']) { $data['data']['begin'] = 0; $data['data']['end'] = $data['data']['totalcount']-1; } // Get columns $data['data']['cols'] = []; $searchopt = &self::getOptions($data['itemtype']); foreach ($data['toview'] as $opt_id) { $data['data']['cols'][] = [ 'itemtype' => $data['itemtype'], 'id' => $opt_id, 'name' => $searchopt[$opt_id]["name"], 'meta' => 0, 'searchopt' => $searchopt[$opt_id], ]; } // manage toview column for criteria with meta flag foreach ($data['meta_toview'] as $m_itemtype => $toview) { $searchopt = &self::getOptions($m_itemtype); foreach ($toview as $opt_id) { $data['data']['cols'][] = [ 'itemtype' => $m_itemtype, 'id' => $opt_id, 'name' => $searchopt[$opt_id]["name"], 'meta' => 1, 'searchopt' => $searchopt[$opt_id], ]; } } // Display columns Headers for meta items $already_printed = []; if (count($data['search']['metacriteria'])) { foreach ($data['search']['metacriteria'] as $metacriteria) { if (isset($metacriteria['itemtype']) && !empty($metacriteria['itemtype']) && isset($metacriteria['value']) && (strlen($metacriteria['value']) > 0)) { if (!isset($already_printed[$metacriteria['itemtype'].$metacriteria['field']])) { $searchopt = &self::getOptions($metacriteria['itemtype']); $data['data']['cols'][] = [ 'itemtype' => $metacriteria['itemtype'], 'id' => $metacriteria['field'], 'name' => $searchopt[$metacriteria['field']]["name"], 'meta' => 1, 'searchopt' =>$searchopt[$metacriteria['field']] ]; $already_printed[$metacriteria['itemtype'].$metacriteria['field']] = 1; } } } } // search group (corresponding of dropdown optgroup) of current col foreach ($data['data']['cols'] as $num => $col) { // search current col in searchoptions () while (key($searchopt) !== null && key($searchopt) != $col['id']) { next($searchopt); } if (key($searchopt) !== null) { //search optgroup (non array option) while (key($searchopt) !== null && is_numeric(key($searchopt)) && is_array(current($searchopt))) { prev($searchopt); } if (key($searchopt) !== null && key($searchopt) !== "common") { $data['data']['cols'][$num]['groupname'] = current($searchopt); } } //reset reset($searchopt); } // Get rows // if real search seek to begin of items to display (because of complete search) if (!$data['search']['no_search']) { $DBread->dataSeek($result, $data['search']['start']); } $i = $data['data']['begin']; $data['data']['warning'] = "For compatibility keep raw data (ITEM_X, META_X) at the top for the moment. Will be drop in next version"; $data['data']['rows'] = []; $data['data']['items'] = []; self::$output_type = $data['display_type']; while (($i < $data['data']['totalcount']) && ($i <= $data['data']['end'])) { $row = $DBread->fetchAssoc($result); $newrow = []; $newrow['raw'] = $row; // Parse datas foreach ($newrow['raw'] as $key => $val) { if (preg_match('/ITEM(_(\w[^\d]+))?_(\d+)(_(.+))?/', $key, $matches)) { $j = $matches[3]; if (isset($matches[2]) && !empty($matches[2])) { $j = $matches[2] . '_' . $matches[3]; } $fieldname = 'name'; if (isset($matches[5])) { $fieldname = $matches[5]; } // No Group_concat case if ($fieldname == 'content' || strpos($val, self::LONGSEP) === false) { $newrow[$j]['count'] = 1; $handled = false; if ($fieldname != 'content' && strpos($val, self::SHORTSEP) !== false) { $split2 = self::explodeWithID(self::SHORTSEP, $val); if (is_numeric($split2[1])) { $newrow[$j][0][$fieldname] = $split2[0]; $newrow[$j][0]['id'] = $split2[1]; $handled = true; } } if (!$handled) { if ($val === self::NULLVALUE) { $newrow[$j][0][$fieldname] = null; } else { $newrow[$j][0][$fieldname] = $val; } } } else { if (!isset($newrow[$j])) { $newrow[$j] = []; } $split = explode(self::LONGSEP, $val); $newrow[$j]['count'] = count($split); foreach ($split as $key2 => $val2) { $handled = false; if (strpos($val2, self::SHORTSEP) !== false) { $split2 = self::explodeWithID(self::SHORTSEP, $val2); if (is_numeric($split2[1])) { $newrow[$j][$key2]['id'] = $split2[1]; if ($split2[0] == self::NULLVALUE) { $newrow[$j][$key2][$fieldname] = null; } else { $newrow[$j][$key2][$fieldname] = $split2[0]; } $handled = true; } } if (!$handled) { $newrow[$j][$key2][$fieldname] = $val2; } } } } else { if ($key == 'currentuser') { if (!isset($data['data']['currentuser'])) { $data['data']['currentuser'] = $val; } } else { $newrow[$key] = $val; // Add id to items list if ($key == 'id') { $data['data']['items'][$val] = $i; } } } } foreach ($data['data']['cols'] as $val) { $newrow[$val['itemtype'] . '_' . $val['id']]['displayname'] = self::giveItem( $val['itemtype'], $val['id'], $newrow ); } $data['data']['rows'][$i] = $newrow; $i++; } $data['data']['count'] = count($data['data']['rows']); } else { echo $DBread->error(); } } /** * Display datas extracted from DB * * @param array $data Array of search datas prepared to get datas * * @return void **/ static function displayData(array $data) { global $CFG_GLPI; //sophal debut $RevueAnnuelle = [ 0 =>'Revue Annuelle Plan Directeur Commercial' , 1=>'Revue Annuelle Plan Directeur Marketing', 2=>'Revue Annuelle Plan Directeur Production', 3=>'Revue Annuelle Plan Directeur Approvisionnements', 4=>'Revue Annuelle Plan Directeur Ressources Humaines' ]; $roleuser =$_SESSION['glpiactiveprofile']['name']; if($data['itemtype'] == "PlanningExternalEvent"){ if( $roleuser == "Directeur Commercial" || $roleuser == "Directeur Marketing" || $roleuser == "Directeur Production" || $roleuser == "Directeur Approvisionnement" || $roleuser == "Directeur RH"){ $countRows = sizeof($data['data']['rows']); for($SUPP = 0 ;$SUPP < $countRows ; $SUPP++){ $io = $data['data']['rows'][$SUPP]['raw']['ITEM_PlanningExternalEvent_1']; if($roleuser == "Directeur Commercial"){ if( $io != $RevueAnnuelle[0]){ ; unset($data['data']['rows'][$SUPP]); } }elseif($roleuser == "Directeur Marketing"){ if( $io != $RevueAnnuelle[1]){ ; unset($data['data']['rows'][$SUPP]); } }elseif($roleuser == "Directeur Production"){ if( $io != $RevueAnnuelle[2]){ ; unset($data['data']['rows'][$SUPP]); } }elseif($roleuser == "Directeur Approvisionnement"){ if( $io != $RevueAnnuelle[3]){ ; unset($data['data']['rows'][$SUPP]); } }elseif($roleuser == "Directeur RH"){ if( $io != $RevueAnnuelle[4]){ ; unset($data['data']['rows'][$SUPP]); } } } } } //sophal fin $item = null; if (class_exists($data['itemtype'])) { $item = new $data['itemtype'](); } if (!isset($data['data']) || !isset($data['data']['totalcount'])) { return false; } // Contruct Pager parameters $globallinkto = Toolbox::append_params(['criteria' => Toolbox::stripslashes_deep($data['search']['criteria']), 'metacriteria' => Toolbox::stripslashes_deep($data['search']['metacriteria'])], '&'); $parameters = "sort=".$data['search']['sort']."&order=".$data['search']['order'].'&'. $globallinkto; if (isset($_GET['_in_modal'])) { $parameters .= "&_in_modal=1"; } // Global search header if ($data['display_type'] == self::GLOBAL_SEARCH) { if ($data['item']) { echo "

".$data['item']->getTypeName(); // More items if ($data['data']['totalcount'] > ($data['search']['start'] + self::GLOBAL_DISPLAY_COUNT)) { echo " ".__('All').""; } echo "

\n"; } else { return false; } } // If the begin of the view is before the number of items if ($data['data']['count'] > 0) { // Display pager only for HTML if ($data['display_type'] == self::HTML_OUTPUT) { // For plugin add new parameter if available if ($plug = isPluginItemType($data['itemtype'])) { $out = Plugin::doOneHook($plug['plugin'], 'addParamFordynamicReport', $data['itemtype']); if (is_array($out) && count($out)) { $parameters .= Toolbox::append_params($out, '&'); } } $search_config_top = ""; $search_config_bottom = ""; if (!isset($_GET['_in_modal'])) { $search_config_top = $search_config_bottom = "
"; $map_link = ''; if (null == $item || $item->maybeLocated()) { $map_link = ""; } $search_config_top .= $map_link; if (Session::haveRightsOr('search_config', [ DisplayPreference::PERSONAL, DisplayPreference::GENERAL ])) { $options_link = " " . __s('Select default items to show') . ""; $search_config_top .= str_replace('%id', 'search_config_top', $options_link); $search_config_bottom .= str_replace('%id', 'search_config_bottom', $options_link); $pref_url = $CFG_GLPI["root_doc"]."/front/displaypreference.form.php?itemtype=". $data['itemtype']; $search_config_top .= Ajax::createIframeModalWindow( 'search_config_top', $pref_url, [ 'title' => __('Select default items to show'), 'reloadonclose' => true, 'display' => false ] ); $search_config_bottom .= Ajax::createIframeModalWindow( 'search_config_bottom', $pref_url, [ 'title' => __('Select default items to show'), 'reloadonclose' => true, 'display' => false ] ); } } if ($item !== null && $item->maybeDeleted()) { $delete_ctrl = self::isDeletedSwitch($data['search']['is_deleted'], $data['itemtype']); $search_config_top .= $delete_ctrl; } if ($data['search']['show_pager']) { Html::printPager($data['search']['start'], $data['data']['totalcount'], $data['search']['target'], $parameters, $data['itemtype'], 0, $search_config_top); } $search_config_top .= "
"; $search_config_bottom .= ""; } // Define begin and end var for loop // Search case $begin_display = $data['data']['begin']; $end_display = $data['data']['end']; // Form to massive actions $isadmin = ($data['item'] && $data['item']->canUpdate()); if (!$isadmin && Infocom::canApplyOn($data['itemtype'])) { $isadmin = (Infocom::canUpdate() || Infocom::canCreate()); } if ($data['itemtype'] != 'AllAssets') { $showmassiveactions = ($data['search']['showmassiveactions'] ?? true) && count(MassiveAction::getAllMassiveActions($data['item'], $data['search']['is_deleted'])); } else { $showmassiveactions = $data['search']['showmassiveactions'] ?? true; } if ($data['search']['as_map'] == 0) { $massformid = 'massform'.$data['itemtype']; if ($showmassiveactions && ($data['display_type'] == self::HTML_OUTPUT)) { Html::openMassiveActionsForm($massformid); $massiveactionparams = $data['search']['massiveactionparams']; $massiveactionparams['num_displayed'] = $end_display-$begin_display; $massiveactionparams['fixed'] = false; $massiveactionparams['is_deleted'] = $data['search']['is_deleted']; $massiveactionparams['container'] = $massformid; Html::showMassiveActions($massiveactionparams); } // Compute number of columns to display // Add toview elements $nbcols = count($data['data']['cols']); if (($data['display_type'] == self::HTML_OUTPUT) && $showmassiveactions) { // HTML display - massive modif $nbcols++; } // Display List Header echo self::showHeader($data['display_type'], $end_display-$begin_display+1, $nbcols); // New Line for Header Items Line $headers_line = ''; $headers_line_top = ''; $headers_line_bottom = ''; $headers_line_top .= self::showBeginHeader($data['display_type']); $headers_line_top .= self::showNewLine($data['display_type']); if ($data['display_type'] == self::HTML_OUTPUT) { // $headers_line_bottom .= self::showBeginHeader($data['display_type']); $headers_line_bottom .= self::showNewLine($data['display_type']); } $header_num = 1; if (($data['display_type'] == self::HTML_OUTPUT) && $showmassiveactions) { // HTML display - massive modif $headers_line_top .= self::showHeaderItem($data['display_type'], Html::getCheckAllAsCheckbox($massformid), $header_num, "", 0, $data['search']['order']); if ($data['display_type'] == self::HTML_OUTPUT) { $headers_line_bottom .= self::showHeaderItem($data['display_type'], Html::getCheckAllAsCheckbox($massformid), $header_num, "", 0, $data['search']['order']); } } // Display column Headers for toview items $metanames = []; foreach ($data['data']['cols'] as $val) { $linkto = ''; if (!$val['meta'] && !$data['search']['no_sort'] && (!isset($val['searchopt']['nosort']) || !$val['searchopt']['nosort'])) { $linkto = $data['search']['target'].(strpos($data['search']['target'], '?') ? '&' : '?'). "itemtype=".$data['itemtype']."&sort=". $val['id']."&order=". (($data['search']['order'] == "ASC") ?"DESC":"ASC"). "&start=".$data['search']['start']."&".$globallinkto; } $name = $val["name"]; // prefix by group name (corresponding to optgroup in dropdown) if exists if (isset($val['groupname'])) { $groupname = $val['groupname']; if (is_array($groupname)) { //since 9.2, getSearchOptions has been changed $groupname = $groupname['name']; } $name = "$groupname - $name"; } // Not main itemtype add itemtype to display if ($data['itemtype'] != $val['itemtype']) { if (!isset($metanames[$val['itemtype']])) { if ($metaitem = getItemForItemtype($val['itemtype'])) { $metanames[$val['itemtype']] = $metaitem->getTypeName(); } } $name = sprintf(__('%1$s - %2$s'), $metanames[$val['itemtype']], $val["name"]); } $headers_line .= self::showHeaderItem($data['display_type'], $name, $header_num, $linkto, (!$val['meta'] && ($data['search']['sort'] == $val['id'])), $data['search']['order']); } // Add specific column Header if (isset($CFG_GLPI["union_search_type"][$data['itemtype']])) { $headers_line .= self::showHeaderItem($data['display_type'], __('Item type'), $header_num); } // End Line for column headers $headers_line .= self::showEndLine($data['display_type']); $headers_line_top .= $headers_line; if ($data['display_type'] == self::HTML_OUTPUT) { $headers_line_bottom .= $headers_line; } $headers_line_top .= self::showEndHeader($data['display_type']); // $headers_line_bottom .= self::showEndHeader($data['display_type']); echo $headers_line_top; // Init list of items displayed if ($data['display_type'] == self::HTML_OUTPUT) { Session::initNavigateListItems($data['itemtype']); } // Num of the row (1=header_line) $row_num = 1; $massiveaction_field = 'id'; if (($data['itemtype'] != 'AllAssets') && isset($CFG_GLPI["union_search_type"][$data['itemtype']])) { $massiveaction_field = 'refID'; } $typenames = []; // Display Loop foreach ($data['data']['rows'] as $rowkey => $row) { // Column num $item_num = 1; $row_num++; // New line echo self::showNewLine($data['display_type'], ($row_num%2), $data['search']['is_deleted']); $current_type = (isset($row['TYPE']) ? $row['TYPE'] : $data['itemtype']); $massiveaction_type = $current_type; if (($data['itemtype'] != 'AllAssets') && isset($CFG_GLPI["union_search_type"][$data['itemtype']])) { $massiveaction_type = $data['itemtype']; } // Add item in item list Session::addToNavigateListItems($current_type, $row["id"]); if (($data['display_type'] == self::HTML_OUTPUT) && $showmassiveactions) { // HTML display - massive modif $tmpcheck = ""; if (($data['itemtype'] == 'Entity') && !in_array($row["id"], $_SESSION["glpiactiveentities"])) { $tmpcheck = " "; } else if ($data['itemtype'] == 'User' && !Session::canViewAllEntities() && !Session::haveAccessToOneOfEntities(Profile_User::getUserEntities($row["id"], false))) { $tmpcheck = " "; } else if (($data['item'] instanceof CommonDBTM) && $data['item']->maybeRecursive() && !in_array($row["entities_id"], $_SESSION["glpiactiveentities"])) { $tmpcheck = " "; } else { $tmpcheck = Html::getMassiveActionCheckBox($massiveaction_type, $row[$massiveaction_field]); } echo self::showItem($data['display_type'], $tmpcheck, $item_num, $row_num, "width='10'"); } // Print other toview items foreach ($data['data']['cols'] as $col) { $colkey = "{$col['itemtype']}_{$col['id']}"; if (!$col['meta']) { echo self::showItem($data['display_type'], $row[$colkey]['displayname'], $item_num, $row_num, self::displayConfigItem($data['itemtype'], $col['id'], $row, $colkey)); } else { // META case echo self::showItem($data['display_type'], $row[$colkey]['displayname'], $item_num, $row_num); } } if (isset($CFG_GLPI["union_search_type"][$data['itemtype']])) { if (!isset($typenames[$row["TYPE"]])) { if ($itemtmp = getItemForItemtype($row["TYPE"])) { $typenames[$row["TYPE"]] = $itemtmp->getTypeName(); } } echo self::showItem($data['display_type'], $typenames[$row["TYPE"]], $item_num, $row_num); } // End Line echo self::showEndLine($data['display_type']); // Flush ONLY for an HTML display (issue #3348) if ($data['display_type'] == self::HTML_OUTPUT && !$data['search']['dont_flush']) { Html::glpi_flush(); } } // Create title $title = ''; if (($data['display_type'] == self::PDF_OUTPUT_LANDSCAPE) || ($data['display_type'] == self::PDF_OUTPUT_PORTRAIT)) { $title = self::computeTitle($data); } if ($data['search']['show_footer']) { if ($data['display_type'] == self::HTML_OUTPUT) { echo $headers_line_bottom; } } // Display footer (close table) echo self::showFooter($data['display_type'], $title, $data['data']['count']); if ($data['search']['show_footer']) { // Delete selected item if ($data['display_type'] == self::HTML_OUTPUT) { if ($showmassiveactions) { $massiveactionparams['ontop'] = false; Html::showMassiveActions($massiveactionparams); // End form for delete item Html::closeForm(); } else { echo "
"; } } if ($data['display_type'] == self::HTML_OUTPUT && $data['search']['show_pager']) { // In case of HTML display Html::printPager($data['search']['start'], $data['data']['totalcount'], $data['search']['target'], $parameters, '', 0, $search_config_bottom); } } } } else { if (!isset($_GET['_in_modal'])) { echo "
"; if (null == $item || $item->maybeLocated()) { $map_link = ""; echo $map_link; } if ($item !== null && $item->maybeDeleted()) { echo self::isDeletedSwitch($data['search']['is_deleted'], $data['itemtype']); } echo "
"; } echo self::showError($data['display_type']); } } /** * @since 0.90 * * @param boolean $is_deleted * @param string $itemtype * * @return string */ static function isDeletedSwitch($is_deleted, $itemtype = "") { $rand = mt_rand(); return "
". "". "
"; } /** * Compute title (use case of PDF OUTPUT) * * @param array $data Array data of search * * @return string Title **/ static function computeTitle($data) { $title = ""; if (count($data['search']['criteria'])) { //Drop the first link as it is not needed, or convert to clean link (AND NOT -> NOT) if (isset($data['search']['criteria']['0']['link'])) { $notpos = strpos($data['search']['criteria']['0']['link'], 'NOT'); //If link was like '%NOT%' just use NOT. Otherwise remove the link if ($notpos > 0) { $data['search']['criteria']['0']['link'] = 'NOT'; } else if (!$notpos) { unset($data['search']['criteria']['0']['link']); } } foreach ($data['search']['criteria'] as $criteria) { if (isset($criteria['itemtype'])) { $searchopt = &self::getOptions($criteria['itemtype']); } else { $searchopt = &self::getOptions($data['itemtype']); } $titlecontain = ''; if (isset($criteria['criteria'])) { //This is a group criteria, call computeTitle again and concat $newdata = $data; $oldlink = $criteria['link']; $newdata['search'] = $criteria; $titlecontain = sprintf(__('%1$s %2$s (%3$s)'), $titlecontain, $oldlink, Search::computeTitle($newdata)); } else { if (strlen($criteria['value']) > 0) { if (isset($criteria['link'])) { $titlecontain = " ".$criteria['link']." "; } $gdname = ''; $valuename = ''; switch ($criteria['field']) { case "all" : $titlecontain = sprintf(__('%1$s %2$s'), $titlecontain, __('All')); break; case "view" : $titlecontain = sprintf(__('%1$s %2$s'), $titlecontain, __('Items seen')); break; default : if (isset($criteria['meta']) && $criteria['meta']) { $searchoptname = sprintf(__('%1$s / %2$s'), $criteria['itemtype'], $searchopt[$criteria['field']]["name"]); } else { $searchoptname = $searchopt[$criteria['field']]["name"]; } $titlecontain = sprintf(__('%1$s %2$s'), $titlecontain, $searchoptname); $itemtype = getItemTypeForTable($searchopt[$criteria['field']]["table"]); $valuename = ''; if ($item = getItemForItemtype($itemtype)) { $valuename = $item->getValueToDisplay($searchopt[$criteria['field']], $criteria['value']); } $gdname = Dropdown::getDropdownName($searchopt[$criteria['field']]["table"], $criteria['value']); } if (empty($valuename)) { $valuename = $criteria['value']; } switch ($criteria['searchtype']) { case "equals" : if (in_array($searchopt[$criteria['field']]["field"], ['name', 'completename'])) { $titlecontain = sprintf(__('%1$s = %2$s'), $titlecontain, $gdname); } else { $titlecontain = sprintf(__('%1$s = %2$s'), $titlecontain, $valuename); } break; case "notequals" : if (in_array($searchopt[$criteria['field']]["field"], ['name', 'completename'])) { $titlecontain = sprintf(__('%1$s <> %2$s'), $titlecontain, $gdname); } else { $titlecontain = sprintf(__('%1$s <> %2$s'), $titlecontain, $valuename); } break; case "lessthan" : $titlecontain = sprintf(__('%1$s < %2$s'), $titlecontain, $valuename); break; case "morethan" : $titlecontain = sprintf(__('%1$s > %2$s'), $titlecontain, $valuename); break; case "contains" : $titlecontain = sprintf(__('%1$s = %2$s'), $titlecontain, '%'.$valuename.'%'); break; case "notcontains" : $titlecontain = sprintf(__('%1$s <> %2$s'), $titlecontain, '%'.$valuename.'%'); break; case "under" : $titlecontain = sprintf(__('%1$s %2$s'), $titlecontain, sprintf(__('%1$s %2$s'), __('under'), $gdname)); break; case "notunder" : $titlecontain = sprintf(__('%1$s %2$s'), $titlecontain, sprintf(__('%1$s %2$s'), __('not under'), $gdname)); break; default : $titlecontain = sprintf(__('%1$s = %2$s'), $titlecontain, $valuename); break; } } } $title .= $titlecontain; } } if (isset($data['search']['metacriteria']) && count($data['search']['metacriteria'])) { $metanames = []; foreach ($data['search']['metacriteria'] as $metacriteria) { $searchopt = &self::getOptions($metacriteria['itemtype']); if (!isset($metanames[$metacriteria['itemtype']])) { if ($metaitem = getItemForItemtype($metacriteria['itemtype'])) { $metanames[$metacriteria['itemtype']] = $metaitem->getTypeName(); } } $titlecontain2 = ''; if (strlen($metacriteria['value']) > 0) { if (isset($metacriteria['link'])) { $titlecontain2 = sprintf(__('%1$s %2$s'), $titlecontain2, $metacriteria['link']); } $titlecontain2 = sprintf(__('%1$s %2$s'), $titlecontain2, sprintf(__('%1$s / %2$s'), $metanames[$metacriteria['itemtype']], $searchopt[$metacriteria['field']]["name"])); $gdname2 = Dropdown::getDropdownName($searchopt[$metacriteria['field']]["table"], $metacriteria['value']); switch ($metacriteria['searchtype']) { case "equals" : if (in_array($searchopt[$metacriteria['link']] ["field"], ['name', 'completename'])) { $titlecontain2 = sprintf(__('%1$s = %2$s'), $titlecontain2, $gdname2); } else { $titlecontain2 = sprintf(__('%1$s = %2$s'), $titlecontain2, $metacriteria['value']); } break; case "notequals" : if (in_array($searchopt[$metacriteria['link']]["field"], ['name', 'completename'])) { $titlecontain2 = sprintf(__('%1$s <> %2$s'), $titlecontain2, $gdname2); } else { $titlecontain2 = sprintf(__('%1$s <> %2$s'), $titlecontain2, $metacriteria['value']); } break; case "lessthan" : $titlecontain2 = sprintf(__('%1$s < %2$s'), $titlecontain2, $metacriteria['value']); break; case "morethan" : $titlecontain2 = sprintf(__('%1$s > %2$s'), $titlecontain2, $metacriteria['value']); break; case "contains" : $titlecontain2 = sprintf(__('%1$s = %2$s'), $titlecontain2, '%'.$metacriteria['value'].'%'); break; case "notcontains" : $titlecontain2 = sprintf(__('%1$s <> %2$s'), $titlecontain2, '%'.$metacriteria['value'].'%'); break; case "under" : $titlecontain2 = sprintf(__('%1$s %2$s'), $titlecontain2, sprintf(__('%1$s %2$s'), __('under'), $gdname2)); break; case "notunder" : $titlecontain2 = sprintf(__('%1$s %2$s'), $titlecontain2, sprintf(__('%1$s %2$s'), __('not under'), $gdname2)); break; default : $titlecontain2 = sprintf(__('%1$s = %2$s'), $titlecontain2, $metacriteria['value']); break; } } $title .= $titlecontain2; } } return $title; } /** * Get meta types available for search engine * * @param string $itemtype Type to display the form * * @return array Array of available itemtype **/ static function getMetaItemtypeAvailable($itemtype) { // Display meta search items $linked = []; // Define meta search items to linked switch (static::getMetaReferenceItemtype($itemtype)) { case 'Computer' : $linked = ['Monitor', 'Peripheral', 'Phone', 'Printer', 'Software', 'User', 'Group', 'Budget']; break; case 'Ticket' : if (Session::haveRight("ticket", Ticket::READALL)) { $linked = array_keys(Ticket::getAllTypesForHelpdesk()); } break; case 'Problem' : if (Session::haveRight("problem", Problem::READALL)) { $linked = array_keys(Problem::getAllTypesForHelpdesk()); } break; case 'Change' : if (Session::haveRight("change", Change::READALL)) { $linked = array_keys(Change::getAllTypesForHelpdesk()); } break; case 'Printer' : case 'Monitor' : case "Peripheral" : case "Software" : case "Phone" : $linked = ['Computer', 'User', 'Group', 'Budget']; break; } return $linked; } /** * @since 0.85 * * @param $itemtype **/ static function getMetaReferenceItemtype ($itemtype) { $types = [ 'Computer', 'Problem', 'Change', 'Ticket', 'Printer', 'Monitor', 'Peripheral', 'Software', 'Phone' ]; foreach ($types as $type) { if (is_a($itemtype, $type, true)) { return $type; } } return false; } /** * @since 0.85 **/ static function getLogicalOperators($only_not = false) { if ($only_not) { return [ 'AND' => Dropdown::EMPTY_VALUE, 'AND NOT' => __("NOT") ]; } return [ 'AND' => __('AND'), 'OR' => __('OR'), 'AND NOT' => __('AND NOT'), 'OR NOT' => __('OR NOT') ]; } /** * Print generic search form * * Params need to parsed before using Search::manageParams function * * @param string $itemtype Type to display the form * @param array $params Array of parameters may include sort, is_deleted, criteria, metacriteria * * @return void **/ static function showGenericSearch($itemtype, array $params) { global $CFG_GLPI; // Default values of parameters $p['sort'] = ''; $p['is_deleted'] = 0; $p['as_map'] = 0; $p['criteria'] = []; $p['metacriteria'] = []; if (class_exists($itemtype)) { $p['target'] = $itemtype::getSearchURL(); } else { $p['target'] = Toolbox::getItemTypeSearchURL($itemtype); } $p['showreset'] = true; $p['showbookmark'] = true; $p['showfolding'] = true; $p['mainform'] = true; $p['prefix_crit'] = ''; $p['addhidden'] = []; $p['actionname'] = 'search'; $p['actionvalue'] = _sx('button', 'Search'); foreach ($params as $key => $val) { $p[$key] = $val; } $main_block_class = ''; if ($p['mainform']) { echo "
"; } else { $main_block_class = "sub_criteria"; } echo "
"; $nbsearchcountvar = 'nbcriteria'.strtolower($itemtype).mt_rand(); $searchcriteriatableid = 'criteriatable'.strtolower($itemtype).mt_rand(); // init criteria count echo Html::scriptBlock(" var $nbsearchcountvar = ".count($p['criteria'])."; "); echo ""; echo "
"; $linked = self::getMetaItemtypeAvailable($itemtype); echo " ".__s('rule')." "; if (count($linked)) { echo " ".__s('global rule')." "; } echo " ".__s('group')." "; $json_p = json_encode($p); if ($p['mainform']) { // Display submit button echo ""; if ($p['showbookmark'] || $p['showreset']) { if ($p['showbookmark']) { //TODO: change that! Ajax::createIframeModalWindow('loadbookmark', SavedSearch::getSearchURL() . "?action=load&type=" . SavedSearch::SEARCH, ['title' => __('Load a saved search')]); SavedSearch::showSaveButton(SavedSearch::SEARCH, $itemtype); } if ($p['showreset']) { echo "" . __s('Blank') .""; } if ($p['showfolding']) { echo ""; } } } echo "
"; //.search_actions $JS = << $val) { echo Html::hidden($key, ['value' => $val]); } } if ($p['mainform']) { // For dropdown echo Html::hidden('itemtype', ['value' => $itemtype]); // Reset to start when submit new search echo Html::hidden('start', ['value' => 0]); } echo "
"; if ($p['mainform']) { Html::closeForm(); } } /** * Display a criteria field set, this function should be called by ajax/search.php * * @since 9.4 * * @param array $request we should have these keys of parameters: * - itemtype: main itemtype for criteria, sub one for metacriteria * - num: index of the criteria * - p: params of showGenericSearch method * * @return void */ static function displayCriteria($request = []) { global $CFG_GLPI; if (!isset($request["itemtype"]) || !isset($request["num"])) { return ""; } $num = (int) $request['num']; $p = $request['p']; $options = self::getCleanedOptions($request["itemtype"]); $randrow = mt_rand(); $rowid = 'searchrow'.$request['itemtype'].$randrow; $addclass = $num == 0 ? ' headerRow' : ''; $prefix = isset($p['prefix_crit']) ? $p['prefix_crit'] :''; $parents_num = isset($p['parents_num']) ? $p['parents_num'] : []; $criteria = []; $sess_itemtype = $request["itemtype"]; if (isset($request['from_meta']) && $request['from_meta']) { $sess_itemtype = $request["parent_itemtype"]; } if (!$criteria = self::findCriteriaInSession($sess_itemtype, $num, $parents_num)) { $criteria = self::getDefaultCriteria($request["itemtype"]); } if (isset($criteria['meta']) && $criteria['meta'] && (!isset($request['from_meta']) || !$request['from_meta'])) { return self::displayMetaCriteria($request); } if (isset($criteria['criteria']) && is_array($criteria['criteria'])) { return self::displayCriteriaGroup($request); } echo "
  • "; if (!isset($request['from_meta']) || !$request['from_meta']) { // First line display add / delete images for normal and meta search items if ($num == 0 && isset($p['mainform']) && $p['mainform']) { // Instanciate an object to access method $item = null; if ($request["itemtype"] != 'AllAssets') { $item = getItemForItemtype($request["itemtype"]); } if ($item && $item->maybeDeleted()) { echo Html::hidden('is_deleted', [ 'value' => $p['is_deleted'], 'id' => 'is_deleted' ]); } echo Html::hidden('as_map', [ 'value' => $p['as_map'], 'id' => 'as_map' ]); } echo " "; } // Display link item $value = ''; if (!isset($request['from_meta']) || !$request['from_meta']) { if (isset($criteria["link"])) { $value = $criteria["link"]; } $operators = Search::getLogicalOperators(($num == 0)); Dropdown::showFromArray("criteria{$prefix}[$num][link]", $operators, [ 'value' => $value, 'width' => '80px' ]); } $values = []; // display select box to define search item if ($CFG_GLPI['allow_search_view'] == 2 && !isset($request['from_meta'])) { $values['view'] = __('Items seen'); } reset($options); $group = ''; foreach ($options as $key => $val) { // print groups if (!is_array($val)) { $group = $val; } else if (count($val) == 1) { $group = $val['name']; } else { if (!isset($val['nosearch']) || ($val['nosearch'] == false)) { $values[$group][$key] = $val["name"]; } } } if ($CFG_GLPI['allow_search_view'] == 1 && !isset($request['from_meta'])) { $values['view'] = __('Items seen'); } if ($CFG_GLPI['allow_search_all'] && !isset($request['from_meta'])) { $values['all'] = __('All'); } $value = ''; if (isset($criteria['field'])) { $value = $criteria['field']; } $rand = Dropdown::showFromArray("criteria{$prefix}[$num][field]", $values, [ 'value' => $value, 'width' => '170px' ]); $field_id = Html::cleanId("dropdown_criteria{$prefix}[$num][field]$rand"); $spanid = Html::cleanId('SearchSpan'.$request["itemtype"].$prefix.$num); echo ""; $used_itemtype = $request["itemtype"]; // Force Computer itemtype for AllAssets to permit to show specific items if ($request["itemtype"] == 'AllAssets') { $used_itemtype = 'Computer'; } $searchtype = isset($criteria['searchtype']) ? $criteria['searchtype'] : ""; $p_value = isset($criteria['value']) ? stripslashes($criteria['value']) : ""; $params = [ 'itemtype' => $used_itemtype, 'field' => $value, 'searchtype' => $searchtype, 'value' => $p_value, 'num' => $num, 'p' => $p, ]; Search::displaySearchoption($params); echo ""; Ajax::updateItemOnSelectEvent( $field_id, $spanid, $CFG_GLPI["root_doc"]."/ajax/search.php", [ 'action' => 'display_searchoption', 'field' => '__VALUE__', ] + $params ); echo "
  • "; } /** * Display a meta-criteria field set, this function should be called by ajax/search.php * Call displayCriteria method after displaying its itemtype field * * @since 9.4 * * @param array $request @see displayCriteria method * * @return void */ static function displayMetaCriteria($request = []) { global $CFG_GLPI; if (!isset($request["itemtype"]) || !isset($request["num"])) { return ""; } $p = $request['p']; $num = (int) $request['num']; $prefix = isset($p['prefix_crit']) ? $p['prefix_crit'] : ''; $parents_num = isset($p['parents_num']) ? $p['parents_num'] : []; $itemtype = $request["itemtype"]; $metacriteria = []; if (!$metacriteria = self::findCriteriaInSession($itemtype, $num, $parents_num)) { // Set default field $options = Search::getCleanedOptions($itemtype); foreach ($options as $key => $val) { if (is_array($val) && isset($val['table'])) { $metacriteria['field'] = $key; break; } } } $linked = Search::getMetaItemtypeAvailable($itemtype); $rand = mt_rand(); $rowid = 'metasearchrow'.$request['itemtype'].$rand; echo "
  • "; echo " "; // Display link item (not for the first item) Dropdown::showFromArray( "criteria{$prefix}[$num][link]", Search::getLogicalOperators(), [ 'value' => isset($metacriteria["link"]) ? $metacriteria["link"] : "", 'width' => '80px' ] ); // Display select of the linked item type available $rand = Dropdown::showItemTypes("criteria{$prefix}[$num][itemtype]", $linked, [ 'value' => isset($metacriteria['itemtype']) && !empty($metacriteria['itemtype']) ? $metacriteria['itemtype'] : "", 'width' => '170px' ]); echo Html::hidden("criteria{$prefix}[$num][meta]", [ 'value' => true ]); $field_id = Html::cleanId("dropdown_criteria{$prefix}[$num][itemtype]$rand"); $spanid = Html::cleanId("show_".$request["itemtype"]."_".$prefix.$num."_$rand"); // Ajax script for display search met& item echo "
    "; $params = [ 'action' => 'display_criteria', 'itemtype' => '__VALUE__', 'parent_itemtype' => $request['itemtype'], 'from_meta' => true, 'num' => $num, 'p' => $request["p"], ]; Ajax::updateItemOnSelectEvent( $field_id, $spanid, $CFG_GLPI["root_doc"]."/ajax/search.php", $params ); echo ""; if (isset($metacriteria['itemtype']) && !empty($metacriteria['itemtype'])) { $params['itemtype'] = $metacriteria['itemtype']; self::displayCriteria($params); } echo ""; echo "
    "; echo "
  • "; } /** * Display a group of nested criteria. * A group (parent) criteria can contains children criteria (who also cantains children, etc) * * @since 9.4 * * @param array $request @see displayCriteria method * * @return void */ static function displayCriteriaGroup($request = []) { $num = (int) $request['num']; $p = $request['p']; $randrow = mt_rand(); $rowid = 'searchrow'.$request['itemtype'].$randrow; $addclass = $num == 0 ? ' headerRow' : ''; $prefix = isset($p['prefix_crit']) ? $p['prefix_crit'] : ''; $parents_num = isset($p['parents_num']) ? $p['parents_num'] : []; if (!$criteria = self::findCriteriaInSession($request['itemtype'], $num, $parents_num)) { $criteria = [ 'criteria' => self::getDefaultCriteria($request['itemtype']), ]; } echo "
  • "; echo " "; Dropdown::showFromArray("criteria{$prefix}[$num][link]", Search::getLogicalOperators(), [ 'value' => isset($criteria["link"]) ? $criteria["link"] : '', 'width' => '80px' ]); $parents_num = isset($p['parents_num']) ? $p['parents_num'] : []; array_push($parents_num, $num); $params = [ 'mainform' => false, 'prefix_crit' => "{$prefix}[$num][criteria]", 'parents_num' => $parents_num, 'criteria' => $criteria['criteria'], ]; echo self::showGenericSearch($request['itemtype'], $params); echo "
  • "; } /** * Retrieve a single criteria in Session by its index * * @since 9.4 * * @param string $itemtype which glpi type we must search in session * @param integer $num index of the criteria * @param array $parents_num node indexes of the parents (@see displayCriteriaGroup) * * @return mixed the found criteria array of false of nothing found */ static function findCriteriaInSession($itemtype = '', $num = 0, $parents_num = []) { if (!isset($_SESSION['glpisearch'][$itemtype]['criteria'])) { return false; } $criteria = &$_SESSION['glpisearch'][$itemtype]['criteria']; if (count($parents_num)) { foreach ($parents_num as $parent) { if (!isset($criteria[$parent]['criteria'])) { return false; } $criteria = &$criteria[$parent]['criteria']; } } if (isset($criteria[$num]) && is_array($criteria[$num])) { return $criteria[$num]; } return false; } /** * construct the default criteria for an itemtype * * @since 9.4 * * @param string $itemtype * * @return array criteria */ static function getDefaultCriteria($itemtype = '') { global $CFG_GLPI; $field = ''; if ($CFG_GLPI['allow_search_view'] == 2) { $field = 'view'; } else { $options = self::getCleanedOptions($itemtype); foreach ($options as $key => $val) { if (is_array($val) && isset($val['table'])) { $field = $key; break; } } } return [ [ 'field' => $field, 'link' => 'contains', 'value' => '' ] ]; } /** * Display first part of criteria (field + searchtype, just after link) * will call displaySearchoptionValue for the next part (value) * * @since 9.4 * * @param array $request we should have these keys of parameters: * - itemtype: main itemtype for criteria, sub one for metacriteria * - num: index of the criteria * - field: field key of the criteria * - p: params of showGenericSearch method * * @return void */ static function displaySearchoption($request = []) { global $CFG_GLPI; if (!isset($request["itemtype"]) || !isset($request["field"]) || !isset($request["num"])) { return ""; } $p = $request['p']; $num = (int) $request['num']; $prefix = isset($p['prefix_crit']) ? $p['prefix_crit'] : ''; if (!is_subclass_of($request['itemtype'], 'CommonDBTM')) { throw new \RuntimeException('Invalid itemtype provided!'); } if (isset($request['meta']) && $request['meta']) { $fieldname = 'metacriteria'; } else { $fieldname = 'criteria'; $request['meta'] = 0; } $actions = Search::getActionsFor($request["itemtype"], $request["field"]); // is it a valid action for type ? if (count($actions) && (empty($request['searchtype']) || !isset($actions[$request['searchtype']]))) { $tmp = $actions; unset($tmp['searchopt']); $request['searchtype'] = key($tmp); unset($tmp); } $rands = -1; $dropdownname = Html::cleanId("spansearchtype$fieldname". $request["itemtype"]. $prefix. $num); $searchopt = []; if (count($actions)>0) { // get already get search options if (isset($actions['searchopt'])) { $searchopt = $actions['searchopt']; // No name for clean array with quotes unset($searchopt['name']); unset($actions['searchopt']); } $searchtype_name = "{$fieldname}{$prefix}[$num][searchtype]"; $rands = Dropdown::showFromArray($searchtype_name, $actions, [ 'value' => $request["searchtype"], 'width' => '105px' ]); $fieldsearch_id = Html::cleanId("dropdown_$searchtype_name$rands"); } echo ""; $params = [ 'value' => rawurlencode(stripslashes($request['value'])), 'searchopt' => $searchopt, 'searchtype' => $request["searchtype"], 'num' => $num, 'itemtype' => $request["itemtype"], 'from_meta' => isset($request['from_meta']) ? $request['from_meta'] : false, 'field' => $request["field"], 'p' => $p, ]; self::displaySearchoptionValue($params); echo ""; Ajax::updateItemOnSelectEvent( $fieldsearch_id, $dropdownname, $CFG_GLPI["root_doc"]."/ajax/search.php", [ 'action' => 'display_searchoption_value', 'searchtype' => '__VALUE__', ] + $params ); } /** * Display last part of criteria (value, just after searchtype) * called by displaySearchoptionValue * * @since 9.4 * * @param array $request we should have these keys of parameters: * - searchtype: (contains, equals) passed by displaySearchoption * * @return void */ static function displaySearchoptionValue($request = []) { if (!isset($request['searchtype'])) { return ""; } $p = $request['p']; $prefix = isset($p['prefix_crit']) ? $p['prefix_crit'] : ''; $searchopt = isset($request['searchopt']) ? $request['searchopt'] : []; $request['value'] = rawurldecode($request['value']); $fieldname = isset($request['meta']) && $request['meta'] ? 'metacriteria' : 'criteria'; $inputname = $fieldname.$prefix.'['.$request['num'].'][value]'; $display = false; $item = getItemForItemtype($request['itemtype']); $options2 = []; $options2['value'] = $request['value']; $options2['width'] = '100%'; // For tree dropdpowns $options2['permit_select_parent'] = true; switch ($request['searchtype']) { case "equals" : case "notequals" : case "morethan" : case "lessthan" : case "under" : case "notunder" : if (!$display && isset($searchopt['field'])) { // Specific cases switch ($searchopt['table'].".".$searchopt['field']) { // Add mygroups choice to searchopt case "glpi_groups.completename" : $searchopt['toadd'] = ['mygroups' => __('My groups')]; break; case "glpi_changes.status" : case "glpi_changes.impact" : case "glpi_changes.urgency" : case "glpi_problems.status" : case "glpi_problems.impact" : case "glpi_problems.urgency" : case "glpi_tickets.status" : case "glpi_tickets.impact" : case "glpi_tickets.urgency" : $options2['showtype'] = 'search'; break; case "glpi_changes.priority" : case "glpi_problems.priority" : case "glpi_tickets.priority" : $options2['showtype'] = 'search'; $options2['withmajor'] = true; break; case "glpi_tickets.global_validation" : $options2['all'] = true; break; case "glpi_ticketvalidations.status" : $options2['all'] = true; break; case "glpi_users.name" : $options2['right'] = (isset($searchopt['right']) ? $searchopt['right'] : 'all'); $options2['inactive_deleted'] = 1; break; } // Standard datatype usage if (!$display && isset($searchopt['datatype'])) { switch ($searchopt['datatype']) { case "date" : case "date_delay" : case "datetime" : $options2['relative_dates'] = true; break; } } $out = $item->getValueToSelect($searchopt, $inputname, $request['value'], $options2); if (strlen($out)) { echo $out; $display = true; } //Could display be handled by a plugin ? if (!$display && $plug = isPluginItemType(getItemTypeForTable($searchopt['table']))) { $display = Plugin::doOneHook( $plug['plugin'], 'searchOptionsValues', [ 'name' => $inputname, 'searchtype' => $request['searchtype'], 'searchoption' => $searchopt, 'value' => $request['value'] ] ); } } break; } // Default case : text field if (!$display) { echo ""; } } /** * Generic Function to add GROUP BY to a request * * @since 9.4: $num param has been dropped * * @param string $LINK link to use * @param string $NOT is is a negative search ? * @param string $itemtype item type * @param integer $ID ID of the item to search * @param string $searchtype search type ('contains' or 'equals') * @param string $val value search * * @return select string **/ static function addHaving($LINK, $NOT, $itemtype, $ID, $searchtype, $val) { global $DB; $searchopt = &self::getOptions($itemtype); if (!isset($searchopt[$ID]['table'])) { return false; } $table = $searchopt[$ID]["table"]; $NAME = "ITEM_{$itemtype}_{$ID}"; // Plugin can override core definition for its type if ($plug = isPluginItemType($itemtype)) { $out = Plugin::doOneHook( $plug['plugin'], 'addHaving', $LINK, $NOT, $itemtype, $ID, $val, "{$itemtype}_{$ID}" ); if (!empty($out)) { return $out; } } //// Default cases // Link with plugin tables if (preg_match("/^glpi_plugin_([a-z0-9]+)/", $table, $matches)) { if (count($matches) == 2) { $plug = $matches[1]; $out = Plugin::doOneHook( $plug, 'addHaving', $LINK, $NOT, $itemtype, $ID, $val, "{$itemtype}_{$ID}" ); if (!empty($out)) { return $out; } } } if (in_array($searchtype, ["notequals", "notcontains"])) { $NOT = !$NOT; } // Preformat items if (isset($searchopt[$ID]["datatype"])) { switch ($searchopt[$ID]["datatype"]) { case "datetime" : if (in_array($searchtype, ['contains', 'notcontains'])) { break; } $force_day = false; if (strstr($val, 'BEGIN') || strstr($val, 'LAST')) { $force_day = true; } $val = Html::computeGenericDateTimeSearch($val, $force_day); $operator = ''; switch ($searchtype) { case 'equals': $operator = !$NOT ? '=' : '!='; break; case 'notequals': $operator = !$NOT ? '!=' : '='; break; case 'lessthan': $operator = !$NOT ? '<' : '>'; break; case 'morethan': $operator = !$NOT ? '>' : '<'; break; } return " {$LINK} ({$DB->quoteName($NAME)} $operator {$DB->quoteValue($val)}) "; break; case "count" : case "number" : case "decimal" : case "timestamp" : $search = ["/\</","/\>/"]; $replace = ["<",">"]; $val = preg_replace($search, $replace, $val); if (preg_match("/([<>])([=]*)[[:space:]]*([0-9]+)/", $val, $regs)) { if ($NOT) { if ($regs[1] == '<') { $regs[1] = '>'; } else { $regs[1] = '<'; } } $regs[1] .= $regs[2]; return " $LINK (`$NAME` ".$regs[1]." ".$regs[3]." ) "; } if (is_numeric($val)) { if (isset($searchopt[$ID]["width"])) { if (!$NOT) { return " $LINK (`$NAME` < ".(intval($val) + $searchopt[$ID]["width"])." AND `$NAME` > ". (intval($val) - $searchopt[$ID]["width"]).") "; } return " $LINK (`$NAME` > ".(intval($val) + $searchopt[$ID]["width"])." OR `$NAME` < ". (intval($val) - $searchopt[$ID]["width"])." ) "; } // Exact search if (!$NOT) { return " $LINK (`$NAME` = ".(intval($val)).") "; } return " $LINK (`$NAME` <> ".(intval($val)).") "; } break; } } return self::makeTextCriteria("`$NAME`", $val, $NOT, $LINK); } /** * Generic Function to add ORDER BY to a request * * @since 9.4: $key param has been dropped * * @param string $itemtype ID of the device type * @param integer $ID field to add * @param string $order order define * * @return select string * **/ static function addOrderBy($itemtype, $ID, $order) { global $CFG_GLPI; // Security test for order if ($order != "ASC") { $order = "DESC"; } $searchopt = &self::getOptions($itemtype); $table = $searchopt[$ID]["table"]; $field = $searchopt[$ID]["field"]; $addtable = ''; $is_fkey_composite_on_self = getTableNameForForeignKeyField($searchopt[$ID]["linkfield"]) == $table && $searchopt[$ID]["linkfield"] != getForeignKeyFieldForTable($table); $orig_table = self::getOrigTableName($itemtype); if (($is_fkey_composite_on_self || $table != $orig_table) && ($searchopt[$ID]["linkfield"] != getForeignKeyFieldForTable($table))) { $addtable .= "_".$searchopt[$ID]["linkfield"]; } if (isset($searchopt[$ID]['joinparams'])) { $complexjoin = self::computeComplexJoinID($searchopt[$ID]['joinparams']); if (!empty($complexjoin)) { $addtable .= "_".$complexjoin; } } if (isset($CFG_GLPI["union_search_type"][$itemtype])) { return " ORDER BY ITEM_{$itemtype}_{$ID} $order "; } // Plugin can override core definition for its type if ($plug = isPluginItemType($itemtype)) { $out = Plugin::doOneHook( $plug['plugin'], 'addOrderBy', $itemtype, $ID, $order, "{$itemtype}_{$ID}" ); if (!empty($out)) { return $out; } } switch ($table.".".$field) { case "glpi_auth_tables.name" : $user_searchopt = self::getOptions('User'); return " ORDER BY `glpi_users`.`authtype` $order, `glpi_authldaps".$addtable."_". self::computeComplexJoinID($user_searchopt[30]['joinparams'])."`. `name` $order, `glpi_authmails".$addtable."_". self::computeComplexJoinID($user_searchopt[31]['joinparams'])."`. `name` $order "; case "glpi_users.name" : if ($itemtype!='User') { if ($_SESSION["glpinames_format"] == User::FIRSTNAME_BEFORE) { $name1 = 'firstname'; $name2 = 'realname'; } else { $name1 = 'realname'; $name2 = 'firstname'; } return " ORDER BY ".$table.$addtable.".$name1 $order, ".$table.$addtable.".$name2 $order, ".$table.$addtable.".`name` $order"; } return " ORDER BY `".$table.$addtable."`.`name` $order"; case "glpi_networkequipments.ip" : case "glpi_ipaddresses.name" : return " ORDER BY INET_ATON($table$addtable.$field) $order "; } //// Default cases // Link with plugin tables if (preg_match("/^glpi_plugin_([a-z0-9]+)/", $table, $matches)) { if (count($matches) == 2) { $plug = $matches[1]; $out = Plugin::doOneHook( $plug, 'addOrderBy', $itemtype, $ID, $order, "{$itemtype}_{$ID}" ); if (!empty($out)) { return $out; } } } // Preformat items if (isset($searchopt[$ID]["datatype"])) { switch ($searchopt[$ID]["datatype"]) { case "date_delay" : $interval = "MONTH"; if (isset($searchopt[$ID]['delayunit'])) { $interval = $searchopt[$ID]['delayunit']; } $add_minus = ''; if (isset($searchopt[$ID]["datafields"][3])) { $add_minus = "- `$table$addtable`.`".$searchopt[$ID]["datafields"][3]."`"; } return " ORDER BY ADDDATE(`$table$addtable`.`".$searchopt[$ID]["datafields"][1]."`, INTERVAL (`$table$addtable`.`". $searchopt[$ID]["datafields"][2]."` $add_minus) $interval) $order "; } } return " ORDER BY ITEM_{$itemtype}_{$ID} $order "; } /** * Generic Function to add default columns to view * * @param string $itemtype device type * @param array $params array of parameters * * @return select string **/ static function addDefaultToView($itemtype, $params) { global $CFG_GLPI; $toview = []; $item = null; $entity_check = true; if ($itemtype != 'AllAssets') { $item = getItemForItemtype($itemtype); $entity_check = $item->isEntityAssign(); } // Add first element (name) array_push($toview, 1); if (isset($params['as_map']) && $params['as_map'] == 1) { // Add location name when map mode array_push($toview, ($itemtype == 'Location' ? 1 : ($itemtype == 'Ticket' ? 83 : 3))); } // Add entity view : if (Session::isMultiEntitiesMode() && $entity_check && (isset($CFG_GLPI["union_search_type"][$itemtype]) || ($item && $item->maybeRecursive()) || isset($_SESSION['glpiactiveentities']) && (count($_SESSION["glpiactiveentities"]) > 1))) { array_push($toview, 80); } return $toview; } /** * Generic Function to add default select to a request * * @param string $itemtype device type * * @return string Select string **/ static function addDefaultSelect($itemtype) { global $DB; $itemtable = self::getOrigTableName($itemtype); $item = null; $mayberecursive = false; if ($itemtype != 'AllAssets') { $item = getItemForItemtype($itemtype); $mayberecursive = $item->maybeRecursive(); } $ret = ""; switch ($itemtype) { case 'FieldUnicity' : $ret = "`glpi_fieldunicities`.`itemtype` AS ITEMTYPE,"; break; default : // Plugin can override core definition for its type if ($plug = isPluginItemType($itemtype)) { $ret = Plugin::doOneHook( $plug['plugin'], 'addDefaultSelect', $itemtype ); } } if ($itemtable == 'glpi_entities') { $ret .= "`$itemtable`.`id` AS entities_id, '1' AS is_recursive, "; } else if ($mayberecursive) { if ($item->isField('entities_id')) { $ret .= $DB->quoteName("$itemtable.entities_id").", "; } if ($item->isField('is_recursive')) { $ret .= $DB->quoteName("$itemtable.is_recursive").", "; } } return $ret; } /** * Generic Function to add select to a request * * @since 9.4: $num param has been dropped * * @param string $itemtype item type * @param integer $ID ID of the item to add * @param boolean $meta boolean is a meta * @param integer $meta_type meta type table ID (default 0) * * @return string Select string **/ static function addSelect($itemtype, $ID, $meta = 0, $meta_type = 0) { global $DB, $CFG_GLPI; $searchopt = &self::getOptions($itemtype); $table = $searchopt[$ID]["table"]; $field = $searchopt[$ID]["field"]; $addtable = ""; $addtable2 = ""; $NAME = "ITEM_{$itemtype}_{$ID}"; $complexjoin = ''; if (isset($searchopt[$ID]['joinparams'])) { $complexjoin = self::computeComplexJoinID($searchopt[$ID]['joinparams']); } $is_fkey_composite_on_self = getTableNameForForeignKeyField($searchopt[$ID]["linkfield"]) == $table && $searchopt[$ID]["linkfield"] != getForeignKeyFieldForTable($table); $orig_table = self::getOrigTableName($itemtype); if (((($is_fkey_composite_on_self || $table != $orig_table) && (!isset($CFG_GLPI["union_search_type"][$itemtype]) || ($CFG_GLPI["union_search_type"][$itemtype] != $table))) || !empty($complexjoin)) && ($searchopt[$ID]["linkfield"] != getForeignKeyFieldForTable($table))) { $addtable .= "_".$searchopt[$ID]["linkfield"]; } if (!empty($complexjoin)) { $addtable .= "_".$complexjoin; $addtable2 .= "_".$complexjoin; } if ($meta) { // $NAME = "META"; if ($meta_type::getTable() != $table) { $addtable .= "_".$meta_type; $addtable2 .= "_".$meta_type; } } // Plugin can override core definition for its type if ($plug = isPluginItemType($itemtype)) { $out = Plugin::doOneHook( $plug['plugin'], 'addSelect', $itemtype, $ID, "{$itemtype}_{$ID}" ); if (!empty($out)) { return $out; } } $tocompute = "`$table$addtable`.`$field`"; $tocomputeid = "`$table$addtable`.`id`"; $tocomputetrans = "IFNULL(`$table".$addtable."_trans`.`value`,'".self::NULLVALUE."') "; $ADDITONALFIELDS = ''; if (isset($searchopt[$ID]["additionalfields"]) && count($searchopt[$ID]["additionalfields"])) { foreach ($searchopt[$ID]["additionalfields"] as $key) { if ($meta || (isset($searchopt[$ID]["forcegroupby"]) && $searchopt[$ID]["forcegroupby"])) { $ADDITONALFIELDS .= " IFNULL(GROUP_CONCAT(DISTINCT CONCAT(IFNULL(`$table$addtable`.`$key`, '".self::NULLVALUE."'), '".self::SHORTSEP."', $tocomputeid) SEPARATOR '".self::LONGSEP."'), '".self::NULLVALUE.self::SHORTSEP."') AS `".$NAME."_$key`, "; } else { $ADDITONALFIELDS .= "`$table$addtable`.`$key` AS `".$NAME."_$key`, "; } } } // Virtual display no select : only get additional fields if (strpos($field, '_virtual') === 0) { return $ADDITONALFIELDS; } switch ($table.".".$field) { case "glpi_users.name" : if ($itemtype != 'User') { if ((isset($searchopt[$ID]["forcegroupby"]) && $searchopt[$ID]["forcegroupby"])) { $addaltemail = ""; if ((($itemtype == 'Ticket') || ($itemtype == 'Problem')) && isset($searchopt[$ID]['joinparams']['beforejoin']['table']) && (($searchopt[$ID]['joinparams']['beforejoin']['table'] == 'glpi_tickets_users') || ($searchopt[$ID]['joinparams']['beforejoin']['table'] == 'glpi_problems_users') || ($searchopt[$ID]['joinparams']['beforejoin']['table'] == 'glpi_changes_users'))) { // For tickets_users $ticket_user_table = $searchopt[$ID]['joinparams']['beforejoin']['table']. "_".self::computeComplexJoinID($searchopt[$ID]['joinparams']['beforejoin'] ['joinparams']); $addaltemail = "GROUP_CONCAT(DISTINCT CONCAT(`$ticket_user_table`.`users_id`, ' ', `$ticket_user_table`.`alternative_email`) SEPARATOR '".self::LONGSEP."') AS `".$NAME."_2`, "; } return " GROUP_CONCAT(DISTINCT `$table$addtable`.`id` SEPARATOR '".self::LONGSEP."') AS `".$NAME."`, $addaltemail $ADDITONALFIELDS"; } return " `$table$addtable`.`$field` AS `".$NAME."`, `$table$addtable`.`realname` AS `".$NAME."_realname`, `$table$addtable`.`id` AS `".$NAME."_id`, `$table$addtable`.`firstname` AS `".$NAME."_firstname`, $ADDITONALFIELDS"; } break; case "glpi_softwarelicenses.number" : if ($meta) { return " FLOOR(SUM(`$table$addtable2`.`$field`) * COUNT(DISTINCT `$table$addtable2`.`id`) / COUNT(`$table$addtable2`.`id`)) AS `".$NAME."`, MIN(`$table$addtable2`.`$field`) AS `".$NAME."_min`, $ADDITONALFIELDS"; } else { return " FLOOR(SUM(`$table$addtable`.`$field`) * COUNT(DISTINCT `$table$addtable`.`id`) / COUNT(`$table$addtable`.`id`)) AS `".$NAME."`, MIN(`$table$addtable`.`$field`) AS `".$NAME."_min`, $ADDITONALFIELDS"; } case "glpi_profiles.name" : if (($itemtype == 'User') && ($ID == 20)) { $addtable2 = ''; if ($meta) { $addtable2 = "_".$meta_type; } return " GROUP_CONCAT(`$table$addtable`.`$field` SEPARATOR '".self::LONGSEP."') AS `".$NAME."`, GROUP_CONCAT(`glpi_profiles_users$addtable2`.`entities_id` SEPARATOR '".self::LONGSEP."') AS `".$NAME."_entities_id`, GROUP_CONCAT(`glpi_profiles_users$addtable2`.`is_recursive` SEPARATOR '".self::LONGSEP."') AS `".$NAME."_is_recursive`, GROUP_CONCAT(`glpi_profiles_users$addtable2`.`is_dynamic` SEPARATOR '".self::LONGSEP."') AS `".$NAME."_is_dynamic`, $ADDITONALFIELDS"; } break; case "glpi_entities.completename" : if (($itemtype == 'User') && ($ID == 80)) { $addtable2 = ''; if ($meta) { $addtable2 = "_".$meta_type; } return " GROUP_CONCAT(`$table$addtable`.`completename` SEPARATOR '".self::LONGSEP."') AS `".$NAME."`, GROUP_CONCAT(`glpi_profiles_users$addtable2`.`profiles_id` SEPARATOR '".self::LONGSEP."') AS `".$NAME."_profiles_id`, GROUP_CONCAT(`glpi_profiles_users$addtable2`.`is_recursive` SEPARATOR '".self::LONGSEP."') AS `".$NAME."_is_recursive`, GROUP_CONCAT(`glpi_profiles_users$addtable2`.`is_dynamic` SEPARATOR '".self::LONGSEP."') AS `".$NAME."_is_dynamic`, $ADDITONALFIELDS"; } break; case "glpi_auth_tables.name": $user_searchopt = self::getOptions('User'); return " `glpi_users`.`authtype` AS `".$NAME."`, `glpi_users`.`auths_id` AS `".$NAME."_auths_id`, `glpi_authldaps".$addtable."_". self::computeComplexJoinID($user_searchopt[30]['joinparams'])."`.`$field` AS `".$NAME."_".$ID."_ldapname`, `glpi_authmails".$addtable."_". self::computeComplexJoinID($user_searchopt[31]['joinparams'])."`.`$field` AS `".$NAME."_mailname`, $ADDITONALFIELDS"; case "glpi_softwareversions.name" : if ($meta) { return " GROUP_CONCAT(DISTINCT CONCAT(`glpi_softwares`.`name`, ' - ', `$table$addtable2`.`$field`, '".self::SHORTSEP."', `$table$addtable2`.`id`) SEPARATOR '".self::LONGSEP."') AS `".$NAME."`, $ADDITONALFIELDS"; } break; case "glpi_softwareversions.comment" : if ($meta) { return " GROUP_CONCAT(DISTINCT CONCAT(`glpi_softwares`.`name`, ' - ', `$table$addtable2`.`$field`,'".self::SHORTSEP."', `$table$addtable2`.`id`) SEPARATOR '".self::LONGSEP."') AS `".$NAME."`, $ADDITONALFIELDS"; } return " GROUP_CONCAT(DISTINCT CONCAT(`$table$addtable`.`name`, ' - ', `$table$addtable`.`$field`, '".self::SHORTSEP."', `$table$addtable`.`id`) SEPARATOR '".self::LONGSEP."') AS `".$NAME."`, $ADDITONALFIELDS"; case "glpi_states.name" : if ($meta && ($meta_type == 'Software')) { return " GROUP_CONCAT(DISTINCT CONCAT(`glpi_softwares`.`name`, ' - ', `glpi_softwareversions$addtable`.`name`, ' - ', `$table$addtable2`.`$field`, '".self::SHORTSEP."', `$table$addtable2`.`id`) SEPARATOR '".self::LONGSEP."') AS `".$NAME."`, $ADDITONALFIELDS"; } else if ($itemtype == 'Software') { return " GROUP_CONCAT(DISTINCT CONCAT(`glpi_softwareversions`.`name`, ' - ', `$table$addtable`.`$field`,'".self::SHORTSEP."', `$table$addtable`.`id`) SEPARATOR '".self::LONGSEP."') AS `".$NAME."`, $ADDITONALFIELDS"; } break; case "glpi_itilfollowups.content": case "glpi_tickettasks.content": case "glpi_changetasks.content": if (is_subclass_of($itemtype, "CommonITILObject")) { // force ordering by date desc return " GROUP_CONCAT( DISTINCT CONCAT( IFNULL($tocompute, '".self::NULLVALUE."'), '".self::SHORTSEP."', $tocomputeid ) ORDER BY `$table$addtable`.`date` DESC SEPARATOR '".self::LONGSEP."' ) AS `".$NAME."`, $ADDITONALFIELDS"; } break; default: break; } //// Default cases // Link with plugin tables if (preg_match("/^glpi_plugin_([a-z0-9]+)/", $table, $matches)) { if (count($matches) == 2) { $plug = $matches[1]; $out = Plugin::doOneHook( $plug, 'addSelect', $itemtype, $ID, "{$itemtype}_{$ID}" ); if (!empty($out)) { return $out; } } } if (isset($searchopt[$ID]["computation"])) { $tocompute = $searchopt[$ID]["computation"]; $tocompute = str_replace($DB->quoteName('TABLE'), 'TABLE', $tocompute); $tocompute = str_replace("TABLE", $DB->quoteName("$table$addtable"), $tocompute); } // Preformat items if (isset($searchopt[$ID]["datatype"])) { switch ($searchopt[$ID]["datatype"]) { case "count" : return " COUNT(DISTINCT `$table$addtable`.`$field`) AS `".$NAME."`, $ADDITONALFIELDS"; case "date_delay" : $interval = "MONTH"; if (isset($searchopt[$ID]['delayunit'])) { $interval = $searchopt[$ID]['delayunit']; } $add_minus = ''; if (isset($searchopt[$ID]["datafields"][3])) { $add_minus = "-`$table$addtable`.`".$searchopt[$ID]["datafields"][3]."`"; } if ($meta || (isset($searchopt[$ID]["forcegroupby"]) && $searchopt[$ID]["forcegroupby"])) { return " GROUP_CONCAT(DISTINCT ADDDATE(`$table$addtable`.`". $searchopt[$ID]["datafields"][1]."`, INTERVAL (`$table$addtable`.`". $searchopt[$ID]["datafields"][2]. "` $add_minus) $interval) SEPARATOR '".self::LONGSEP."') AS `".$NAME."`, $ADDITONALFIELDS"; } return "ADDDATE(`$table$addtable`.`".$searchopt[$ID]["datafields"][1]."`, INTERVAL (`$table$addtable`.`".$searchopt[$ID]["datafields"][2]. "` $add_minus) $interval) AS `".$NAME."`, $ADDITONALFIELDS"; case "itemlink" : if ($meta || (isset($searchopt[$ID]["forcegroupby"]) && $searchopt[$ID]["forcegroupby"])) { $TRANS = ''; if (Session::haveTranslations(getItemTypeForTable($table), $field)) { $TRANS = "GROUP_CONCAT(DISTINCT CONCAT(IFNULL($tocomputetrans, '".self::NULLVALUE."'), '".self::SHORTSEP."',$tocomputeid) ORDER BY $tocomputeid SEPARATOR '".self::LONGSEP."') AS `".$NAME."_trans`, "; } return " GROUP_CONCAT(DISTINCT CONCAT($tocompute, '".self::SHORTSEP."' , `$table$addtable`.`id`) ORDER BY `$table$addtable`.`id` SEPARATOR '".self::LONGSEP."') AS `".$NAME."`, $TRANS $ADDITONALFIELDS"; } return " $tocompute AS `".$NAME."`, `$table$addtable`.`id` AS `".$NAME."_id`, $ADDITONALFIELDS"; } } // Default case if ($meta || (isset($searchopt[$ID]["forcegroupby"]) && $searchopt[$ID]["forcegroupby"] && (!isset($searchopt[$ID]["computation"]) || isset($searchopt[$ID]["computationgroupby"]) && $searchopt[$ID]["computationgroupby"]))) { // Not specific computation $TRANS = ''; if (Session::haveTranslations(getItemTypeForTable($table), $field)) { $TRANS = "GROUP_CONCAT(DISTINCT CONCAT(IFNULL($tocomputetrans, '".self::NULLVALUE."'), '".self::SHORTSEP."',$tocomputeid) ORDER BY $tocomputeid SEPARATOR '".self::LONGSEP."') AS `".$NAME."_trans`, "; } return " GROUP_CONCAT(DISTINCT CONCAT(IFNULL($tocompute, '".self::NULLVALUE."'), '".self::SHORTSEP."',$tocomputeid) ORDER BY $tocomputeid SEPARATOR '".self::LONGSEP."') AS `".$NAME."`, $TRANS $ADDITONALFIELDS"; } $TRANS = ''; if (Session::haveTranslations(getItemTypeForTable($table), $field)) { $TRANS = $tocomputetrans." AS `".$NAME."_trans`, "; } return "$tocompute AS `".$NAME."`, $TRANS $ADDITONALFIELDS"; } /** * Generic Function to add default where to a request * * @param string $itemtype device type * * @return string Where string **/ static function addDefaultWhere($itemtype) { $condition = ''; switch ($itemtype) { case 'Reminder' : $condition = Reminder::addVisibilityRestrict(); break; case 'RSSFeed' : $condition = RSSFeed::addVisibilityRestrict(); break; case 'Notification' : if (!Config::canView()) { $condition = " `glpi_notifications`.`itemtype` NOT IN ('CronTask', 'DBConnection') "; } break; // No link case 'User' : // View all entities if (!Session::canViewAllEntities()) { $condition = getEntitiesRestrictRequest("", "glpi_profiles_users", '', '', true); } break; case 'ProjectTask' : $condition = ''; $teamtable = 'glpi_projecttaskteams'; $condition .= "`glpi_projects`.`is_template` = 0"; $condition .= " AND ((`$teamtable`.`itemtype` = 'User' AND `$teamtable`.`items_id` = '".Session::getLoginUserID()."')"; if (count($_SESSION['glpigroups'])) { $condition .= " OR (`$teamtable`.`itemtype` = 'Group' AND `$teamtable`.`items_id` IN (".implode(",", $_SESSION['glpigroups'])."))"; } $condition .= ") "; break; case 'Project' : $condition = ''; if (!Session::haveRight("project", Project::READALL)) { $teamtable = 'glpi_projectteams'; $condition .= "(`glpi_projects`.users_id = '".Session::getLoginUserID()."' OR (`$teamtable`.`itemtype` = 'User' AND `$teamtable`.`items_id` = '".Session::getLoginUserID()."')"; if (count($_SESSION['glpigroups'])) { $condition .= " OR (`glpi_projects`.`groups_id` IN (".implode(",", $_SESSION['glpigroups'])."))"; $condition .= " OR (`$teamtable`.`itemtype` = 'Group' AND `$teamtable`.`items_id` IN (".implode(",", $_SESSION['glpigroups'])."))"; } $condition .= ") "; } break; case 'Ticket' : // Same structure in addDefaultJoin $condition = ''; if (!Session::haveRight("ticket", Ticket::READALL)) { $searchopt = &self::getOptions($itemtype); $requester_table = '`glpi_tickets_users_'. self::computeComplexJoinID($searchopt[4]['joinparams']['beforejoin'] ['joinparams']).'`'; $requestergroup_table = '`glpi_groups_tickets_'. self::computeComplexJoinID($searchopt[71]['joinparams']['beforejoin'] ['joinparams']).'`'; $assign_table = '`glpi_tickets_users_'. self::computeComplexJoinID($searchopt[5]['joinparams']['beforejoin'] ['joinparams']).'`'; $assigngroup_table = '`glpi_groups_tickets_'. self::computeComplexJoinID($searchopt[8]['joinparams']['beforejoin'] ['joinparams']).'`'; $observer_table = '`glpi_tickets_users_'. self::computeComplexJoinID($searchopt[66]['joinparams']['beforejoin'] ['joinparams']).'`'; $observergroup_table = '`glpi_groups_tickets_'. self::computeComplexJoinID($searchopt[65]['joinparams']['beforejoin'] ['joinparams']).'`'; $condition = "("; if (Session::haveRight("ticket", Ticket::READMY)) { $condition .= " $requester_table.users_id = '".Session::getLoginUserID()."' OR $observer_table.users_id = '".Session::getLoginUserID()."' OR `glpi_tickets`.`users_id_recipient` = '".Session::getLoginUserID()."'"; } else { $condition .= "0=1"; } if (Session::haveRight("ticket", Ticket::READGROUP)) { if (count($_SESSION['glpigroups'])) { $condition .= " OR $requestergroup_table.`groups_id` IN (".implode(",", $_SESSION['glpigroups']).")"; $condition .= " OR $observergroup_table.`groups_id` IN (".implode(",", $_SESSION['glpigroups']).")"; } } if (Session::haveRight("ticket", Ticket::OWN)) {// Can own ticket : show assign to me $condition .= " OR $assign_table.users_id = '".Session::getLoginUserID()."' "; } if (Session::haveRight("ticket", Ticket::READASSIGN)) { // assign to me $condition .=" OR $assign_table.`users_id` = '".Session::getLoginUserID()."'"; if (count($_SESSION['glpigroups'])) { $condition .= " OR $assigngroup_table.`groups_id` IN (".implode(",", $_SESSION['glpigroups']).")"; } if (Session::haveRight('ticket', Ticket::ASSIGN)) { $condition .= " OR `glpi_tickets`.`status`='".CommonITILObject::INCOMING."'"; } } if (Session::haveRightsOr('ticketvalidation', [TicketValidation::VALIDATEINCIDENT, TicketValidation::VALIDATEREQUEST])) { $condition .= " OR `glpi_ticketvalidations`.`users_id_validate` = '".Session::getLoginUserID()."'"; } $condition .= ") "; } break; case 'Change' : case 'Problem': if ($itemtype == 'Change') { $right = 'change'; $table = 'changes'; $groupetable = "`glpi_changes_groups_"; } else if ($itemtype == 'Problem') { $right = 'problem'; $table = 'problems'; $groupetable = "`glpi_groups_problems_"; } // Same structure in addDefaultJoin $condition = ''; if (!Session::haveRight("$right", $itemtype::READALL)) { $searchopt = &self::getOptions($itemtype); if (Session::haveRight("$right", $itemtype::READMY)) { $requester_table = '`glpi_'.$table.'_users_'. self::computeComplexJoinID($searchopt[4]['joinparams'] ['beforejoin']['joinparams']).'`'; $requestergroup_table = $groupetable. self::computeComplexJoinID($searchopt[71]['joinparams'] ['beforejoin']['joinparams']).'`'; $observer_table = '`glpi_'.$table.'_users_'. self::computeComplexJoinID($searchopt[66]['joinparams'] ['beforejoin']['joinparams']).'`'; $observergroup_table = $groupetable. self::computeComplexJoinID($searchopt[65]['joinparams'] ['beforejoin']['joinparams']).'`'; $assign_table = '`glpi_'.$table.'_users_'. self::computeComplexJoinID($searchopt[5]['joinparams'] ['beforejoin']['joinparams']).'`'; $assigngroup_table = $groupetable. self::computeComplexJoinID($searchopt[8]['joinparams'] ['beforejoin']['joinparams']).'`'; } $condition = "("; if (Session::haveRight("$right", $itemtype::READMY)) { $condition .= " $requester_table.users_id = '".Session::getLoginUserID()."' OR $observer_table.users_id = '".Session::getLoginUserID()."' OR $assign_table.users_id = '".Session::getLoginUserID()."' OR `glpi_".$table."`.`users_id_recipient` = '".Session::getLoginUserID()."'"; if (count($_SESSION['glpigroups'])) { $my_groups_keys = "'" . implode("','", $_SESSION['glpigroups']) . "'"; $condition .= " OR $requestergroup_table.groups_id IN ($my_groups_keys) OR $observergroup_table.groups_id IN ($my_groups_keys) OR $assigngroup_table.groups_id IN ($my_groups_keys)"; } } else { $condition .= "0=1"; } $condition .= ") "; } break; case 'Config': $availableContexts = ['core'] + Plugin::getPlugins(); $availableContexts = implode("', '", $availableContexts); $condition = "`context` IN ('$availableContexts')"; break; case 'SavedSearch': $condition = SavedSearch::addVisibilityRestrict(); break; case 'TicketTask': // Filter on is_private $allowed_is_private = []; if (Session::haveRight(TicketTask::$rightname, CommonITILTask::SEEPRIVATE)) { $allowed_is_private[] = 1; } if (Session::haveRight(TicketTask::$rightname, CommonITILTask::SEEPUBLIC)) { $allowed_is_private[] = 0; } // If the user can't see public and private if (!count($allowed_is_private)) { $condition = "0 = 1"; break; } $in = "IN ('" . implode("','", $allowed_is_private) . "')"; $condition = "(`glpi_tickettasks`.`is_private` $in "; // Check for assigned or created tasks $condition .= "OR `users_id` = " . Session::getLoginUserID() . " "; $condition .= "OR `users_id_tech` = " . Session::getLoginUserID() . " "; // Check for parent item visibility unless the user can see all the // possible parents if (!Session::haveRight('ticket', Ticket::READALL)) { $condition .= "AND " . TicketTask::buildParentCondition(); } $condition .= ")"; break; case 'ITILFollowup': // Filter on is_private $allowed_is_private = []; if (Session::haveRight(ITILFollowup::$rightname, ITILFollowup::SEEPRIVATE)) { $allowed_is_private[] = 1; } if (Session::haveRight(ITILFollowup::$rightname, ITILFollowup::SEEPUBLIC)) { $allowed_is_private[] = 0; } // If the user can't see public and private if (!count($allowed_is_private)) { $condition = "0 = 1"; break; } $in = "IN ('" . implode("','", $allowed_is_private) . "')"; $condition = "(`glpi_itilfollowups`.`is_private` $in "; // Now filter on parent item visiblity $condition .= "AND ("; // Filter for "ticket" parents $condition .= ITILFollowup::buildParentCondition(\Ticket::getType()); $condition .= "OR "; // Filter for "change" parents $condition .= ITILFollowup::buildParentCondition( \Change::getType(), 'changes_id', "glpi_changes_users", "glpi_changes_groups" ); $condition .= "OR "; // Fitler for "problem" parents $condition .= ITILFollowup::buildParentCondition( \Problem::getType(), 'problems_id', "glpi_problems_users", "glpi_groups_problems" ); $condition .= "))"; break; default : // Plugin can override core definition for its type if ($plug = isPluginItemType($itemtype)) { $condition = Plugin::doOneHook($plug['plugin'], 'addDefaultWhere', $itemtype); } break; } /* Hook to restrict user right on current itemtype */ list($itemtype, $condition) = Plugin::doHookFunction('add_default_where', [$itemtype, $condition]); return $condition; } /** * Generic Function to add where to a request * * @param string $link Link string * @param boolean $nott Is it a negative search ? * @param string $itemtype Item type * @param integer $ID ID of the item to search * @param string $searchtype Searchtype used (equals or contains) * @param string $val Item num in the request * @param integer $meta Is a meta search (meta=2 in search.class.php) (default 0) * * @return string Where string **/ static function addWhere($link, $nott, $itemtype, $ID, $searchtype, $val, $meta = 0) { global $DB; $searchopt = &self::getOptions($itemtype); if (!isset($searchopt[$ID]['table'])) { return false; } $table = $searchopt[$ID]["table"]; $field = $searchopt[$ID]["field"]; $inittable = $table; $addtable = ''; $is_fkey_composite_on_self = getTableNameForForeignKeyField($searchopt[$ID]["linkfield"]) == $table && $searchopt[$ID]["linkfield"] != getForeignKeyFieldForTable($table); $orig_table = self::getOrigTableName($itemtype); if (($table != 'asset_types') && ($is_fkey_composite_on_self || $table != $orig_table) && ($searchopt[$ID]["linkfield"] != getForeignKeyFieldForTable($table))) { $addtable = "_".$searchopt[$ID]["linkfield"]; $table .= $addtable; } if (isset($searchopt[$ID]['joinparams'])) { $complexjoin = self::computeComplexJoinID($searchopt[$ID]['joinparams']); if (!empty($complexjoin)) { $table .= "_".$complexjoin; } } if ($meta && ($itemtype::getTable() != $inittable)) { $table .= "_".$itemtype; } // Hack to allow search by ID on every sub-table if (preg_match('/^\$\$\$\$([0-9]+)$/', $val, $regs)) { return $link." (`$table`.`id` ".($nott?"<>":"=").$regs[1]." ". (($regs[1] == 0)?" OR `$table`.`id` IS NULL":'').") "; } // Preparse value if (isset($searchopt[$ID]["datatype"])) { switch ($searchopt[$ID]["datatype"]) { case "datetime" : case "date" : case "date_delay" : $force_day = true; if ($searchopt[$ID]["datatype"] == 'datetime' && !(strstr($val, 'BEGIN') || strstr($val, 'LAST') || strstr($val, 'DAY')) ) { $force_day = false; } $val = Html::computeGenericDateTimeSearch($val, $force_day); break; } } switch ($searchtype) { case "notcontains" : $nott = !$nott; case "contains" : $SEARCH = self::makeTextSearch($val, $nott); break; case "equals" : if ($nott) { $SEARCH = " <> '$val'"; } else { $SEARCH = " = '$val'"; } break; case "notequals" : if ($nott) { $SEARCH = " = '$val'"; } else { $SEARCH = " <> '$val'"; } break; case "under" : if ($nott) { $SEARCH = " NOT IN ('".implode("','", getSonsOf($inittable, $val))."')"; } else { $SEARCH = " IN ('".implode("','", getSonsOf($inittable, $val))."')"; } break; case "notunder" : if ($nott) { $SEARCH = " IN ('".implode("','", getSonsOf($inittable, $val))."')"; } else { $SEARCH = " NOT IN ('".implode("','", getSonsOf($inittable, $val))."')"; } break; } //Check in current item if a specific where is defined if (method_exists($itemtype, 'addWhere')) { $out = $itemtype::addWhere($link, $nott, $itemtype, $ID, $searchtype, $val); if (!empty($out)) { return $out; } } // Plugin can override core definition for its type if ($plug = isPluginItemType($itemtype)) { $out = Plugin::doOneHook( $plug['plugin'], 'addWhere', $link, $nott, $itemtype, $ID, $val, $searchtype ); if (!empty($out)) { return $out; } } switch ($inittable.".".$field) { // case "glpi_users_validation.name" : case "glpi_users.name" : if ($itemtype == 'User') { // glpi_users case / not link table if (in_array($searchtype, ['equals', 'notequals'])) { $search_str = "`$table`.`id`" . $SEARCH; if ($searchtype == 'notequals') { $nott = !$nott; } // Add NULL if $val = 0 and not negative search // Or negative search on real value if ((!$nott && ($val == 0)) || ($nott && ($val != 0))) { $search_str .= " OR `$table`.`id` IS NULL"; } return " $link ($search_str)"; } return self::makeTextCriteria("`$table`.`$field`", $val, $nott, $link); } if ($_SESSION["glpinames_format"] == User::FIRSTNAME_BEFORE) { $name1 = 'firstname'; $name2 = 'realname'; } else { $name1 = 'realname'; $name2 = 'firstname'; } if (in_array($searchtype, ['equals', 'notequals'])) { return " $link (`$table`.`id`".$SEARCH. (($val == 0)?" OR `$table`.`id` IS". (($searchtype == "notequals")?" NOT":"")." NULL":'').') '; } $toadd = ''; $tmplink = 'OR'; if ($nott) { $tmplink = 'AND'; } if (($itemtype == 'Ticket') || ($itemtype == 'Problem')) { if (isset($searchopt[$ID]["joinparams"]["beforejoin"]["table"]) && isset($searchopt[$ID]["joinparams"]["beforejoin"]["joinparams"]) && (($searchopt[$ID]["joinparams"]["beforejoin"]["table"] == 'glpi_tickets_users') || ($searchopt[$ID]["joinparams"]["beforejoin"]["table"] == 'glpi_problems_users') || ($searchopt[$ID]["joinparams"]["beforejoin"]["table"] == 'glpi_changes_users'))) { $bj = $searchopt[$ID]["joinparams"]["beforejoin"]; $linktable = $bj['table'].'_'.self::computeComplexJoinID($bj['joinparams']); //$toadd = "`$linktable`.`alternative_email` $SEARCH $tmplink "; $toadd = self::makeTextCriteria("`$linktable`.`alternative_email`", $val, $nott, $tmplink); if ($val == '^$') { return $link." ((`$linktable`.`users_id` IS NULL) OR `$linktable`.`alternative_email` IS NULL)"; } } } $toadd2 = ''; if ($nott && ($val != 'NULL') && ($val != 'null')) { $toadd2 = " OR `$table`.`$field` IS NULL"; } return $link." (((`$table`.`$name1` $SEARCH $tmplink `$table`.`$name2` $SEARCH $tmplink `$table`.`$field` $SEARCH $tmplink CONCAT(`$table`.`$name1`, ' ', `$table`.`$name2`) $SEARCH ) $toadd2) $toadd)"; case "glpi_groups.completename" : if ($val == 'mygroups') { switch ($searchtype) { case 'equals' : return " $link (`$table`.`id` IN ('".implode("','", $_SESSION['glpigroups'])."')) "; case 'notequals' : return " $link (`$table`.`id` NOT IN ('".implode("','", $_SESSION['glpigroups'])."')) "; case 'under' : $groups = $_SESSION['glpigroups']; foreach ($_SESSION['glpigroups'] as $g) { $groups += getSonsOf($inittable, $g); } $groups = array_unique($groups); return " $link (`$table`.`id` IN ('".implode("','", $groups)."')) "; case 'notunder' : $groups = $_SESSION['glpigroups']; foreach ($_SESSION['glpigroups'] as $g) { $groups += getSonsOf($inittable, $g); } $groups = array_unique($groups); return " $link (`$table`.`id` NOT IN ('".implode("','", $groups)."')) "; } } break; case "glpi_auth_tables.name" : $user_searchopt = self::getOptions('User'); $tmplink = 'OR'; if ($nott) { $tmplink = 'AND'; } return $link." (`glpi_authmails".$addtable."_". self::computeComplexJoinID($user_searchopt[31]['joinparams'])."`.`name` $SEARCH $tmplink `glpi_authldaps".$addtable."_". self::computeComplexJoinID($user_searchopt[30]['joinparams'])."`.`name` $SEARCH ) "; case "glpi_ipaddresses.name" : $search = ["/\</","/\>/"]; $replace = ["<",">"]; $val = preg_replace($search, $replace, $val); if (preg_match("/^\s*([<>])([=]*)[[:space:]]*([0-9\.]+)/", $val, $regs)) { if ($nott) { if ($regs[1] == '<') { $regs[1] = '>'; } else { $regs[1] = '<'; } } $regs[1] .= $regs[2]; return $link." (INET_ATON(`$table`.`$field`) ".$regs[1]." INET_ATON('".$regs[3]."')) "; } break; case "glpi_tickets.status" : case "glpi_problems.status" : case "glpi_changes.status" : if ($val == 'all') { return ""; } $tocheck = []; if ($item = getItemForItemtype($itemtype)) { switch ($val) { case 'process' : $tocheck = $item->getProcessStatusArray(); break; case 'notclosed' : $tocheck = $item->getAllStatusArray(); foreach ($item->getClosedStatusArray() as $status) { if (isset($tocheck[$status])) { unset($tocheck[$status]); } } $tocheck = array_keys($tocheck); break; case 'old' : $tocheck = array_merge($item->getSolvedStatusArray(), $item->getClosedStatusArray()); break; case 'notold' : $tocheck = $item::getNotSolvedStatusArray(); break; } } if (count($tocheck) == 0) { $statuses = $item->getAllStatusArray(); if (isset($statuses[$val])) { $tocheck = [$val]; } } if (count($tocheck)) { if ($nott) { return $link." `$table`.`$field` NOT IN ('".implode("','", $tocheck)."')"; } return $link." `$table`.`$field` IN ('".implode("','", $tocheck)."')"; } break; case "glpi_tickets_tickets.tickets_id_1" : $tmplink = 'OR'; $compare = '='; if ($nott) { $tmplink = 'AND'; $compare = '<>'; } $toadd2 = ''; if ($nott && ($val != 'NULL') && ($val != 'null')) { $toadd2 = " OR `$table`.`$field` IS NULL"; } return $link." (((`$table`.`tickets_id_1` $compare '$val' $tmplink `$table`.`tickets_id_2` $compare '$val') AND `glpi_tickets`.`id` <> '$val') $toadd2)"; case "glpi_tickets.priority" : case "glpi_tickets.impact" : case "glpi_tickets.urgency" : case "glpi_problems.priority" : case "glpi_problems.impact" : case "glpi_problems.urgency" : case "glpi_changes.priority" : case "glpi_changes.impact" : case "glpi_changes.urgency" : case "glpi_projects.priority" : if (is_numeric($val)) { if ($val > 0) { $compare = ($nott ? '<>' : '='); return $link." `$table`.`$field` $compare '$val'"; } if ($val < 0) { $compare = ($nott ? '<' : '>='); return $link." `$table`.`$field` $compare '".abs($val)."'"; } // Show all $compare = ($nott ? '<' : '>='); return $link." `$table`.`$field` $compare '0' "; } return ""; case "glpi_tickets.global_validation" : case "glpi_ticketvalidations.status" : if ($val == 'all') { return ""; } $tocheck = []; switch ($val) { case 'can' : $tocheck = CommonITILValidation::getCanValidationStatusArray(); break; case 'all' : $tocheck = CommonITILValidation::getAllValidationStatusArray(); break; } if (count($tocheck) == 0) { $tocheck = [$val]; } if (count($tocheck)) { if ($nott) { return $link." `$table`.`$field` NOT IN ('".implode("','", $tocheck)."')"; } return $link." `$table`.`$field` IN ('".implode("','", $tocheck)."')"; } break; case "glpi_notifications.event" : if (in_array($searchtype, ['equals', 'notequals']) && strpos($val, self::SHORTSEP)) { $not = 'notequals' === $searchtype ? 'NOT' : ''; list($itemtype_val, $event_val) = explode(self::SHORTSEP, $val); return " $link $not(`$table`.`event` = '$event_val' AND `$table`.`itemtype` = '$itemtype_val')"; } break; } //// Default cases // Link with plugin tables if (preg_match("/^glpi_plugin_([a-z0-9]+)/", $inittable, $matches)) { if (count($matches) == 2) { $plug = $matches[1]; $out = Plugin::doOneHook( $plug, 'addWhere', $link, $nott, $itemtype, $ID, $val, $searchtype ); if (!empty($out)) { return $out; } } } $tocompute = "`$table`.`$field`"; $tocomputetrans = "`".$table."_trans`.`value`"; if (isset($searchopt[$ID]["computation"])) { $tocompute = $searchopt[$ID]["computation"]; $tocompute = str_replace($DB->quoteName('TABLE'), 'TABLE', $tocompute); $tocompute = str_replace("TABLE", $DB->quoteName("$table"), $tocompute); } // Preformat items if (isset($searchopt[$ID]["datatype"])) { switch ($searchopt[$ID]["datatype"]) { case "itemtypename" : if (in_array($searchtype, ['equals', 'notequals'])) { return " $link (`$table`.`$field`".$SEARCH.') '; } break; case "itemlink" : if (in_array($searchtype, ['equals', 'notequals', 'under', 'notunder'])) { return " $link (`$table`.`id`".$SEARCH.') '; } break; case "datetime" : case "date" : case "date_delay" : if ($searchopt[$ID]["datatype"] == 'datetime') { // Specific search for datetime if (in_array($searchtype, ['equals', 'notequals'])) { $val = preg_replace("/:00$/", '', $val); $val = '^'.$val; if ($searchtype == 'notequals') { $nott = !$nott; } return self::makeTextCriteria("`$table`.`$field`", $val, $nott, $link); } } if ($searchtype == 'lessthan') { $val = '<'.$val; } if ($searchtype == 'morethan') { $val = '>'.$val; } if ($searchtype) { $date_computation = $tocompute; } if (in_array($searchtype, ["contains", "notcontains"])) { $date_computation = "CONVERT($date_computation USING utf8)"; } $search_unit = ' MONTH '; if (isset($searchopt[$ID]['searchunit'])) { $search_unit = $searchopt[$ID]['searchunit']; } if ($searchopt[$ID]["datatype"]=="date_delay") { $delay_unit = ' MONTH '; if (isset($searchopt[$ID]['delayunit'])) { $delay_unit = $searchopt[$ID]['delayunit']; } $add_minus = ''; if (isset($searchopt[$ID]["datafields"][3])) { $add_minus = "-`$table`.`".$searchopt[$ID]["datafields"][3]."`"; } $date_computation = "ADDDATE(`$table`.".$searchopt[$ID]["datafields"][1].", INTERVAL (`$table`.".$searchopt[$ID]["datafields"][2]." $add_minus) $delay_unit)"; } if (in_array($searchtype, ['equals', 'notequals'])) { return " $link ($date_computation ".$SEARCH.') '; } $search = ["/\</","/\>/"]; $replace = ["<",">"]; $val = preg_replace($search, $replace, $val); if (preg_match("/^\s*([<>=]+)(.*)/", $val, $regs)) { if (is_numeric($regs[2])) { return $link." $date_computation ".$regs[1]." ADDDATE(NOW(), INTERVAL ".$regs[2]." $search_unit) "; } // ELSE Reformat date if needed $regs[2] = preg_replace('@(\d{1,2})(-|/)(\d{1,2})(-|/)(\d{4})@', '\5-\3-\1', $regs[2]); if (preg_match('/[0-9]{2,4}-[0-9]{1,2}-[0-9]{1,2}/', $regs[2])) { $ret = $link; if ($nott) { $ret .= " NOT("; } $ret .= " $date_computation {$regs[1]} '{$regs[2]}'"; if ($nott) { $ret .= ")"; } return $ret; } return ""; } // ELSE standard search // Date format modification if needed $val = preg_replace('@(\d{1,2})(-|/)(\d{1,2})(-|/)(\d{4})@', '\5-\3-\1', $val); if ($date_computation) { return self::makeTextCriteria($date_computation, $val, $nott, $link); } return ''; case "right" : if ($searchtype == 'notequals') { $nott = !$nott; } return $link. ($nott?' NOT':'')." ($tocompute & '$val') "; case "bool" : if (!is_numeric($val)) { if (strcasecmp($val, __('No')) == 0) { $val = 0; } else if (strcasecmp($val, __('Yes')) == 0) { $val = 1; } } // No break here : use number comparaison case case "count" : case "number" : case "decimal" : case "timestamp" : $search = ["/\</", "/\>/"]; $replace = ["<", ">"]; $val = preg_replace($search, $replace, $val); if (preg_match("/([<>])([=]*)[[:space:]]*([0-9]+)/", $val, $regs)) { if (in_array($searchtype, ["notequals", "notcontains"])) { $nott = !$nott; } if ($nott) { if ($regs[1] == '<') { $regs[1] = '>'; } else { $regs[1] = '<'; } } $regs[1] .= $regs[2]; return $link." ($tocompute ".$regs[1]." ".$regs[3].") "; } if (is_numeric($val)) { $numeric_val = floatval($val); if (in_array($searchtype, ["notequals", "notcontains"])) { $nott = !$nott; } if (isset($searchopt[$ID]["width"])) { $ADD = ""; if ($nott && ($val != 'NULL') && ($val != 'null')) { $ADD = " OR $tocompute IS NULL"; } if ($nott) { return $link." ($tocompute < ".($numeric_val - $searchopt[$ID]["width"])." OR $tocompute > ".($numeric_val + $searchopt[$ID]["width"])." $ADD) "; } return $link." (($tocompute >= ".($numeric_val - $searchopt[$ID]["width"])." AND $tocompute <= ".($numeric_val + $searchopt[$ID]["width"]).") $ADD) "; } if (!$nott) { return " $link ($tocompute = $numeric_val) "; } return " $link ($tocompute <> $numeric_val) "; } break; } } // Default case if (in_array($searchtype, ['equals', 'notequals','under', 'notunder'])) { if ((!isset($searchopt[$ID]['searchequalsonfield']) || !$searchopt[$ID]['searchequalsonfield']) && ($itemtype == 'AllAssets' || $table != $itemtype::getTable())) { $out = " $link (`$table`.`id`".$SEARCH; } else { $out = " $link (`$table`.`$field`".$SEARCH; } if ($searchtype == 'notequals') { $nott = !$nott; } // Add NULL if $val = 0 and not negative search // Or negative search on real value if ((!$nott && ($val == 0)) || ($nott && ($val != 0))) { $out .= " OR `$table`.`id` IS NULL"; } $out .= ')'; return $out; } $transitemtype = getItemTypeForTable($inittable); if (Session::haveTranslations($transitemtype, $field)) { return " $link (".self::makeTextCriteria($tocompute, $val, $nott, '')." OR ".self::makeTextCriteria($tocomputetrans, $val, $nott, '').")"; } return self::makeTextCriteria($tocompute, $val, $nott, $link); } /** * Generic Function to add Default left join to a request * * @param string $itemtype Reference item type * @param string $ref_table Reference table * @param array &$already_link_tables Array of tables already joined * * @return string Left join string **/ static function addDefaultJoin($itemtype, $ref_table, array &$already_link_tables) { switch ($itemtype) { // No link case 'User' : return self::addLeftJoin($itemtype, $ref_table, $already_link_tables, "glpi_profiles_users", "profiles_users_id", 0, 0, ['jointype' => 'child']); case 'Reminder' : return Reminder::addVisibilityJoins(); case 'RSSFeed' : return RSSFeed::addVisibilityJoins(); case 'ProjectTask' : // Same structure in addDefaultWhere $out = ''; $out .= self::addLeftJoin($itemtype, $ref_table, $already_link_tables, "glpi_projects", "projects_id"); $out .= self::addLeftJoin($itemtype, $ref_table, $already_link_tables, "glpi_projecttaskteams", "projecttaskteams_id", 0, 0, ['jointype' => 'child']); return $out; case 'Project' : // Same structure in addDefaultWhere $out = ''; if (!Session::haveRight("project", Project::READALL)) { $out .= self::addLeftJoin($itemtype, $ref_table, $already_link_tables, "glpi_projectteams", "projectteams_id", 0, 0, ['jointype' => 'child']); } return $out; case 'Ticket' : // Same structure in addDefaultWhere $out = ''; if (!Session::haveRight("ticket", Ticket::READALL)) { $searchopt = &self::getOptions($itemtype); // show mine : requester $out .= self::addLeftJoin($itemtype, $ref_table, $already_link_tables, "glpi_tickets_users", "tickets_users_id", 0, 0, $searchopt[4]['joinparams']['beforejoin']['joinparams']); if (Session::haveRight("ticket", Ticket::READGROUP)) { if (count($_SESSION['glpigroups'])) { $out .= self::addLeftJoin($itemtype, $ref_table, $already_link_tables, "glpi_groups_tickets", "groups_tickets_id", 0, 0, $searchopt[71]['joinparams']['beforejoin'] ['joinparams']); } } // show mine : observer $out .= self::addLeftJoin($itemtype, $ref_table, $already_link_tables, "glpi_tickets_users", "tickets_users_id", 0, 0, $searchopt[66]['joinparams']['beforejoin']['joinparams']); if (count($_SESSION['glpigroups'])) { $out .= self::addLeftJoin($itemtype, $ref_table, $already_link_tables, "glpi_groups_tickets", "groups_tickets_id", 0, 0, $searchopt[65]['joinparams']['beforejoin']['joinparams']); } if (Session::haveRight("ticket", Ticket::OWN)) { // Can own ticket : show assign to me $out .= self::addLeftJoin($itemtype, $ref_table, $already_link_tables, "glpi_tickets_users", "tickets_users_id", 0, 0, $searchopt[5]['joinparams']['beforejoin']['joinparams']); } if (Session::haveRightsOr("ticket", [Ticket::READMY, Ticket::READASSIGN])) { // show mine + assign to me $out .= self::addLeftJoin($itemtype, $ref_table, $already_link_tables, "glpi_tickets_users", "tickets_users_id", 0, 0, $searchopt[5]['joinparams']['beforejoin']['joinparams']); if (count($_SESSION['glpigroups'])) { $out .= self::addLeftJoin($itemtype, $ref_table, $already_link_tables, "glpi_groups_tickets", "groups_tickets_id", 0, 0, $searchopt[8]['joinparams']['beforejoin'] ['joinparams']); } } if (Session::haveRightsOr('ticketvalidation', [TicketValidation::VALIDATEINCIDENT, TicketValidation::VALIDATEREQUEST])) { $out .= self::addLeftJoin($itemtype, $ref_table, $already_link_tables, "glpi_ticketvalidations", "ticketvalidations_id", 0, 0, $searchopt[58]['joinparams']['beforejoin']['joinparams']); } } return $out; case 'Change' : case 'Problem' : if ($itemtype == 'Change') { $right = 'change'; $table = 'changes'; $groupetable = "glpi_changes_groups"; $linkfield = "changes_groups_id"; } else if ($itemtype == 'Problem') { $right = 'problem'; $table = 'problems'; $groupetable = "glpi_groups_problems"; $linkfield = "groups_problems_id"; } // Same structure in addDefaultWhere $out = ''; if (!Session::haveRight("$right", $itemtype::READALL)) { $searchopt = &self::getOptions($itemtype); if (Session::haveRight("$right", $itemtype::READMY)) { // show mine : requester $out .= self::addLeftJoin($itemtype, $ref_table, $already_link_tables, "glpi_".$table."_users", $table."_users_id", 0, 0, $searchopt[4]['joinparams']['beforejoin']['joinparams']); if (count($_SESSION['glpigroups'])) { $out .= self::addLeftJoin($itemtype, $ref_table, $already_link_tables, $groupetable, $linkfield, 0, 0, $searchopt[71]['joinparams']['beforejoin']['joinparams']); } // show mine : observer $out .= self::addLeftJoin($itemtype, $ref_table, $already_link_tables, "glpi_".$table."_users", $table."_users_id", 0, 0, $searchopt[66]['joinparams']['beforejoin']['joinparams']); if (count($_SESSION['glpigroups'])) { $out .= self::addLeftJoin($itemtype, $ref_table, $already_link_tables, $groupetable, $linkfield, 0, 0, $searchopt[65]['joinparams']['beforejoin']['joinparams']); } // show mine : assign $out .= self::addLeftJoin($itemtype, $ref_table, $already_link_tables, "glpi_".$table."_users", $table."_users_id", 0, 0, $searchopt[5]['joinparams']['beforejoin']['joinparams']); if (count($_SESSION['glpigroups'])) { $out .= self::addLeftJoin($itemtype, $ref_table, $already_link_tables, $groupetable, $linkfield, 0, 0, $searchopt[8]['joinparams']['beforejoin']['joinparams']); } } } return $out; default : // Plugin can override core definition for its type if ($plug = isPluginItemType($itemtype)) { $plugin_name = $plug['plugin']; $hook_function = 'plugin_' . $plugin_name . '_addDefaultJoin'; $hook_closure = function () use ($hook_function, $itemtype, $ref_table, &$already_link_tables) { if (is_callable($hook_function)) { return $hook_function($itemtype, $ref_table, $already_link_tables); } }; $out = Plugin::doOneHook($plug['plugin'], $hook_closure); if (!empty($out)) { return $out; } } return ""; } } /** * Generic Function to add left join to a request * * @param string $itemtype Item type * @param string $ref_table Reference table * @param array $already_link_tables Array of tables already joined * @param string $new_table New table to join * @param string $linkfield Linkfield for LeftJoin * @param boolean $meta Is it a meta item ? (default 0) * @param integer $meta_type Meta type table (default 0) * @param array $joinparams Array join parameters (condition / joinbefore...) * @param string $field Field to display (needed for translation join) (default '') * * @return string Left join string **/ static function addLeftJoin($itemtype, $ref_table, array &$already_link_tables, $new_table, $linkfield, $meta = 0, $meta_type = 0, $joinparams = [], $field = '') { // Rename table for meta left join $AS = ""; $nt = $new_table; $cleannt = $nt; // Virtual field no link if (strpos($linkfield, '_virtual') === 0) { return false; } $complexjoin = self::computeComplexJoinID($joinparams); $is_fkey_composite_on_self = getTableNameForForeignKeyField($linkfield) == $ref_table && $linkfield != getForeignKeyFieldForTable($ref_table); // Auto link if (($ref_table == $new_table) && empty($complexjoin) && !$is_fkey_composite_on_self) { $transitemtype = getItemTypeForTable($new_table); if (Session::haveTranslations($transitemtype, $field)) { $transAS = $nt.'_trans'; return self::joinDropdownTranslations( $transAS, $nt, $transitemtype, $field ); } return ""; } // Multiple link possibilies case if (!empty($linkfield) && ($linkfield != getForeignKeyFieldForTable($new_table))) { $nt .= "_".$linkfield; $AS = " AS `$nt`"; } if (!empty($complexjoin)) { $nt .= "_".$complexjoin; $AS = " AS `$nt`"; } $addmetanum = ""; $rt = $ref_table; $cleanrt = $rt; if ($meta && $meta_type::getTable() != $new_table) { $addmetanum = "_".$meta_type; $AS = " AS `$nt$addmetanum`"; $nt = $nt.$addmetanum; } // Do not take into account standard linkfield $tocheck = $nt.".".$linkfield; if ($linkfield == getForeignKeyFieldForTable($new_table)) { $tocheck = $nt; } if (in_array($tocheck, $already_link_tables)) { return ""; } array_push($already_link_tables, $tocheck); $specific_leftjoin = ''; // Plugin can override core definition for its type if ($plug = isPluginItemType($itemtype)) { $plugin_name = $plug['plugin']; $hook_function = 'plugin_' . $plugin_name . '_addLeftJoin'; $hook_closure = function () use ($hook_function, $itemtype, $ref_table, $new_table, $linkfield, &$already_link_tables) { if (is_callable($hook_function)) { return $hook_function($itemtype, $ref_table, $new_table, $linkfield, $already_link_tables); } }; $specific_leftjoin = Plugin::doOneHook($plugin_name, $hook_closure); } // Link with plugin tables : need to know left join structure if (empty($specific_leftjoin) && preg_match("/^glpi_plugin_([a-z0-9]+)/", $new_table, $matches)) { if (count($matches) == 2) { $plugin_name = $matches[1]; $hook_function = 'plugin_' . $plugin_name . '_addLeftJoin'; $hook_closure = function () use ($hook_function, $itemtype, $ref_table, $new_table, $linkfield, &$already_link_tables) { if (is_callable($hook_function)) { return $hook_function($itemtype, $ref_table, $new_table, $linkfield, $already_link_tables); } }; $specific_leftjoin = Plugin::doOneHook($plugin_name, $hook_closure); } } if (!empty($linkfield)) { $before = ''; if (isset($joinparams['beforejoin']) && is_array($joinparams['beforejoin'])) { if (isset($joinparams['beforejoin']['table'])) { $joinparams['beforejoin'] = [$joinparams['beforejoin']]; } foreach ($joinparams['beforejoin'] as $tab) { if (isset($tab['table'])) { $intertable = $tab['table']; if (isset($tab['linkfield'])) { $interlinkfield = $tab['linkfield']; } else { $interlinkfield = getForeignKeyFieldForTable($intertable); } $interjoinparams = []; if (isset($tab['joinparams'])) { $interjoinparams = $tab['joinparams']; } $before .= self::addLeftJoin($itemtype, $rt, $already_link_tables, $intertable, $interlinkfield, $meta, $meta_type, $interjoinparams); } // No direct link with the previous joins if (!isset($tab['joinparams']['nolink']) || !$tab['joinparams']['nolink']) { $cleanrt = $intertable; $complexjoin = self::computeComplexJoinID($interjoinparams); if (!empty($complexjoin)) { $intertable .= "_".$complexjoin; } $rt = $intertable.$addmetanum; } } } $addcondition = ''; if (isset($joinparams['condition'])) { $condition = $joinparams['condition']; if (is_array($condition)) { $it = new DBmysqlIterator(null); $condition = $it->analyseCrit($condition); } $from = ["`REFTABLE`", "REFTABLE", "`NEWTABLE`", "NEWTABLE"]; $to = ["`$rt`", "`$rt`", "`$nt`", "`$nt`"]; $addcondition = str_replace($from, $to, $condition); $addcondition = $addcondition." "; } if (!isset($joinparams['jointype'])) { $joinparams['jointype'] = 'standard'; } if (empty($specific_leftjoin)) { switch ($new_table) { // No link case "glpi_auth_tables" : $user_searchopt = self::getOptions('User'); $specific_leftjoin = self::addLeftJoin($itemtype, $rt, $already_link_tables, "glpi_authldaps", 'auths_id', 0, 0, $user_searchopt[30]['joinparams']); $specific_leftjoin .= self::addLeftJoin($itemtype, $rt, $already_link_tables, "glpi_authmails", 'auths_id', 0, 0, $user_searchopt[31]['joinparams']); break; } } if (empty($specific_leftjoin)) { switch ($joinparams['jointype']) { case 'child' : $linkfield = getForeignKeyFieldForTable($cleanrt); if (isset($joinparams['linkfield'])) { $linkfield = $joinparams['linkfield']; } // Child join $specific_leftjoin = " LEFT JOIN `$new_table` $AS ON (`$rt`.`id` = `$nt`.`$linkfield` $addcondition)"; break; case 'item_item' : // Item_Item join $specific_leftjoin = " LEFT JOIN `$new_table` $AS ON ((`$rt`.`id` = `$nt`.`".getForeignKeyFieldForTable($cleanrt)."_1` OR `$rt`.`id` = `$nt`.`".getForeignKeyFieldForTable($cleanrt)."_2`) $addcondition)"; break; case 'item_item_revert' : // Item_Item join reverting previous item_item $specific_leftjoin = " LEFT JOIN `$new_table` $AS ON ((`$nt`.`id` = `$rt`.`".getForeignKeyFieldForTable($cleannt)."_1` OR `$nt`.`id` = `$rt`.`".getForeignKeyFieldForTable($cleannt)."_2`) $addcondition)"; break; case "mainitemtype_mainitem" : $addmain = 'main'; case "itemtype_item" : if (!isset($addmain)) { $addmain = ''; } $used_itemtype = $itemtype; if (isset($joinparams['specific_itemtype']) && !empty($joinparams['specific_itemtype'])) { $used_itemtype = $joinparams['specific_itemtype']; } // Itemtype join $specific_leftjoin = " LEFT JOIN `$new_table` $AS ON (`$rt`.`id` = `$nt`.`".$addmain."items_id` AND `$nt`.`".$addmain."itemtype` = '$used_itemtype' $addcondition) "; break; case "itemtype_item_revert" : if (!isset($addmain)) { $addmain = ''; } $used_itemtype = $itemtype; if (isset($joinparams['specific_itemtype']) && !empty($joinparams['specific_itemtype'])) { $used_itemtype = $joinparams['specific_itemtype']; } // Itemtype join $specific_leftjoin = " LEFT JOIN `$new_table` $AS ON (`$nt`.`id` = `$rt`.`".$addmain."items_id` AND `$rt`.`".$addmain."itemtype` = '$used_itemtype' $addcondition) "; break; case "itemtypeonly" : $used_itemtype = $itemtype; if (isset($joinparams['specific_itemtype']) && !empty($joinparams['specific_itemtype'])) { $used_itemtype = $joinparams['specific_itemtype']; } // Itemtype join $specific_leftjoin = " LEFT JOIN `$new_table` $AS ON (`$nt`.`itemtype` = '$used_itemtype' $addcondition) "; break; default : // Standard join $specific_leftjoin = "LEFT JOIN `$new_table` $AS ON (`$rt`.`$linkfield` = `$nt`.`id` $addcondition)"; $transitemtype = getItemTypeForTable($new_table); if (Session::haveTranslations($transitemtype, $field)) { $transAS = $nt.'_trans'; $specific_leftjoin .= self::joinDropdownTranslations( $transAS, $nt, $transitemtype, $field ); } break; } } return $before.$specific_leftjoin; } } /** * Generic Function to add left join for meta items * * @param string $from_type Reference item type ID * @param string $to_type Item type to add * @param array $already_link_tables2 Array of tables already joined * * @return string Meta Left join string **/ static function addMetaLeftJoin($from_type, $to_type, array &$already_link_tables2, $joinparams = []) { $LINK = " LEFT JOIN "; $from_table = $from_type::getTable(); $from_fk = getForeignKeyFieldForTable($from_table); $to_table = $to_type::getTable(); $to_fk = getForeignKeyFieldForTable($to_table); $complexjoin = self::computeComplexJoinID($joinparams); if ($complexjoin != '') { $complexjoin .= '_'; } // Generic metacriteria switch ($to_type) { case 'User' : case 'Group' : array_push($already_link_tables2, $to_table); return "$LINK `$to_table` ON (`$from_table`.`$to_fk` = `$to_table`.`id`) "; case 'Budget' : array_push($already_link_tables2, $to_table); return "$LINK `glpi_infocoms` ON (`$from_table`.`id` = `glpi_infocoms`.`items_id` AND `glpi_infocoms`.`itemtype` = '$from_type') $LINK `$to_table` ON (`glpi_infocoms`.`$to_fk` = `$to_table`.`id`) "; } // specific metacriteria switch (static::getMetaReferenceItemtype($from_type)) { case 'Ticket' : case 'Problem' : case 'Change' : switch ($from_type) { case 'Ticket': $link_table = "glpi_items_tickets"; break; case 'Problem': $link_table = "glpi_items_problems"; break; case 'Change': $link_table = "glpi_changes_items"; break; } array_push($already_link_tables2, $to_table); return " $LINK `$link_table` AS {$link_table}_to_$to_type ON (`$from_table`.`id` = `{$link_table}_to_$to_type`.`$from_fk`) $LINK `$to_table` ON (`$to_table`.`id` = `{$link_table}_to_$to_type`.`items_id` AND `{$link_table}_to_$to_type`.`itemtype` = '$to_type')"; case 'Computer' : switch ($to_type) { case 'Printer' : array_push($already_link_tables2, $to_table); array_push($already_link_tables2, "glpi_computers_items_$to_type"); return " $LINK `glpi_computers_items` AS `glpi_computers_items_$to_type` ON (`glpi_computers_items_$to_type`.`computers_id` = `glpi_computers`.`id` AND `glpi_computers_items_$to_type`.`itemtype` = '$to_type' AND `glpi_computers_items_$to_type`.`is_deleted` = 0) $LINK `glpi_printers` ON (`glpi_computers_items_$to_type`.`items_id` = `glpi_printers`.`id`) "; case 'Monitor' : array_push($already_link_tables2, $to_table); array_push($already_link_tables2, "glpi_computers_items_$to_type"); return " $LINK `glpi_computers_items` AS `glpi_computers_items_$to_type` ON (`glpi_computers_items_$to_type`.`computers_id` = `glpi_computers`.`id` AND `glpi_computers_items_$to_type`.`itemtype` = '$to_type' AND `glpi_computers_items_$to_type`.`is_deleted` = 0) $LINK `glpi_monitors` ON (`glpi_computers_items_$to_type`.`items_id` = `glpi_monitors`.`id`) "; case 'Peripheral' : array_push($already_link_tables2, $to_table); array_push($already_link_tables2, "glpi_computers_items_$to_type"); return " $LINK `glpi_computers_items` AS `glpi_computers_items_$to_type` ON (`glpi_computers_items_$to_type`.`computers_id` = `glpi_computers`.`id` AND `glpi_computers_items_$to_type`.`itemtype` = '$to_type' AND `glpi_computers_items_$to_type`.`is_deleted` = 0) $LINK `glpi_peripherals` ON (`glpi_computers_items_$to_type`.`items_id` = `glpi_peripherals`.`id`) "; case 'Phone' : array_push($already_link_tables2, $to_table); array_push($already_link_tables2, "glpi_computers_items_$to_type"); return " $LINK `glpi_computers_items` AS `glpi_computers_items_$to_type` ON (`glpi_computers_items_$to_type`.`computers_id` = `glpi_computers`.`id` AND `glpi_computers_items_$to_type`.`itemtype` = '$to_type' AND `glpi_computers_items_$to_type`.`is_deleted` = 0) $LINK `glpi_phones` ON (`glpi_computers_items_$to_type`.`items_id` = `glpi_phones`.`id`) "; case 'Software' : array_push($already_link_tables2, $to_table); array_push($already_link_tables2, "glpi_softwareversions_$to_type"); array_push($already_link_tables2, "glpi_softwarelicenses_$to_type"); return " $LINK `glpi_items_softwareversions` AS `glpi_items_softwareversions_$complexjoin$to_type` ON (`glpi_items_softwareversions_$complexjoin$to_type`.`items_id` = `$from_table`.`id` AND `glpi_items_softwareversions_$complexjoin$to_type`.`itemtype` = '$from_type' AND `glpi_items_softwareversions_$complexjoin$to_type`.`is_deleted` = 0) $LINK `glpi_softwareversions` AS `glpi_softwareversions_$complexjoin$to_type` ON (`glpi_items_softwareversions_$complexjoin$to_type`.`softwareversions_id` = `glpi_softwareversions_$complexjoin$to_type`.`id`) $LINK `glpi_softwares` ON (`glpi_softwareversions_$complexjoin$to_type`.`softwares_id` = `glpi_softwares`.`id`) LEFT JOIN `glpi_softwarelicenses` AS `glpi_softwarelicenses_$complexjoin$to_type` ON (`glpi_softwares`.`id` = `glpi_softwarelicenses_$complexjoin$to_type`.`softwares_id`". getEntitiesRestrictRequest(' AND', "glpi_softwarelicenses_$complexjoin$to_type", '', '', true).") "; } break; case 'Monitor' : switch ($to_type) { case 'Computer' : array_push($already_link_tables2, $to_table); array_push($already_link_tables2, "glpi_computers_items_$to_type"); return " $LINK `glpi_computers_items` AS `glpi_computers_items_$to_type` ON (`glpi_computers_items_$to_type`.`items_id` = `glpi_monitors`.`id` AND `glpi_computers_items_$to_type`.`itemtype` = '$from_type' AND `glpi_computers_items_$to_type`.`is_deleted` = 0) $LINK `glpi_computers` ON (`glpi_computers_items_$to_type`.`computers_id` = `glpi_computers`.`id`) "; case 'Software' : array_push($already_link_tables2, getTableForItemType($to_type)); array_push($already_link_tables2, "glpi_softwareversions_$to_type"); array_push($already_link_tables2, "glpi_softwarelicenses_$to_type"); return " $LINK `glpi_items_softwareversions` AS `glpi_items_softwareversions_$complexjoin$to_type` ON (`glpi_items_softwareversions_$complexjoin$to_type`.`items_id` = `$from_table`.`id` AND `glpi_items_softwareversions_$complexjoin$to_type`.`itemtype` = '$from_type' AND `glpi_items_softwareversions_$complexjoin$to_type`.`is_deleted` = 0) $LINK `glpi_softwareversions` AS `glpi_softwareversions_$complexjoin$to_type` ON (`glpi_items_softwareversions_$complexjoin$to_type`.`softwareversions_id` = `glpi_softwareversions_$complexjoin$to_type`.`id`) $LINK `glpi_softwares` ON (`glpi_softwareversions_$complexjoin$to_type`.`softwares_id` = `glpi_softwares`.`id`) LEFT JOIN `glpi_softwarelicenses` AS `glpi_softwarelicenses_$complexjoin$to_type` ON (`glpi_softwares`.`id` = `glpi_softwarelicenses_$complexjoin$to_type`.`softwares_id`". getEntitiesRestrictRequest(' AND', "glpi_softwarelicenses_$complexjoin$to_type", '', '', true).") "; } break; case 'Printer' : switch ($to_type) { case 'Computer' : array_push($already_link_tables2, $to_table); array_push($already_link_tables2, "glpi_computers_items_$to_type"); return " $LINK `glpi_computers_items` AS `glpi_computers_items_$to_type` ON (`glpi_computers_items_$to_type`.`items_id` = `glpi_printers`.`id` AND `glpi_computers_items_$to_type`.`itemtype` = '$from_type' AND `glpi_computers_items_$to_type`.`is_deleted` = 0) $LINK `glpi_computers` ON (`glpi_computers_items_$to_type`.`computers_id` = `glpi_computers`.`id` ". getEntitiesRestrictRequest("AND", 'glpi_computers').") "; } break; case 'Peripheral' : switch ($to_type) { case 'Computer' : array_push($already_link_tables2, $to_table); array_push($already_link_tables2, "glpi_computers_items_$to_type"); return " $LINK `glpi_computers_items` AS `glpi_computers_items_$to_type` ON (`glpi_computers_items_$to_type`.`items_id` = `glpi_peripherals`.`id` AND `glpi_computers_items_$to_type`.`itemtype` = '$from_type' AND `glpi_computers_items_$to_type`.`is_deleted` = 0) $LINK `glpi_computers` ON (`glpi_computers_items_$to_type`.`computers_id` = `glpi_computers`.`id`) "; } break; case 'Phone' : switch ($to_type) { case 'Computer' : array_push($already_link_tables2, $to_table); array_push($already_link_tables2, "glpi_computers_items_$to_type"); return " $LINK `glpi_computers_items` AS `glpi_computers_items_$to_type` ON (`glpi_computers_items_$to_type`.`items_id` = `glpi_phones`.`id` AND `glpi_computers_items_$to_type`.`itemtype` = '$from_type' AND `glpi_computers_items_$to_type`.`is_deleted` = 0) $LINK `glpi_computers` ON (`glpi_computers_items_$to_type`.`computers_id` = `glpi_computers`.`id`) "; } break; case 'Software' : switch ($to_type) { case 'Computer' : array_push($already_link_tables2, $to_table); array_push($already_link_tables2, "glpi_softwareversions_$to_type"); array_push($already_link_tables2, "glpi_softwareversions_$to_type"); return " $LINK `glpi_softwareversions` AS `glpi_softwareversions_$to_type` ON (`glpi_softwareversions_$to_type`.`softwares_id` = `glpi_softwares`.`id`) $LINK `glpi_items_softwareversions` AS `glpi_items_softwareversions_$to_type` ON (`glpi_items_softwareversions_$to_type`.`softwareversions_id` = `glpi_softwareversions_$to_type`.`id` AND `glpi_items_softwareversions_$to_type`.`itemtype` = '$from_type' AND `glpi_items_softwareversions_$to_type`.`is_deleted` = 0) $LINK `$to_table` ON (`glpi_items_softwareversions_$to_type`.`items_id` = `$to_table`.`id` AND `glpi_items_softwareversions_$to_type`.`itemtype` = '$to_type' ". getEntitiesRestrictRequest("AND", $to_table).") "; } break; } } /** * Generic Function to display Items * * @since 9.4: $num param has been dropped * * @param string $itemtype item type * @param integer $ID ID of the SEARCH_OPTION item * @param array $data array retrieved data array * * @return string String to print **/ static function displayConfigItem($itemtype, $ID, $data = []) { $searchopt = &self::getOptions($itemtype); $table = $searchopt[$ID]["table"]; $field = $searchopt[$ID]["field"]; // Plugin can override core definition for its type if ($plug = isPluginItemType($itemtype)) { $out = Plugin::doOneHook( $plug['plugin'], 'displayConfigItem', $itemtype, $ID, $data, "{$itemtype}_{$ID}" ); if (!empty($out)) { return $out; } } $out = ""; $NAME = "{$itemtype}_{$ID}"; switch ($table.".".$field) { case "glpi_tickets.time_to_resolve" : case "glpi_tickets.internal_time_to_resolve" : case "glpi_problems.time_to_resolve" : case "glpi_changes.time_to_resolve" : case "glpi_tickets.time_to_own" : case "glpi_tickets.internal_time_to_own" : if (!in_array($ID, [151, 158, 181, 186]) && !empty($data[$NAME][0]['name']) && ($data[$NAME][0]['status'] != CommonITILObject::WAITING) && ($data[$NAME][0]['name'] < $_SESSION['glpi_currenttime'])) { $out = " style=\"background-color: #cf9b9b\" "; } break; case "glpi_projectstates.color" : $out = " style=\"background-color:".$data[$NAME][0]['name'].";\" "; break; case "glpi_projectstates.name" : if (array_key_exists('color', $data[$NAME][0])) { $out = " style=\"background-color:".$data[$NAME][0]['color'].";\" "; } break; } return $out; } /** * Generic Function to display Items * * @since 9.4: $num param has been dropped * * @param string $itemtype item type * @param integer $ID ID of the SEARCH_OPTION item * @param array $data array containing data results * @param boolean $meta is a meta item ? (default 0) * @param array $addobjectparams array added parameters for union search * @param string $orig_itemtype Original itemtype, used for union_search_type * * @return string String to print **/ static function giveItem($itemtype, $ID, array $data, $meta = 0, array $addobjectparams = [], $orig_itemtype = null) { global $CFG_GLPI; $searchopt = &self::getOptions($itemtype); if ($itemtype == 'AllAssets' || isset($CFG_GLPI["union_search_type"][$itemtype]) && ($CFG_GLPI["union_search_type"][$itemtype] == $searchopt[$ID]["table"])) { $oparams = []; if (isset($searchopt[$ID]['addobjectparams']) && $searchopt[$ID]['addobjectparams']) { $oparams = $searchopt[$ID]['addobjectparams']; } // Search option may not exists in subtype // This is the case for "Inventory number" for a Software listed from ReservationItem search $subtype_so = &self::getOptions($data["TYPE"]); if (!array_key_exists($ID, $subtype_so)) { return ''; } return self::giveItem($data["TYPE"], $ID, $data, $meta, $oparams, $itemtype); } $so = $searchopt[$ID]; $orig_id = $ID; $ID = ($orig_itemtype !== null ? $orig_itemtype : $itemtype) . '_' . $ID; if (count($addobjectparams)) { $so = array_merge($so, $addobjectparams); } // Plugin can override core definition for its type if ($plug = isPluginItemType($itemtype)) { $out = Plugin::doOneHook( $plug['plugin'], 'giveItem', $itemtype, $orig_id, $data, $ID ); if (!empty($out)) { return $out; } } if (isset($so["table"])) { $table = $so["table"]; $field = $so["field"]; $linkfield = $so["linkfield"]; /// TODO try to clean all specific cases using SpecificToDisplay switch ($table.'.'.$field) { case "glpi_users.name" : if ($itemtype == 'Ticket' && Session::getCurrentInterface() == 'helpdesk' && $orig_id == 5 && Entity::getUsedConfig( 'anonymize_support_agents', $itemtype::getById($data['id'])->getEntityId() ) ) { return __("Helpdesk"); } // USER search case if (($itemtype != 'User') && isset($so["forcegroupby"]) && $so["forcegroupby"]) { $out = ""; $count_display = 0; $added = []; $showuserlink = 0; if (Session::haveRight('user', READ)) { $showuserlink = 1; } for ($k=0; $k<$data[$ID]['count']; $k++) { if ((isset($data[$ID][$k]['name']) && ($data[$ID][$k]['name'] > 0)) || (isset($data[$ID][$k][2]) && ($data[$ID][$k][2] != ''))) { if ($count_display) { $out .= self::LBBR; } if ($itemtype == 'Ticket') { if (isset($data[$ID][$k]['name']) && $data[$ID][$k]['name'] > 0) { $userdata = getUserName($data[$ID][$k]['name'], 2); $tooltip = ""; if (Session::haveRight('user', READ)) { $tooltip = Html::showToolTip($userdata["comment"], ['link' => $userdata["link"], 'display' => false]); } $out .= sprintf(__('%1$s %2$s'), $userdata['name'], $tooltip); $count_display++; } } else { $out .= getUserName($data[$ID][$k]['name'], $showuserlink); $count_display++; } // Manage alternative_email for tickets_users if (($itemtype == 'Ticket') && isset($data[$ID][$k][2])) { $split = explode(self::LONGSEP, $data[$ID][$k][2]); for ($l=0; $l".$split2[1].""; } } } } } return $out; } if ($itemtype != 'User') { $toadd = ''; if (($itemtype == 'Ticket') && ($data[$ID][0]['id'] > 0)) { $userdata = getUserName($data[$ID][0]['id'], 2); $toadd = Html::showToolTip($userdata["comment"], ['link' => $userdata["link"], 'display' => false]); } $usernameformat = formatUserName($data[$ID][0]['id'], $data[$ID][0]['name'], $data[$ID][0]['realname'], $data[$ID][0]['firstname'], 1); return sprintf(__('%1$s %2$s'), $usernameformat, $toadd); } break; case "glpi_profiles.name" : if (($itemtype == 'User') && ($orig_id == 20)) { $out = ""; $count_display = 0; $added = []; for ($k=0; $k<$data[$ID]['count']; $k++) { if (strlen(trim($data[$ID][$k]['name'])) > 0 && !in_array($data[$ID][$k]['name']."-".$data[$ID][$k]['entities_id'], $added)) { $text = sprintf(__('%1$s - %2$s'), $data[$ID][$k]['name'], Dropdown::getDropdownName('glpi_entities', $data[$ID][$k]['entities_id'])); $comp = ''; if ($data[$ID][$k]['is_recursive']) { $comp = __('R'); if ($data[$ID][$k]['is_dynamic']) { $comp = sprintf(__('%1$s%2$s'), $comp, ", "); } } if ($data[$ID][$k]['is_dynamic']) { $comp = sprintf(__('%1$s%2$s'), $comp, __('D')); } if (!empty($comp)) { $text = sprintf(__('%1$s %2$s'), $text, "(".$comp.")"); } if ($count_display) { $out .= self::LBBR; } $count_display++; $out .= $text; $added[] = $data[$ID][$k]['name']."-".$data[$ID][$k]['entities_id']; } } return $out; } break; case "glpi_entities.completename" : if ($itemtype == 'User') { $out = ""; $added = []; $count_display = 0; for ($k=0; $k<$data[$ID]['count']; $k++) { if (isset($data[$ID][$k]['name']) && (strlen(trim($data[$ID][$k]['name'])) > 0) && !in_array($data[$ID][$k]['name']."-".$data[$ID][$k]['profiles_id'], $added)) { $text = sprintf(__('%1$s - %2$s'), $data[$ID][$k]['name'], Dropdown::getDropdownName('glpi_profiles', $data[$ID][$k]['profiles_id'])); $comp = ''; if ($data[$ID][$k]['is_recursive']) { $comp = __('R'); if ($data[$ID][$k]['is_dynamic']) { $comp = sprintf(__('%1$s%2$s'), $comp, ", "); } } if ($data[$ID][$k]['is_dynamic']) { $comp = sprintf(__('%1$s%2$s'), $comp, __('D')); } if (!empty($comp)) { $text = sprintf(__('%1$s %2$s'), $text, "(".$comp.")"); } if ($count_display) { $out .= self::LBBR; } $count_display++; $out .= $text; $added[] = $data[$ID][$k]['name']."-".$data[$ID][$k]['profiles_id']; } } return $out; } break; case "glpi_documenttypes.icon" : if (!empty($data[$ID][0]['name'])) { return ""; } return " "; case "glpi_documents.filename" : $doc = new Document(); if ($doc->getFromDB($data['id'])) { return $doc->getDownloadLink(); } return NOT_AVAILABLE; case "glpi_tickets_tickets.tickets_id_1" : $out = ""; $displayed = []; for ($k=0; $k<$data[$ID]['count']; $k++) { $linkid = ($data[$ID][$k]['tickets_id_2'] == $data['id']) ? $data[$ID][$k]['name'] : $data[$ID][$k]['tickets_id_2']; if (($linkid > 0) && !isset($displayed[$linkid])) { $text = ""; $text .= Dropdown::getDropdownName('glpi_tickets', $linkid).""; if (count($displayed)) { $out .= self::LBBR; } $displayed[$linkid] = $linkid; $out .= $text; } } return $out; case "glpi_problems.id" : if ($so["datatype"] == 'count') { if (($data[$ID][0]['name'] > 0) && Session::haveRight("problem", Problem::READALL)) { if ($itemtype == 'ITILCategory') { $options['criteria'][0]['field'] = 7; $options['criteria'][0]['searchtype'] = 'equals'; $options['criteria'][0]['value'] = $data['id']; $options['criteria'][0]['link'] = 'AND'; } else { $options['criteria'][0]['field'] = 12; $options['criteria'][0]['searchtype'] = 'equals'; $options['criteria'][0]['value'] = 'all'; $options['criteria'][0]['link'] = 'AND'; $options['metacriteria'][0]['itemtype'] = $itemtype; $options['metacriteria'][0]['field'] = self::getOptionNumber($itemtype, 'name'); $options['metacriteria'][0]['searchtype'] = 'equals'; $options['metacriteria'][0]['value'] = $data['id']; $options['metacriteria'][0]['link'] = 'AND'; } $options['reset'] = 'reset'; $out = ""; $out .= $data[$ID][0]['name'].""; return $out; } } break; case "glpi_tickets.id" : if ($so["datatype"] == 'count') { if (($data[$ID][0]['name'] > 0) && Session::haveRight("ticket", Ticket::READALL)) { if ($itemtype == 'User') { // Requester if ($ID == 60) { $options['criteria'][0]['field'] = 4; $options['criteria'][0]['searchtype']= 'equals'; $options['criteria'][0]['value'] = $data['id']; $options['criteria'][0]['link'] = 'AND'; } // Writer if ($ID == 61) { $options['criteria'][0]['field'] = 22; $options['criteria'][0]['searchtype']= 'equals'; $options['criteria'][0]['value'] = $data['id']; $options['criteria'][0]['link'] = 'AND'; } // Assign if ($ID == 64) { $options['criteria'][0]['field'] = 5; $options['criteria'][0]['searchtype']= 'equals'; $options['criteria'][0]['value'] = $data['id']; $options['criteria'][0]['link'] = 'AND'; } } else if ($itemtype == 'ITILCategory') { $options['criteria'][0]['field'] = 7; $options['criteria'][0]['searchtype'] = 'equals'; $options['criteria'][0]['value'] = $data['id']; $options['criteria'][0]['link'] = 'AND'; } else { $options['criteria'][0]['field'] = 12; $options['criteria'][0]['searchtype'] = 'equals'; $options['criteria'][0]['value'] = 'all'; $options['criteria'][0]['link'] = 'AND'; $options['metacriteria'][0]['itemtype'] = $itemtype; $options['metacriteria'][0]['field'] = self::getOptionNumber($itemtype, 'name'); $options['metacriteria'][0]['searchtype'] = 'equals'; $options['metacriteria'][0]['value'] = $data['id']; $options['metacriteria'][0]['link'] = 'AND'; } $options['reset'] = 'reset'; $out = ""; $out .= $data[$ID][0]['name'].""; return $out; } } break; case "glpi_tickets.time_to_resolve" : case "glpi_problems.time_to_resolve" : case "glpi_changes.time_to_resolve" : case "glpi_tickets.time_to_own" : case "glpi_tickets.internal_time_to_own" : case "glpi_tickets.internal_time_to_resolve" : // Due date + progress if (in_array($orig_id, [151, 158, 181, 186])) { $out = Html::convDateTime($data[$ID][0]['name']); // No due date in waiting status if ($data[$ID][0]['status'] == CommonITILObject::WAITING) { return ''; } if (empty($data[$ID][0]['name'])) { return ''; } if (($data[$ID][0]['status'] == Ticket::SOLVED) || ($data[$ID][0]['status'] == Ticket::CLOSED)) { return $out; } $itemtype = getItemTypeForTable($table); $item = new $itemtype(); $item->getFromDB($data['id']); $percentage = 0; $totaltime = 0; $currenttime = 0; $slaField = 'slas_id'; // define correct sla field switch ($table.'.'.$field) { case "glpi_tickets.time_to_resolve" : $slaField = 'slas_id_ttr'; break; case "glpi_tickets.time_to_own" : $slaField = 'slas_id_tto'; break; case "glpi_tickets.internal_time_to_own" : $slaField = 'olas_id_tto'; break; case "glpi_tickets.internal_time_to_resolve" : $slaField = 'olas_id_ttr'; break; } switch ($table.'.'.$field) { // If ticket has been taken into account : no progression display case "glpi_tickets.time_to_own" : case "glpi_tickets.internal_time_to_own" : if (($item->fields['takeintoaccount_delay_stat'] > 0)) { return $out; } break; } if ($item->isField($slaField) && $item->fields[$slaField] != 0) { // Have SLA $sla = new SLA(); $sla->getFromDB($item->fields[$slaField]); $currenttime = $sla->getActiveTimeBetween($item->fields['date'], date('Y-m-d H:i:s')); $totaltime = $sla->getActiveTimeBetween($item->fields['date'], $data[$ID][0]['name']); } else { $calendars_id = Entity::getUsedConfig('calendars_id', $item->fields['entities_id']); if ($calendars_id != 0) { // Ticket entity have calendar $calendar = new Calendar(); $calendar->getFromDB($calendars_id); $currenttime = $calendar->getActiveTimeBetween($item->fields['date'], date('Y-m-d H:i:s')); $totaltime = $calendar->getActiveTimeBetween($item->fields['date'], $data[$ID][0]['name']); } else { // No calendar $currenttime = strtotime(date('Y-m-d H:i:s')) - strtotime($item->fields['date']); $totaltime = strtotime($data[$ID][0]['name']) - strtotime($item->fields['date']); } } if ($totaltime != 0) { $percentage = round((100 * $currenttime) / $totaltime); } else { // Total time is null : no active time $percentage = 100; } if ($percentage > 100) { $percentage = 100; } $percentage_text = $percentage; if ($_SESSION['glpiduedatewarning_unit'] == '%') { $less_warn_limit = $_SESSION['glpiduedatewarning_less']; $less_warn = (100 - $percentage); } else if ($_SESSION['glpiduedatewarning_unit'] == 'hour') { $less_warn_limit = $_SESSION['glpiduedatewarning_less'] * HOUR_TIMESTAMP; $less_warn = ($totaltime - $currenttime); } else if ($_SESSION['glpiduedatewarning_unit'] == 'day') { $less_warn_limit = $_SESSION['glpiduedatewarning_less'] * DAY_TIMESTAMP; $less_warn = ($totaltime - $currenttime); } if ($_SESSION['glpiduedatecritical_unit'] == '%') { $less_crit_limit = $_SESSION['glpiduedatecritical_less']; $less_crit = (100 - $percentage); } else if ($_SESSION['glpiduedatecritical_unit'] == 'hour') { $less_crit_limit = $_SESSION['glpiduedatecritical_less'] * HOUR_TIMESTAMP; $less_crit = ($totaltime - $currenttime); } else if ($_SESSION['glpiduedatecritical_unit'] == 'day') { $less_crit_limit = $_SESSION['glpiduedatecritical_less'] * DAY_TIMESTAMP; $less_crit = ($totaltime - $currenttime); } $color = $_SESSION['glpiduedateok_color']; if ($less_crit < $less_crit_limit) { $color = $_SESSION['glpiduedatecritical_color']; } else if ($less_warn < $less_warn_limit) { $color = $_SESSION['glpiduedatewarning_color']; } if (!isset($so['datatype'])) { $so['datatype'] = 'progressbar'; } $progressbar_data = [ 'text' => Html::convDateTime($data[$ID][0]['name']), 'percent' => $percentage, 'percent_text' => $percentage_text, 'color' => $color ]; } break; case "glpi_softwarelicenses.number" : if ($data[$ID][0]['min'] == -1) { return __('Unlimited'); } if (empty($data[$ID][0]['name'])) { return 0; } return $data[$ID][0]['name']; case "glpi_auth_tables.name" : return Auth::getMethodName($data[$ID][0]['name'], $data[$ID][0]['auths_id'], 1, $data[$ID][0]['ldapname'].$data[$ID][0]['mailname']); case "glpi_reservationitems.comment" : if (empty($data[$ID][0]['name'])) { $text = __('None'); } else { $text = Html::resume_text($data[$ID][0]['name']); } if (Session::haveRight('reservation', UPDATE)) { return "".$text.""; } return $text; case 'glpi_crontasks.description' : $tmp = new CronTask(); return $tmp->getDescription($data[$ID][0]['name']); case 'glpi_changes.status': $status = Change::getStatus($data[$ID][0]['name']); return "". Change::getStatusIcon($data[$ID][0]['name']) . " $status". ""; case 'glpi_problems.status': $status = Problem::getStatus($data[$ID][0]['name']); return "". Problem::getStatusIcon($data[$ID][0]['name']) . " $status". ""; case 'glpi_tickets.status': $status = Ticket::getStatus($data[$ID][0]['name']); return "". Ticket::getStatusIcon($data[$ID][0]['name']) . " $status". ""; case 'glpi_projectstates.name': $out = ''; $name = $data[$ID][0]['name']; if (isset($data[$ID][0]['trans'])) { $name = $data[$ID][0]['trans']; } if ($itemtype == 'ProjectState') { $out = "". $name.""; } else { $out = $name; } return $out; case 'glpi_items_tickets.items_id' : case 'glpi_items_problems.items_id' : case 'glpi_changes_items.items_id' : case 'glpi_certificates_items.items_id' : case 'glpi_appliances_items.items_id' : if (!empty($data[$ID])) { $items = []; foreach ($data[$ID] as $key => $val) { if (is_numeric($key)) { if (!empty($val['itemtype']) && ($item = getItemForItemtype($val['itemtype']))) { if ($item->getFromDB($val['name'])) { $items[] = $item->getLink(['comments' => true]); } } } } if (!empty($items)) { return implode("
    ", $items); } } return ' '; case 'glpi_items_tickets.itemtype' : case 'glpi_items_problems.itemtype' : if (!empty($data[$ID])) { $itemtypes = []; foreach ($data[$ID] as $key => $val) { if (is_numeric($key)) { if (!empty($val['name'])) { $item = new $val['name'](); $name = $item->getTypeName(); $itemtypes[] = __($name); } } } if (!empty($itemtypes)) { return implode("
    ", $itemtypes); } } return ' '; case 'glpi_tickets.name' : case 'glpi_problems.name' : case 'glpi_changes.name' : if (isset($data[$ID][0]['content']) && isset($data[$ID][0]['id']) && isset($data[$ID][0]['status'])) { $link = $itemtype::getFormURLWithID($data[$ID][0]['id']); $out = "getSolvedStatusArray())) { $out .= "&forcetab=$itemtype$2"; } } $out .= "\">"; $name = $data[$ID][0]['name']; if ($_SESSION["glpiis_ids_visible"] || empty($data[$ID][0]['name'])) { $name = sprintf(__('%1$s (%2$s)'), $name, $data[$ID][0]['id']); } $out .= $name.""; $hdecode = Html::entity_decode_deep($data[$ID][0]['content']); $content = Toolbox::unclean_cross_side_scripting_deep($hdecode); $out = sprintf(__('%1$s %2$s'), $out, Html::showToolTip(nl2br(Html::Clean($content)), ['applyto' => $itemtype. $data[$ID][0]['id'], 'display' => false])); return $out; } case 'glpi_ticketvalidations.status' : $out = ''; for ($k=0; $k<$data[$ID]['count']; $k++) { if ($data[$ID][$k]['name']) { $status = TicketValidation::getStatus($data[$ID][$k]['name']); $bgcolor = TicketValidation::getStatusColor($data[$ID][$k]['name']); $out .= (empty($out)?'':self::LBBR). "
    ".$status.'
    '; } } return $out; case 'glpi_ticketsatisfactions.satisfaction' : if (self::$output_type == self::HTML_OUTPUT) { return TicketSatisfaction::displaySatisfaction($data[$ID][0]['name']); } break; case 'glpi_projects._virtual_planned_duration' : return Html::timestampToString(ProjectTask::getTotalPlannedDurationForProject($data["id"]), false); case 'glpi_projects._virtual_effective_duration' : return Html::timestampToString(ProjectTask::getTotalEffectiveDurationForProject($data["id"]), false); case 'glpi_cartridgeitems._virtual' : return Cartridge::getCount($data["id"], $data[$ID][0]['alarm_threshold'], self::$output_type != self::HTML_OUTPUT); case 'glpi_printers._virtual' : return Cartridge::getCountForPrinter($data["id"], self::$output_type != self::HTML_OUTPUT); case 'glpi_consumableitems._virtual' : return Consumable::getCount($data["id"], $data[$ID][0]['alarm_threshold'], self::$output_type != self::HTML_OUTPUT); case 'glpi_links._virtual' : $out = ''; $link = new Link(); if (($item = getItemForItemtype($itemtype)) && $item->getFromDB($data['id']) && $link->getfromDB($data[$ID][0]['id']) && ($item->fields['entities_id'] == $link->fields['entities_id'])) { if (count($data[$ID])) { $count_display = 0; foreach ($data[$ID] as$val) { if (is_array($val)) { $links = Link::getAllLinksFor($item, $val); foreach ($links as $link) { if ($count_display) { $out .= self::LBBR; } $out .= $link; $count_display++; } } } } } return $out; case 'glpi_reservationitems._virtual' : if ($data[$ID][0]['is_active']) { return "". "".__('See planning').""; } else { return " "; } case "glpi_tickets.priority" : case "glpi_problems.priority" : case "glpi_changes.priority" : case "glpi_projects.priority" : $index = $data[$ID][0]['name']; $color = $_SESSION["glpipriority_$index"]; $name = CommonITILObject::getPriorityName($index); return "
     $name
    "; } } //// Default case if ($itemtype == 'Ticket' && Session::getCurrentInterface() == 'helpdesk' && $orig_id == 8 && Entity::getUsedConfig( 'anonymize_support_agents', $itemtype::getById($data['id'])->getEntityId() ) ) { // Assigned groups return __("Helpdesk group"); } // Link with plugin tables : need to know left join structure if (isset($table)) { if (preg_match("/^glpi_plugin_([a-z0-9]+)/", $table.'.'.$field, $matches)) { if (count($matches) == 2) { $plug = $matches[1]; $out = Plugin::doOneHook( $plug, 'giveItem', $itemtype, $orig_id, $data, $ID ); if (!empty($out)) { return $out; } } } } $unit = ''; if (isset($so['unit'])) { $unit = $so['unit']; } // Preformat items if (isset($so["datatype"])) { switch ($so["datatype"]) { case "itemlink" : $linkitemtype = getItemTypeForTable($so["table"]); $out = ""; $count_display = 0; $separate = self::LBBR; if (isset($so['splititems']) && $so['splititems']) { $separate = self::LBHR; } for ($k=0; $k<$data[$ID]['count']; $k++) { if (isset($data[$ID][$k]['id'])) { if ($count_display) { $out .= $separate; } $count_display++; $page = $linkitemtype::getFormURLWithID($data[$ID][$k]['id']); $name = Dropdown::getValueWithUnit($data[$ID][$k]['name'], $unit); if ($_SESSION["glpiis_ids_visible"] || empty($data[$ID][$k]['name'])) { $name = sprintf(__('%1$s (%2$s)'), $name, $data[$ID][$k]['id']); } $out .= "". $name.""; } } return $out; case "text" : $separate = self::LBBR; if (isset($so['splititems']) && $so['splititems']) { $separate = self::LBHR; } $out = ''; $count_display = 0; for ($k=0; $k<$data[$ID]['count']; $k++) { if (strlen(trim($data[$ID][$k]['name'])) > 0) { if ($count_display) { $out .= $separate; } $count_display++; $text = ""; if (isset($so['htmltext']) && $so['htmltext']) { $text = Html::clean(Toolbox::unclean_cross_side_scripting_deep(nl2br($data[$ID][$k]['name']))); } else { $text = nl2br($data[$ID][$k]['name']); } if (self::$output_type == self::HTML_OUTPUT && (Toolbox::strlen($text) > $CFG_GLPI['cut'])) { $rand = mt_rand(); $popup_params = [ 'display' => false ]; if (Toolbox::strlen($text) > $CFG_GLPI['cut']) { $popup_params += [ 'awesome-class' => 'fa-comments', 'autoclose' => false, 'onclick' => true ]; } else { $popup_params += [ 'applyto' => "text$rand", ]; } $out .= sprintf( __('%1$s %2$s'), "". Html::resume_text($text, $CFG_GLPI['cut']).'', Html::showToolTip( '
    '.$text.'
    ', $popup_params ) ); } else { $out .= $text; } } } return $out; case "date" : case "date_delay" : $out = ''; for ($k=0; $k<$data[$ID]['count']; $k++) { if (is_null($data[$ID][$k]['name']) && isset($so['emptylabel']) && $so['emptylabel']) { $out .= (empty($out)?'':self::LBBR).$so['emptylabel']; } else { $out .= (empty($out)?'':self::LBBR).Html::convDate($data[$ID][$k]['name']); } } return $out; case "datetime" : $out = ''; for ($k=0; $k<$data[$ID]['count']; $k++) { if (is_null($data[$ID][$k]['name']) && isset($so['emptylabel']) && $so['emptylabel']) { $out .= (empty($out)?'':self::LBBR).$so['emptylabel']; } else { $out .= (empty($out)?'':self::LBBR).Html::convDateTime($data[$ID][$k]['name']); } } return $out; case "timestamp" : $withseconds = false; if (isset($so['withseconds'])) { $withseconds = $so['withseconds']; } $withdays = true; if (isset($so['withdays'])) { $withdays = $so['withdays']; } $out = ''; for ($k=0; $k<$data[$ID]['count']; $k++) { $out .= (empty($out)?'':'
    ').Html::timestampToString($data[$ID][$k]['name'], $withseconds, $withdays); } return $out; case "email" : $out = ''; $count_display = 0; for ($k=0; $k<$data[$ID]['count']; $k++) { if ($count_display) { $out .= self::LBBR; } $count_display++; if (!empty($data[$ID][$k]['name'])) { $out .= (empty($out)?'':self::LBBR); $out .= "".$data[$ID][$k]['name']; $out .= ""; } } return (empty($out) ? " " : $out); case "weblink" : $orig_link = trim($data[$ID][0]['name']); if (!empty($orig_link)) { // strip begin of link $link = preg_replace('/https?:\/\/(www[^\.]*\.)?/', '', $orig_link); $link = preg_replace('/\/$/', '', $link); if (Toolbox::strlen($link)>$CFG_GLPI["url_maxlength"]) { $link = Toolbox::substr($link, 0, $CFG_GLPI["url_maxlength"])."..."; } return "$link"; } return " "; case "count" : case "number" : $out = ""; $count_display = 0; for ($k=0; $k<$data[$ID]['count']; $k++) { if (strlen(trim($data[$ID][$k]['name'])) > 0) { if ($count_display) { $out .= self::LBBR; } $count_display++; if (isset($so['toadd']) && isset($so['toadd'][$data[$ID][$k]['name']])) { $out .= $so['toadd'][$data[$ID][$k]['name']]; } else { $number = str_replace(' ', ' ', Html::formatNumber($data[$ID][$k]['name'], false, 0)); $out .= Dropdown::getValueWithUnit($number, $unit); } } } return $out; case "decimal" : $out = ""; $count_display = 0; for ($k=0; $k<$data[$ID]['count']; $k++) { if (strlen(trim($data[$ID][$k]['name'])) > 0) { if ($count_display) { $out .= self::LBBR; } $count_display++; if (isset($so['toadd']) && isset($so['toadd'][$data[$ID][$k]['name']])) { $out .= $so['toadd'][$data[$ID][$k]['name']]; } else { $number = str_replace(' ', ' ', Html::formatNumber($data[$ID][$k]['name'])); $out .= Dropdown::getValueWithUnit($number, $unit); } } } return $out; case "bool" : $out = ""; $count_display = 0; for ($k=0; $k<$data[$ID]['count']; $k++) { if (strlen(trim($data[$ID][$k]['name'])) > 0) { if ($count_display) { $out .= self::LBBR; } $count_display++; $out .= Dropdown::getValueWithUnit(Dropdown::getYesNo($data[$ID][$k]['name']), $unit); } } return $out; case "itemtypename": if ($obj = getItemForItemtype($data[$ID][0]['name'])) { return $obj->getTypeName(); } return ""; case "language": if (isset($CFG_GLPI['languages'][$data[$ID][0]['name']])) { return $CFG_GLPI['languages'][$data[$ID][0]['name']][0]; } return __('Default value'); case 'progressbar': if (!isset($progressbar_data)) { $bar_color = 'green'; $progressbar_data = [ 'percent' => $data[$ID][0]['name'], 'percent_text' => $data[$ID][0]['name'], 'color' => $bar_color, 'text' => '' ]; } $out = "{$progressbar_data['text']}
    "; $out .= "
     {$progressbar_data['percent_text']}%
    "; $out .= "
    "; $out .= "
    "; return $out; break; } } // Manage items with need group by / group_concat $out = ""; $count_display = 0; $separate = self::LBBR; if (isset($so['splititems']) && $so['splititems']) { $separate = self::LBHR; } for ($k=0; $k<$data[$ID]['count']; $k++) { if (strlen(trim($data[$ID][$k]['name'])) > 0) { if ($count_display) { $out .= $separate; } $count_display++; // Get specific display if available if (isset($table)) { $itemtype = getItemTypeForTable($table); if ($item = getItemForItemtype($itemtype)) { $tmpdata = $data[$ID][$k]; // Copy name to real field $tmpdata[$field] = $data[$ID][$k]['name']; $specific = $item->getSpecificValueToDisplay( $field, $tmpdata, [ 'html' => true, 'searchopt' => $so, 'raw_data' => $data ] ); } } if (!empty($specific)) { $out .= $specific; } else { if (isset($so['toadd']) && isset($so['toadd'][$data[$ID][$k]['name']])) { $out .= $so['toadd'][$data[$ID][$k]['name']]; } else { // Empty is 0 or empty if (empty($split[0])&& isset($so['emptylabel'])) { $out .= $so['emptylabel']; } else { // Trans field exists if (isset($data[$ID][$k]['trans']) && !empty($data[$ID][$k]['trans'])) { $out .= Dropdown::getValueWithUnit($data[$ID][$k]['trans'], $unit); } else { $out .= Dropdown::getValueWithUnit($data[$ID][$k]['name'], $unit); } } } } } } return $out; } /** * Reset save searches * * @return void **/ static function resetSaveSearch() { unset($_SESSION['glpisearch']); $_SESSION['glpisearch'] = []; } /** * Completion of the URL $_GET values with the $_SESSION values or define default values * * @param string $itemtype Item type to manage * @param array $params Params to parse * @param boolean $usesession Use datas save in session (true by default) * @param boolean $forcebookmark Force trying to load parameters from default bookmark: * used for global search (false by default) * * @return array parsed params **/ static function manageParams($itemtype, $params = [], $usesession = true, $forcebookmark = false) { $default_values = []; $default_values["start"] = 0; $default_values["order"] = "ASC"; $default_values["sort"] = 1; $default_values["is_deleted"] = 0; $default_values["as_map"] = 0; if (isset($params['start'])) { $params['start'] = (int)$params['start']; } $default_values["criteria"] = self::getDefaultCriteria($itemtype); $default_values["metacriteria"] = []; // Reorg search array // start // order // sort // is_deleted // itemtype // criteria : array (0 => array (link => // field => // searchtype => // value => (contains) // metacriteria : array (0 => array (itemtype => // link => // field => // searchtype => // value => (contains) if (($itemtype != 'AllAssets') && class_exists($itemtype)) { // retrieve default values for current itemtype $itemtype_default_values = []; if (method_exists($itemtype, 'getDefaultSearchRequest')) { $itemtype_default_values = call_user_func([$itemtype, 'getDefaultSearchRequest']); } // retrieve default values for the current user $user_default_values = SavedSearch_User::getDefault(Session::getLoginUserID(), $itemtype); if ($user_default_values === false) { $user_default_values = []; } // we construct default values in this order: // - general default // - itemtype default // - user default // // The last ones erase values or previous // So, we can combine each part (order from itemtype, criteria from user, etc) $default_values = array_merge($default_values, $itemtype_default_values, $user_default_values); } // First view of the page or force bookmark : try to load a bookmark if ($forcebookmark || ($usesession && !isset($params["reset"]) && !isset($_SESSION['glpisearch'][$itemtype]))) { $user_default_values = SavedSearch_User::getDefault(Session::getLoginUserID(), $itemtype); if ($user_default_values) { $_SESSION['glpisearch'][$itemtype] = []; // Only get datas for bookmarks if ($forcebookmark) { $params = $user_default_values; } else { $bookmark = new SavedSearch(); $bookmark->load($user_default_values['savedsearches_id'], false); } } } // Force reorder criterias if (isset($params["criteria"]) && is_array($params["criteria"]) && count($params["criteria"])) { $tmp = $params["criteria"]; $params["criteria"] = []; foreach ($tmp as $val) { $params["criteria"][] = $val; } } // transform legacy meta-criteria in criteria (with flag meta=true) // at the end of the array, as before there was only at the end of the query if (isset($params["metacriteria"]) && is_array($params["metacriteria"])) { // as we will append meta to criteria, check the key exists if (!isset($params["criteria"])) { $params["criteria"] = []; } foreach ($params["metacriteria"] as $val) { $params["criteria"][] = $val + ['meta' => 1]; } $params["metacriteria"] = []; } if ($usesession && isset($params["reset"])) { if (isset($_SESSION['glpisearch'][$itemtype])) { unset($_SESSION['glpisearch'][$itemtype]); } } if (isset($params) && is_array($params) && $usesession) { foreach ($params as $key => $val) { $_SESSION['glpisearch'][$itemtype][$key] = $val; } } $saved_params = $params; foreach ($default_values as $key => $val) { if (!isset($params[$key])) { if ($usesession && ($key == 'is_deleted' || $key == 'as_map' || !isset($saved_params['criteria'])) // retrieve session only if not a new request && isset($_SESSION['glpisearch'][$itemtype][$key])) { $params[$key] = $_SESSION['glpisearch'][$itemtype][$key]; } else { $params[$key] = $val; $_SESSION['glpisearch'][$itemtype][$key] = $val; } } } return $params; } /** * Clean search options depending of user active profile * * @param string $itemtype Item type to manage * @param integer $action Action which is used to manupulate searchoption * (default READ) * @param boolean $withplugins Get plugins options (true by default) * * @return array Clean $SEARCH_OPTION array **/ static function getCleanedOptions($itemtype, $action = READ, $withplugins = true) { global $CFG_GLPI; $options = &self::getOptions($itemtype, $withplugins); $todel = []; if (!Session::haveRight('infocom', $action) && Infocom::canApplyOn($itemtype)) { $itemstodel = Infocom::getSearchOptionsToAdd($itemtype); $todel = array_merge($todel, array_keys($itemstodel)); } if (!Session::haveRight('contract', $action) && in_array($itemtype, $CFG_GLPI["contract_types"])) { $itemstodel = Contract::getSearchOptionsToAdd(); $todel = array_merge($todel, array_keys($itemstodel)); } if (!Session::haveRight('document', $action) && Document::canApplyOn($itemtype)) { $itemstodel = Document::getSearchOptionsToAdd(); $todel = array_merge($todel, array_keys($itemstodel)); } // do not show priority if you don't have right in profile if (($itemtype == 'Ticket') && ($action == UPDATE) && !Session::haveRight('ticket', Ticket::CHANGEPRIORITY)) { $todel[] = 3; } if ($itemtype == 'Computer') { if (!Session::haveRight('networking', $action)) { $itemstodel = NetworkPort::getSearchOptionsToAdd($itemtype); $todel = array_merge($todel, array_keys($itemstodel)); } } if (!Session::haveRight(strtolower($itemtype), READNOTE)) { $todel[] = 90; } if (count($todel)) { foreach ($todel as $ID) { if (isset($options[$ID])) { unset($options[$ID]); } } } return $options; } /** * * Get an option number in the SEARCH_OPTION array * * @param string $itemtype Item type * @param string $field Name * * @return integer **/ static function getOptionNumber($itemtype, $field) { $table = $itemtype::getTable(); $opts = &self::getOptions($itemtype); foreach ($opts as $num => $opt) { if (is_array($opt) && isset($opt['table']) && ($opt['table'] == $table) && ($opt['field'] == $field)) { return $num; } } return 0; } /** * Get the SEARCH_OPTION array * * @param string $itemtype Item type * @param boolean $withplugins Get search options from plugins (true by default) * * @return array The reference to the array of search options for the given item type **/ static function &getOptions($itemtype, $withplugins = true) { global $CFG_GLPI; $item = null; if (!isset(self::$search[$itemtype])) { // standard type first switch ($itemtype) { case 'Internet' : self::$search[$itemtype]['common'] = __('Characteristics'); self::$search[$itemtype][1]['table'] = 'networkport_types'; self::$search[$itemtype][1]['field'] = 'name'; self::$search[$itemtype][1]['name'] = __('Name'); self::$search[$itemtype][1]['datatype'] = 'itemlink'; self::$search[$itemtype][1]['searchtype'] = 'contains'; self::$search[$itemtype][2]['table'] = 'networkport_types'; self::$search[$itemtype][2]['field'] = 'id'; self::$search[$itemtype][2]['name'] = __('ID'); self::$search[$itemtype][2]['searchtype'] = 'contains'; self::$search[$itemtype][31]['table'] = 'glpi_states'; self::$search[$itemtype][31]['field'] = 'completename'; self::$search[$itemtype][31]['name'] = __('Status'); self::$search[$itemtype] += NetworkPort::getSearchOptionsToAdd('networkport_types'); break; case 'AllAssets' : self::$search[$itemtype]['common'] = __('Characteristics'); self::$search[$itemtype][1]['table'] = 'asset_types'; self::$search[$itemtype][1]['field'] = 'name'; self::$search[$itemtype][1]['name'] = __('Name'); self::$search[$itemtype][1]['datatype'] = 'itemlink'; self::$search[$itemtype][1]['searchtype'] = 'contains'; self::$search[$itemtype][2]['table'] = 'asset_types'; self::$search[$itemtype][2]['field'] = 'id'; self::$search[$itemtype][2]['name'] = __('ID'); self::$search[$itemtype][2]['searchtype'] = 'contains'; self::$search[$itemtype][31]['table'] = 'glpi_states'; self::$search[$itemtype][31]['field'] = 'completename'; self::$search[$itemtype][31]['name'] = __('Status'); self::$search[$itemtype] += Location::getSearchOptionsToAdd(); self::$search[$itemtype][5]['table'] = 'asset_types'; self::$search[$itemtype][5]['field'] = 'serial'; self::$search[$itemtype][5]['name'] = __('Serial number'); self::$search[$itemtype][6]['table'] = 'asset_types'; self::$search[$itemtype][6]['field'] = 'otherserial'; self::$search[$itemtype][6]['name'] = __('Inventory number'); self::$search[$itemtype][16]['table'] = 'asset_types'; self::$search[$itemtype][16]['field'] = 'comment'; self::$search[$itemtype][16]['name'] = __('Comments'); self::$search[$itemtype][16]['datatype'] = 'text'; self::$search[$itemtype][70]['table'] = 'glpi_users'; self::$search[$itemtype][70]['field'] = 'name'; self::$search[$itemtype][70]['name'] = User::getTypeName(1); self::$search[$itemtype][7]['table'] = 'asset_types'; self::$search[$itemtype][7]['field'] = 'contact'; self::$search[$itemtype][7]['name'] = __('Alternate username'); self::$search[$itemtype][7]['datatype'] = 'string'; self::$search[$itemtype][8]['table'] = 'asset_types'; self::$search[$itemtype][8]['field'] = 'contact_num'; self::$search[$itemtype][8]['name'] = __('Alternate username number'); self::$search[$itemtype][8]['datatype'] = 'string'; self::$search[$itemtype][71]['table'] = 'glpi_groups'; self::$search[$itemtype][71]['field'] = 'completename'; self::$search[$itemtype][71]['name'] = Group::getTypeName(1); self::$search[$itemtype][19]['table'] = 'asset_types'; self::$search[$itemtype][19]['field'] = 'date_mod'; self::$search[$itemtype][19]['name'] = __('Last update'); self::$search[$itemtype][19]['datatype'] = 'datetime'; self::$search[$itemtype][19]['massiveaction'] = false; self::$search[$itemtype][23]['table'] = 'glpi_manufacturers'; self::$search[$itemtype][23]['field'] = 'name'; self::$search[$itemtype][23]['name'] = Manufacturer::getTypeName(1); self::$search[$itemtype][24]['table'] = 'glpi_users'; self::$search[$itemtype][24]['field'] = 'name'; self::$search[$itemtype][24]['linkfield'] = 'users_id_tech'; self::$search[$itemtype][24]['name'] = __('Technician in charge of the hardware'); self::$search[$itemtype][24]['condition'] = ['is_assign' => 1]; self::$search[$itemtype][49]['table'] = 'glpi_groups'; self::$search[$itemtype][49]['field'] = 'completename'; self::$search[$itemtype][49]['linkfield'] = 'groups_id_tech'; self::$search[$itemtype][49]['name'] = __('Group in charge of the hardware'); self::$search[$itemtype][49]['condition'] = ['is_assign' => 1]; self::$search[$itemtype][49]['datatype'] = 'dropdown'; self::$search[$itemtype][80]['table'] = 'glpi_entities'; self::$search[$itemtype][80]['field'] = 'completename'; self::$search[$itemtype][80]['name'] = Entity::getTypeName(1); break; default : if ($item = getItemForItemtype($itemtype)) { self::$search[$itemtype] = $item->searchOptions(); } break; } if (Session::getLoginUserID() && in_array($itemtype, $CFG_GLPI["ticket_types"])) { self::$search[$itemtype]['tracking'] = __('Assistance'); self::$search[$itemtype][60]['table'] = 'glpi_tickets'; self::$search[$itemtype][60]['field'] = 'id'; self::$search[$itemtype][60]['datatype'] = 'count'; self::$search[$itemtype][60]['name'] = _x('quantity', 'Number of tickets'); self::$search[$itemtype][60]['forcegroupby'] = true; self::$search[$itemtype][60]['usehaving'] = true; self::$search[$itemtype][60]['massiveaction'] = false; self::$search[$itemtype][60]['joinparams'] = ['beforejoin' => ['table' => 'glpi_items_tickets', 'joinparams' => ['jointype' => 'itemtype_item']], 'condition' => getEntitiesRestrictRequest('AND', 'NEWTABLE')]; self::$search[$itemtype][140]['table'] = 'glpi_problems'; self::$search[$itemtype][140]['field'] = 'id'; self::$search[$itemtype][140]['datatype'] = 'count'; self::$search[$itemtype][140]['name'] = _x('quantity', 'Number of problems'); self::$search[$itemtype][140]['forcegroupby'] = true; self::$search[$itemtype][140]['usehaving'] = true; self::$search[$itemtype][140]['massiveaction'] = false; self::$search[$itemtype][140]['joinparams'] = ['beforejoin' => ['table' => 'glpi_items_problems', 'joinparams' => ['jointype' => 'itemtype_item']], 'condition' => getEntitiesRestrictRequest('AND', 'NEWTABLE')]; } if (in_array($itemtype, $CFG_GLPI["networkport_types"]) || ($itemtype == 'AllAssets')) { self::$search[$itemtype] += NetworkPort::getSearchOptionsToAdd($itemtype); } if (in_array($itemtype, $CFG_GLPI["contract_types"]) || ($itemtype == 'AllAssets')) { self::$search[$itemtype] += Contract::getSearchOptionsToAdd(); } if (Document::canApplyOn($itemtype) || ($itemtype == 'AllAssets')) { self::$search[$itemtype] += Document::getSearchOptionsToAdd(); } if (Infocom::canApplyOn($itemtype) || ($itemtype == 'AllAssets')) { self::$search[$itemtype] += Infocom::getSearchOptionsToAdd($itemtype); } if (in_array($itemtype, $CFG_GLPI["domain_types"]) || ($itemtype == 'AllAssets')) { self::$search[$itemtype] += Domain::getSearchOptionsToAdd($itemtype); } if (in_array($itemtype, $CFG_GLPI["link_types"])) { self::$search[$itemtype]['link'] = _n('External link', 'External links', Session::getPluralNumber()); self::$search[$itemtype] += Link::getSearchOptionsToAdd($itemtype); } if ($withplugins) { // Search options added by plugins $plugsearch = Plugin::getAddSearchOptions($itemtype); $plugsearch = $plugsearch + Plugin::getAddSearchOptionsNew($itemtype); if (count($plugsearch)) { self::$search[$itemtype] += ['plugins' => _n('Plugin', 'Plugins', Session::getPluralNumber())]; self::$search[$itemtype] += $plugsearch; } } // Complete linkfield if not define if (is_null($item)) { // Special union type $itemtable = $CFG_GLPI['union_search_type'][$itemtype]; } else { if ($item = getItemForItemtype($itemtype)) { $itemtable = $item->getTable(); } } foreach (self::$search[$itemtype] as $key => $val) { if (!is_array($val) || count($val) == 1) { // skip sub-menu continue; } // Compatibility before 0.80 : Force massive action to false if linkfield is empty : if (isset($val['linkfield']) && empty($val['linkfield'])) { self::$search[$itemtype][$key]['massiveaction'] = false; } // Set default linkfield if (!isset($val['linkfield']) || empty($val['linkfield'])) { if ((strcmp($itemtable, $val['table']) == 0) && (!isset($val['joinparams']) || (count($val['joinparams']) == 0))) { self::$search[$itemtype][$key]['linkfield'] = $val['field']; } else { self::$search[$itemtype][$key]['linkfield'] = getForeignKeyFieldForTable($val['table']); } } // Add default joinparams if (!isset($val['joinparams'])) { self::$search[$itemtype][$key]['joinparams'] = []; } } } return self::$search[$itemtype]; } /** * Is the search item related to infocoms * * @param string $itemtype Item type * @param integer $searchID ID of the element in $SEARCHOPTION * * @return boolean **/ static function isInfocomOption($itemtype, $searchID) { if (!Infocom::canApplyOn($itemtype)) { return false; } $infocom_options = Infocom::rawSearchOptionsToAdd($itemtype); $found_infocoms = array_filter($infocom_options, function($option) use ($searchID) { return isset($option['id']) && $searchID == $option['id']; }); return (count($found_infocoms) > 0); } /** * @param string $itemtype * @param integer $field_num **/ static function getActionsFor($itemtype, $field_num) { $searchopt = &self::getOptions($itemtype); $actions = [ 'contains' => __('contains'), 'notcontains' => __('not contains'), 'searchopt' => [] ]; if (isset($searchopt[$field_num]) && isset($searchopt[$field_num]['table'])) { $actions['searchopt'] = $searchopt[$field_num]; // Force search type if (isset($actions['searchopt']['searchtype'])) { // Reset search option $actions = []; $actions['searchopt'] = $searchopt[$field_num]; if (!is_array($actions['searchopt']['searchtype'])) { $actions['searchopt']['searchtype'] = [$actions['searchopt']['searchtype']]; } foreach ($actions['searchopt']['searchtype'] as $searchtype) { switch ($searchtype) { case "equals" : $actions['equals'] = __('is'); break; case "notequals" : $actions['notequals'] = __('is not'); break; case "contains" : $actions['contains'] = __('contains'); $actions['notcontains'] = __('not contains'); break; case "notcontains" : $actions['notcontains'] = __('not contains'); break; case "under" : $actions['under'] = __('under'); break; case "notunder" : $actions['notunder'] = __('not under'); break; case "lessthan" : $actions['lessthan'] = __('before'); break; case "morethan" : $actions['morethan'] = __('after'); break; } } return $actions; } if (isset($searchopt[$field_num]['datatype'])) { switch ($searchopt[$field_num]['datatype']) { case 'count' : case 'number' : $opt = [ 'contains' => __('contains'), 'notcontains' => __('not contains'), 'equals' => __('is'), 'notequals' => __('is not'), 'searchopt' => $searchopt[$field_num] ]; // No is / isnot if no limits defined if (!isset($searchopt[$field_num]['min']) && !isset($searchopt[$field_num]['max'])) { unset($opt['equals']); unset($opt['notequals']); // https://github.com/glpi-project/glpi/issues/6917 // change filter wording for numeric values to be more // obvious if the number dropdown will not be used $opt['contains'] = __('is'); $opt['notcontains'] = __('is not'); } return $opt; case 'bool' : return [ 'equals' => __('is'), 'notequals' => __('is not'), 'contains' => __('contains'), 'notcontains' => __('not contains'), 'searchopt' => $searchopt[$field_num] ]; case 'right' : return ['equals' => __('is'), 'notequals' => __('is not'), 'searchopt' => $searchopt[$field_num]]; case 'itemtypename' : return ['equals' => __('is'), 'notequals' => __('is not'), 'searchopt' => $searchopt[$field_num]]; case 'date' : case 'datetime' : case 'date_delay' : return [ 'equals' => __('is'), 'notequals' => __('is not'), 'lessthan' => __('before'), 'morethan' => __('after'), 'contains' => __('contains'), 'notcontains' => __('not contains'), 'searchopt' => $searchopt[$field_num] ]; } } // switch ($searchopt[$field_num]['table']) { // case 'glpi_users_validation' : // return array('equals' => __('is'), // 'notequals' => __('is not'), // 'searchopt' => $searchopt[$field_num]); // } switch ($searchopt[$field_num]['field']) { case 'id' : return ['equals' => __('is'), 'notequals' => __('is not'), 'searchopt' => $searchopt[$field_num]]; case 'name' : case 'completename' : $actions = [ 'contains' => __('contains'), 'notcontains' => __('not contains'), 'equals' => __('is'), 'notequals' => __('is not'), 'searchopt' => $searchopt[$field_num] ]; // Specific case of TreeDropdown : add under $itemtype_linked = getItemTypeForTable($searchopt[$field_num]['table']); if ($itemlinked = getItemForItemtype($itemtype_linked)) { if ($itemlinked instanceof CommonTreeDropdown) { $actions['under'] = __('under'); $actions['notunder'] = __('not under'); } return $actions; } } } return $actions; } /** * Print generic Header Column * * @param integer $type Display type (0=HTML, 1=Sylk, 2=PDF, 3=CSV) * @param string $value Value to display * @param integer &$num Column number * @param string $linkto Link display element (HTML specific) (default '') * @param boolean|integer $issort Is the sort column ? (default 0) * @param string $order Order type ASC or DESC (defaut '') * @param string $options Options to add (default '') * * @return string HTML to display **/ static function showHeaderItem($type, $value, &$num, $linkto = "", $issort = 0, $order = "", $options = "") { $out = ""; switch ($type) { case self::PDF_OUTPUT_LANDSCAPE : //pdf case self::PDF_OUTPUT_PORTRAIT : global $PDF_TABLE; $PDF_TABLE .= ""; $PDF_TABLE .= Html::clean($value); $PDF_TABLE .= "\n"; break; case self::SYLK_OUTPUT : //sylk global $SYLK_HEADER,$SYLK_SIZE; $SYLK_HEADER[$num] = self::sylk_clean($value); $SYLK_SIZE[$num] = Toolbox::strlen($SYLK_HEADER[$num]); break; case self::CSV_OUTPUT : //CSV $out = "\"".self::csv_clean($value)."\"".$_SESSION["glpicsv_delimiter"]; break; default : $class = ""; if ($issort) { $class = "order_$order"; } $out = ""; if (!empty($linkto)) { $out .= ""; } $out .= $value; if (!empty($linkto)) { $out .= ""; } $out .= "\n"; } $num++; return $out; } /** * Print generic normal Item Cell * * @param integer $type Display type (0=HTML, 1=Sylk, 2=PDF, 3=CSV) * @param string $value Value to display * @param integer &$num Column number * @param integer $row Row number * @param string $extraparam Extra parameters for display (default '') * * @return string HTML to display **/ static function showItem($type, $value, &$num, $row, $extraparam = '') { $out = ""; switch ($type) { case self::PDF_OUTPUT_LANDSCAPE : //pdf case self::PDF_OUTPUT_PORTRAIT : global $PDF_TABLE; $value = preg_replace('/'.self::LBBR.'/', '
    ', $value); $value = preg_replace('/'.self::LBHR.'/', '
    ', $value); $PDF_TABLE .= ""; $PDF_TABLE .= Html::weblink_extract(Html::clean($value)); $PDF_TABLE .= "\n"; break; case self::SYLK_OUTPUT : //sylk global $SYLK_ARRAY,$SYLK_SIZE; $value = Html::weblink_extract(Html::clean($value)); $value = preg_replace('/'.self::LBBR.'/', '
    ', $value); $value = preg_replace('/'.self::LBHR.'/', '
    ', $value); $SYLK_ARRAY[$row][$num] = self::sylk_clean($value); $SYLK_SIZE[$num] = max($SYLK_SIZE[$num], Toolbox::strlen($SYLK_ARRAY[$row][$num])); break; case self::CSV_OUTPUT : //csv $value = preg_replace('/'.self::LBBR.'/', '
    ', $value); $value = preg_replace('/'.self::LBHR.'/', '
    ', $value); $value = Html::weblink_extract(Html::clean($value)); $out = "\"".self::csv_clean($value)."\"".$_SESSION["glpicsv_delimiter"]; break; default : global $CFG_GLPI; $out = ""; if (!preg_match('/'.self::LBHR.'/', $value)) { $values = preg_split('/'.self::LBBR.'/i', $value); $line_delimiter = '
    '; } else { $values = preg_split('/'.self::LBHR.'/i', $value); $line_delimiter = '
    '; } if (count($values) > 1 && Toolbox::strlen($value) > $CFG_GLPI['cut']) { $value = ''; foreach ($values as $v) { $value .= $v.$line_delimiter; } $value = preg_replace('/'.self::LBBR.'/', '
    ', $value); $value = preg_replace('/'.self::LBHR.'/', '
    ', $value); $value = '
    '.$value.'
    '; $valTip = " ".Html::showToolTip( $value, [ 'awesome-class' => 'fa-comments', 'display' => false, 'autoclose' => false, 'onclick' => true ] ); $out .= $values[0] . $valTip; } else { $value = preg_replace('/'.self::LBBR.'/', '
    ', $value); $value = preg_replace('/'.self::LBHR.'/', '
    ', $value); $out .= $value; } $out .= "\n"; } $num++; return $out; } /** * Print generic error * * @param integer $type Display type (0=HTML, 1=Sylk, 2=PDF, 3=CSV) * @param string $message Message to display, if empty "no item found" will be displayed * * @return string HTML to display **/ static function showError($type, $message = "") { if (strlen($message) == 0) { $message = __('No item found'); } $out = ""; switch ($type) { case self::PDF_OUTPUT_LANDSCAPE : //pdf case self::PDF_OUTPUT_PORTRAIT : case self::SYLK_OUTPUT : //sylk case self::CSV_OUTPUT : //csv break; default : $out = "
    $message
    \n"; } return $out; } /** * Print generic footer * * @param integer $type Display type (0=HTML, 1=Sylk, 2=PDF, 3=CSV) * @param string $title title of file : used for PDF (default '') * @param integer $count Total number of results * * @return string HTML to display **/ static function showFooter($type, $title = "", $count = null) { $out = ""; switch ($type) { case self::PDF_OUTPUT_LANDSCAPE : //pdf case self::PDF_OUTPUT_PORTRAIT : global $PDF_TABLE; if ($type == self::PDF_OUTPUT_LANDSCAPE) { $pdf = new GLPIPDF('L', 'mm', 'A4', true, 'UTF-8', false); } else { $pdf = new GLPIPDF('P', 'mm', 'A4', true, 'UTF-8', false); } if ($count !== null) { $pdf->setTotalCount($count); } $pdf->SetCreator('GLPI'); $pdf->SetAuthor('GLPI'); $pdf->SetTitle($title); $pdf->SetHeaderData('', '', $title, ''); $font = 'helvetica'; //$subsetting = true; $fontsize = 8; if (isset($_SESSION['glpipdffont']) && $_SESSION['glpipdffont']) { $font = $_SESSION['glpipdffont']; //$subsetting = false; } $pdf->setHeaderFont([$font, 'B', $fontsize]); $pdf->setFooterFont([$font, 'B', $fontsize]); //set margins $pdf->SetMargins(10, 15, 10); $pdf->SetHeaderMargin(10); $pdf->SetFooterMargin(10); //set auto page breaks $pdf->SetAutoPageBreak(true, 15); // For standard language //$pdf->setFontSubsetting($subsetting); // set font $pdf->SetFont($font, '', $fontsize); $pdf->AddPage(); $PDF_TABLE .= ''; $pdf->writeHTML($PDF_TABLE, true, false, true, false, ''); $pdf->Output('glpi.pdf', 'I'); break; case self::SYLK_OUTPUT : //sylk global $SYLK_HEADER,$SYLK_ARRAY,$SYLK_SIZE; // largeurs des colonnes foreach ($SYLK_SIZE as $num => $val) { $out .= "F;W".$num." ".$num." ".min(50, $val)."\n"; } $out .= "\n"; // Header foreach ($SYLK_HEADER as $num => $val) { $out .= "F;SDM4;FG0C;".($num == 1 ? "Y1;" : "")."X$num\n"; $out .= "C;N;K\"$val\"\n"; $out .= "\n"; } // Datas foreach ($SYLK_ARRAY as $row => $tab) { foreach ($tab as $num => $val) { $out .= "F;P3;FG0L;".($num == 1 ? "Y".$row.";" : "")."X$num\n"; $out .= "C;N;K\"$val\"\n"; } } $out.= "E\n"; break; case self::CSV_OUTPUT : //csv break; default : $out = "\n"; } return $out; } /** * Print generic footer * * @param integer $type Display type (0=HTML, 1=Sylk, 2=PDF, 3=CSV) * @param integer $rows Number of rows * @param integer $cols Number of columns * @param boolean|integer $fixed Used tab_cadre_fixe table for HTML export ? (default 0) * * @return string HTML to display **/ static function showHeader($type, $rows, $cols, $fixed = 0) { $out = ""; switch ($type) { case self::PDF_OUTPUT_LANDSCAPE : //pdf case self::PDF_OUTPUT_PORTRAIT : global $PDF_TABLE; $PDF_TABLE = ""; break; case self::SYLK_OUTPUT : // Sylk global $SYLK_ARRAY, $SYLK_HEADER, $SYLK_SIZE; $SYLK_ARRAY = []; $SYLK_HEADER = []; $SYLK_SIZE = []; // entetes HTTP header("Expires: Mon, 26 Nov 1962 00:00:00 GMT"); header('Pragma: private'); /// IE BUG + SSL header('Cache-control: private, must-revalidate'); /// IE BUG + SSL header("Content-disposition: filename=glpi.slk"); header('Content-type: application/octetstream'); // entete du fichier echo "ID;PGLPI_EXPORT\n"; // ID;Pappli echo "\n"; // formats echo "P;PGeneral\n"; echo "P;P#,##0.00\n"; // P;Pformat_1 (reels) echo "P;P#,##0\n"; // P;Pformat_2 (entiers) echo "P;P@\n"; // P;Pformat_3 (textes) echo "\n"; // polices echo "P;EArial;M200\n"; echo "P;EArial;M200\n"; echo "P;EArial;M200\n"; echo "P;FArial;M200;SB\n"; echo "\n"; // nb lignes * nb colonnes echo "B;Y".$rows; echo ";X".$cols."\n"; // B;Yligmax;Xcolmax echo "\n"; break; case self::CSV_OUTPUT : // csv header("Expires: Mon, 26 Nov 1962 00:00:00 GMT"); header('Pragma: private'); /// IE BUG + SSL header('Cache-control: private, must-revalidate'); /// IE BUG + SSL header("Content-disposition: filename=glpi.csv"); header('Content-type: text/csv'); // zero width no break space (for excel) echo"\xEF\xBB\xBF"; break; default : if ($fixed) { $out = "
    \n"; } else { $out = "
    \n"; } } return $out; } /** * Print begin of header part * * @param integer $type Display type (0=HTML, 1=Sylk, 2=PDF, 3=CSV) * * @since 0.85 * * @return string HTML to display **/ static function showBeginHeader($type) { $out = ""; switch ($type) { case self::PDF_OUTPUT_LANDSCAPE : //pdf case self::PDF_OUTPUT_PORTRAIT : global $PDF_TABLE; $PDF_TABLE .= ""; break; case self::SYLK_OUTPUT : //sylk case self::CSV_OUTPUT : //csv break; default : $out = ""; } return $out; } /** * Print end of header part * * @param integer $type Display type (0=HTML, 1=Sylk, 2=PDF, 3=CSV) * * @since 0.85 * * @return string to display **/ static function showEndHeader($type) { $out = ""; switch ($type) { case self::PDF_OUTPUT_LANDSCAPE : //pdf case self::PDF_OUTPUT_PORTRAIT : global $PDF_TABLE; $PDF_TABLE .= ""; break; case self::SYLK_OUTPUT : //sylk case self::CSV_OUTPUT : //csv break; default : $out = ""; } return $out; } /** * Print generic new line * * @param integer $type Display type (0=HTML, 1=Sylk, 2=PDF, 3=CSV) * @param boolean $odd Is it a new odd line ? (false by default) * @param boolean $is_deleted Is it a deleted search ? (false by default) * * @return string HTML to display **/ static function showNewLine($type, $odd = false, $is_deleted = false) { $out = ""; switch ($type) { case self::PDF_OUTPUT_LANDSCAPE : //pdf case self::PDF_OUTPUT_PORTRAIT : global $PDF_TABLE; $style = ""; if ($odd) { $style = " style=\"background-color:#DDDDDD;\" "; } $PDF_TABLE .= ""; break; case self::SYLK_OUTPUT : //sylk case self::CSV_OUTPUT : //csv break; default : $class = " class='tab_bg_2".($is_deleted?'_2':'')."' "; if ($odd) { $class = " class='tab_bg_1".($is_deleted?'_2':'')."' "; } $out = ""; } return $out; } /** * Print generic end line * * @param integer $type Display type (0=HTML, 1=Sylk, 2=PDF, 3=CSV) * * @return string HTML to display **/ static function showEndLine($type) { $out = ""; switch ($type) { case self::PDF_OUTPUT_LANDSCAPE : //pdf case self::PDF_OUTPUT_PORTRAIT : global $PDF_TABLE; $PDF_TABLE.= ''; break; case self::SYLK_OUTPUT : //sylk break; case self::CSV_OUTPUT : //csv $out = "\n"; break; default : $out = ""; } return $out; } /** * @param array $joinparams */ static function computeComplexJoinID(array $joinparams) { $complexjoin = ''; if (isset($joinparams['condition'])) { if (is_array($joinparams['condition'])) { $complexjoin .= print_r($joinparams['condition'], true); } else { $complexjoin .= $joinparams['condition']; } } // For jointype == child if (isset($joinparams['jointype']) && ($joinparams['jointype'] == 'child') && isset($joinparams['linkfield'])) { $complexjoin .= $joinparams['linkfield']; } if (isset($joinparams['beforejoin'])) { if (isset($joinparams['beforejoin']['table'])) { $joinparams['beforejoin'] = [$joinparams['beforejoin']]; } foreach ($joinparams['beforejoin'] as $tab) { if (isset($tab['table'])) { $complexjoin .= $tab['table']; } if (isset($tab['joinparams']) && isset($tab['joinparams']['condition'])) { if (is_array($tab['joinparams']['condition'])) { $complexjoin .= print_r($tab['joinparams']['condition'], true); } else { $complexjoin .= $tab['joinparams']['condition']; } } } } if (!empty($complexjoin)) { $complexjoin = md5($complexjoin); } return $complexjoin; } /** * Clean display value for csv export * * @param string $value value * * @return string Clean value **/ static function csv_clean($value) { $value = str_replace("\"", "''", $value); $value = Html::clean($value, true, 2, false); $value = str_replace(">", ">", $value); $value = str_replace("<", "<", $value); return $value; } /** * Clean display value for sylk export * * @param string $value value * * @return string Clean value **/ static function sylk_clean($value) { $value = preg_replace('/\x0A/', ' ', $value); $value = preg_replace('/\x0D/', null, $value); $value = str_replace("\"", "''", $value); $value = Html::clean($value); $value = str_replace("\n", " | ", $value); $value = str_replace(">", ">", $value); $value = str_replace("<", "<", $value); return $value; } /** * Create SQL search condition * * @param string $field Nname (should be ` protected) * @param string $val Value to search * @param boolean $not Is a negative search ? (false by default) * @param string $link With previous criteria (default 'AND') * * @return search SQL string **/ static function makeTextCriteria ($field, $val, $not = false, $link = 'AND') { $sql = $field . self::makeTextSearch($val, $not); // mange empty field (string with length = 0) $sql_or = ""; if (strtolower($val) == "null") { $sql_or = "OR $field = ''"; } if (($not && ($val != 'NULL') && ($val != 'null') && ($val != '^$')) // Not something ||(!$not && ($val == '^$'))) { // Empty $sql = "($sql OR $field IS NULL)"; } return " $link ($sql $sql_or)"; } /** * Create SQL search value * * @since 9.4 * * @param string $val value to search * * @return string|null **/ static function makeTextSearchValue($val) { // Unclean to permit < and > search $val = Toolbox::unclean_cross_side_scripting_deep($val); // escape _ char used as wildcard in mysql likes $val = str_replace('_', '\\_', $val); if (($val == 'NULL') || ($val == 'null')) { return null; } $search = ''; preg_match('/^(\^?)([^\^\$]*)(\$?)$/', $val, $matches); if (isset($matches[2]) && strlen(trim($matches[2])) > 0) { $search = ($matches[1] != '^' ? '%' : '') . trim($matches[2]) . ($matches[3] != '$' ? '%' : ''); } else if (isset($matches[1]) && strlen(trim($matches[1])) == 1 && (!isset($matches[3]) || empty($matches[3]))) { // this case is for search with only ^, so mean the field is not empty / not null $search = '%'; } return $search; } /** * Create SQL search condition * * @param string $val Value to search * @param boolean $not Is a negative search ? (false by default) * * @return string Search string **/ static function makeTextSearch($val, $not = false) { $NOT = ""; if ($not) { $NOT = "NOT"; } $val = self::makeTextSearchValue($val); if ($val == null) { $SEARCH = " IS $NOT NULL "; } else { $SEARCH = " $NOT LIKE '$val' "; } return $SEARCH; } /** * @since 0.84 * * @param string $pattern * @param string $subject **/ static function explodeWithID($pattern, $subject) { $tab = explode($pattern, $subject); if (isset($tab[1]) && !is_numeric($tab[1])) { // Report $ to tab[0] if (preg_match('/^(\\$*)(.*)/', $tab[1], $matchs)) { if (isset($matchs[2]) && is_numeric($matchs[2])) { $tab[1] = $matchs[2]; $tab[0] .= $matchs[1]; } } } // Manage NULL value if ($tab[0] == self::NULLVALUE) { $tab[0] = null; } return $tab; } /** * Add join for dropdown translations * * @param string $alias Alias for translation table * @param string $table Table to join on * @param string $itemtype Item type * @param string $field Field name * * @return string */ public static function joinDropdownTranslations($alias, $table, $itemtype, $field) { return "LEFT JOIN `glpi_dropdowntranslations` AS `$alias` ON (`$alias`.`itemtype` = '$itemtype' AND `$alias`.`items_id` = `$table`.`id` AND `$alias`.`language` = '". $_SESSION['glpilanguage']."' AND `$alias`.`field` = '$field')"; } /** * Get table name for item type * * @param string $itemtype * * @return string */ public static function getOrigTableName(string $itemtype): string { return (is_a($itemtype, CommonDBTM::class, true)) ? $itemtype::getTable() : getTableForItemType($itemtype); } }