static function constructSQL(array &$data)
{
global $CFG_GLPI;
if (!isset($data['itemtype'])) {
return false;
}
$data['sql']['count'] = array();
$data['sql']['search'] = '';
$searchopt =& self::getOptions($data['itemtype']);
$blacklist_tables = array();
if (isset($CFG_GLPI['union_search_type'][$data['itemtype']])) {
$itemtable = $CFG_GLPI['union_search_type'][$data['itemtype']];
$blacklist_tables[] = getTableForItemType($data['itemtype']);
} else {
$itemtable = getTableForItemType($data['itemtype']);
}
// hack for AllAssets
if (isset($CFG_GLPI['union_search_type'][$data['itemtype']])) {
$entity_restrict = true;
} else {
$entity_restrict = $data['item']->isEntityAssign();
}
// Construct the request
//// 1 - SELECT
// request currentuser for SQL supervision, not displayed
$SELECT = "SELECT '" . Toolbox::addslashes_deep($_SESSION['glpiname']) . "' AS currentuser,\n " . self::addDefaultSelect($data['itemtype']);
// Add select for all toview item
foreach ($data['toview'] as $key => $val) {
$SELECT .= self::addSelect($data['itemtype'], $val, $key, 0);
}
//// 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 = array();
// 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 $key => $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)) {
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` = '" . $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());
}
}
}
$WHERE = "";
$HAVING = "";
// Add search conditions
// If there is search items
if (count($data['search']['criteria'])) {
foreach ($data['search']['criteria'] as $key => $criteria) {
// if real search (strlen >0) and not all and view search
if (isset($criteria['value']) && strlen($criteria['value']) > 0) {
// common search
if (isset($criteria['field']) && $criteria['field'] != "all" && $criteria['field'] != "view") {
$LINK = " ";
$NOT = 0;
$tmplink = "";
if (isset($criteria['link'])) {
if (strstr($criteria['link'], "NOT")) {
$tmplink = " " . str_replace(" NOT", "", $criteria['link']);
$NOT = 1;
} else {
$tmplink = " " . $criteria['link'];
}
} else {
$tmplink = " AND ";
}
if (isset($searchopt[$criteria['field']]["usehaving"])) {
// Manage Link if not first item
if (!empty($HAVING)) {
$LINK = $tmplink;
}
// Find key
$item_num = array_search($criteria['field'], $data['tocompute']);
$HAVING .= self::addHaving($LINK, $NOT, $data['itemtype'], $criteria['field'], $criteria['searchtype'], $criteria['value'], 0, $item_num);
} else {
// Manage Link if not first item
if (!empty($WHERE)) {
$LINK = $tmplink;
}
$WHERE .= self::addWhere($LINK, $NOT, $data['itemtype'], $criteria['field'], $criteria['searchtype'], $criteria['value']);
}
} else {
// view and all search
$LINK = " OR ";
$NOT = 0;
$globallink = " AND ";
if (isset($criteria['link'])) {
switch ($criteria['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($WHERE)) {
$WHERE .= $globallink;
}
$WHERE .= " ( ";
$first2 = true;
$items = array();
if (isset($criteria['field']) && $criteria['field'] == "all") {
$items = $searchopt;
} else {
// toview case : populate toview
foreach ($data['toview'] as $key2 => $val2) {
$items[$val2] = $searchopt[$val2];
}
}
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 (!isset($val2["usehaving"])) {
$tmplink = $LINK;
if ($first2) {
$tmplink = " ";
$first2 = false;
}
$WHERE .= self::addWhere($tmplink, $NOT, $data['itemtype'], $key2, $criteria['searchtype'], $criteria['value']);
}
}
}
$WHERE .= " ) ";
}
}
}
}
//// 4 - ORDER
$ORDER = " ORDER BY `id` ";
foreach ($data['tocompute'] as $key => $val) {
if ($data['search']['sort'] == $val) {
$ORDER = self::addOrderBy($data['itemtype'], $data['search']['sort'], $data['search']['order'], $key);
}
}
//// 5 - META SEARCH
// Preprocessing
if (count($data['search']['metacriteria'])) {
// Already link meta table in order not to linked a table several times
$already_link_tables2 = array();
$metanum = count($data['toview']) - 1;
foreach ($data['search']['metacriteria'] as $key => $metacriteria) {
if (isset($metacriteria['itemtype']) && !empty($metacriteria['itemtype']) && isset($metacriteria['value']) && strlen($metacriteria['value']) > 0) {
$metaopt =& self::getOptions($metacriteria['itemtype']);
$sopt = $metaopt[$metacriteria['field']];
$metanum++;
// a - SELECT
$SELECT .= self::addSelect($metacriteria['itemtype'], $metacriteria['field'], $metanum, 1, $metacriteria['itemtype']);
// b - ADD LEFT JOIN
// Link reference tables
if (!in_array(getTableForItemType($metacriteria['itemtype']), $already_link_tables2) && !in_array(getTableForItemType($metacriteria['itemtype']), $already_link_tables)) {
$FROM .= self::addMetaLeftJoin($data['itemtype'], $metacriteria['itemtype'], $already_link_tables2, $metacriteria['value'] == "NULL" || strstr($metacriteria['link'], "NOT"), $sopt["joinparams"]);
}
// Link items tables
if (!in_array($sopt["table"] . "_" . $metacriteria['itemtype'], $already_link_tables2)) {
$FROM .= self::addLeftJoin($metacriteria['itemtype'], getTableForItemType($metacriteria['itemtype']), $already_link_tables2, $sopt["table"], $sopt["linkfield"], 1, $metacriteria['itemtype'], $sopt["joinparams"], $sopt["field"]);
}
// Where
$LINK = "";
// For AND NOT statement need to take into account all the group by items
if (strstr($metacriteria['link'], "AND NOT") || isset($sopt["usehaving"])) {
$NOT = 0;
if (strstr($metacriteria['link'], "NOT")) {
$tmplink = " " . str_replace(" NOT", "", $metacriteria['link']);
$NOT = 1;
} else {
$tmplink = " " . $metacriteria['link'];
}
if (!empty($HAVING)) {
$LINK = $tmplink;
}
$HAVING .= self::addHaving($LINK, $NOT, $metacriteria['itemtype'], $metacriteria['field'], $metacriteria['searchtype'], $metacriteria['value'], 1, $metanum);
} else {
// Meta Where Search
$LINK = " ";
$NOT = 0;
// Manage Link if not first item
if (isset($metacriteria['link']) && strstr($metacriteria['link'], "NOT")) {
$tmplink = " " . str_replace(" NOT", "", $metacriteria['link']);
$NOT = 1;
} else {
if (isset($metacriteria['link'])) {
$tmplink = " " . $metacriteria['link'];
} else {
$tmplink = " AND ";
}
}
if (!empty($WHERE)) {
$LINK = $tmplink;
}
$WHERE .= self::addWhere($LINK, $NOT, $metacriteria['itemtype'], $metacriteria['field'], $metacriteria['searchtype'], $metacriteria['value'], 1);
}
}
}
}
//// 6 - Add item ID
// Add ID to the select
if (!empty($itemtable)) {
$SELECT .= "`{$itemtable}`.`id` AS id ";
}
//// 7 - Manage GROUP BY
$GROUPBY = "";
// Meta Search / Search All / Count tickets
if (count($data['search']['metacriteria']) || !empty($HAVING) || $data['search']['all_search']) {
$GROUPBY = " GROUP BY `{$itemtable}`.`id`";
}
if (empty($GROUPBY)) {
foreach ($data['toview'] as $key2 => $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 " . $data['search']['start'] . ", " . $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},\n '" . Toolbox::addslashes_deep($_SESSION['glpiname']) . "' AS currentuser\n 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;
$numrows = 0;
foreach ($CFG_GLPI[$CFG_GLPI["union_search_type"][$data['itemtype']]] as $ctype) {
$ctable = getTableForItemType($ctype);
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 = getTableForItemType($data['itemtype']);
if ($data['item'] && $data['item']->maybeDeleted()) {
$tmpquery = str_replace("`" . $CFG_GLPI["union_search_type"][$data['itemtype']] . "`.\n `is_deleted`", "`{$reftable}`.`is_deleted`", $tmpquery);
}
$replace = "FROM `{$reftable}`\n INNER JOIN `{$ctable}`\n ON (`{$reftable}`.`items_id` =`{$ctable}`.`id`\n 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 = getTableForItemType($ctype);
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;
$tmpquery = str_replace($CFG_GLPI["union_search_type"][$data['itemtype']], $ctable, $tmpquery);
$tmpquery = str_replace($data['itemtype'], $ctype, $tmpquery);
} else {
// Ref table case
$reftable = getTableForItemType($data['itemtype']);
$tmpquery = $SELECT . ", '{$ctype}' AS TYPE,\n `{$reftable}`.`id` AS refID, " . "\n `{$ctable}`.`entities_id` AS ENTITY " . $FROM . $WHERE;
if ($data['item']->maybeDeleted()) {
$tmpquery = str_replace("`" . $CFG_GLPI["union_search_type"][$data['itemtype']] . "`.\n `is_deleted`", "`{$reftable}`.`is_deleted`", $tmpquery);
}
$replace = "FROM `{$reftable}`" . "\n INNER JOIN `{$ctable}`" . "\n ON (`{$reftable}`.`items_id`=`{$ctable}`.`id`" . "\n 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);
}
$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;
}