search.class.php 318 KB
Newer Older
1
<?php
2 3 4
/**
 * ---------------------------------------------------------------------
 * GLPI - Gestionnaire Libre de Parc Informatique
5
 * Copyright (C) 2015-2018 Teclib' and contributors.
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
 *
 * http://glpi-project.org
 *
 * based on GLPI - Gestionnaire Libre de Parc Informatique
 * Copyright (C) 2003-2014 by the INDEPNET Development Team.
 *
 * ---------------------------------------------------------------------
 *
 * LICENSE
 *
 * This file is part of GLPI.
 *
 * GLPI is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * GLPI is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with GLPI. If not, see <http://www.gnu.org/licenses/>.
 * ---------------------------------------------------------------------
moyooo's avatar
moyooo committed
31
 */
yllen's avatar
CS  
yllen committed
32

moyooo's avatar
moyooo committed
33
if (!defined('GLPI_ROOT')) {
Stefan Weil's avatar
Stefan Weil committed
34
   die("Sorry. You can't access this file directly");
moyooo's avatar
moyooo committed
35 36
}

moyooo's avatar
moyooo committed
37 38 39 40 41
/**
 * Search Class
 *
 * Generic class for Search Engine
**/
moyooo's avatar
moyooo committed
42 43
class Search {

yllen's avatar
yllen committed
44 45 46 47 48 49 50 51 52
   // 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;
remi's avatar
remi committed
53

moyooo's avatar
moyooo committed
54 55
   const LBBR = '#LBBR#';
   const LBHR = '#LBHR#';
56

moyooo's avatar
moyooo committed
57 58
   const SHORTSEP = '$#$';
   const LONGSEP  = '$$##$$';
moyooo's avatar
moyooo committed
59 60

   const NULLVALUE = '__NULL__';
yllen's avatar
yllen committed
61

Johan Cwiklinski's avatar
Johan Cwiklinski committed
62
   private $output_type = self::HTML_OUTPUT;
63
   static $search = [];
64

Johan Cwiklinski's avatar
Johan Cwiklinski committed
65 66
   private $db;
   private $item;
Johan Cwiklinski's avatar
Johan Cwiklinski committed
67
   private $itemtype;
Johan Cwiklinski's avatar
Johan Cwiklinski committed
68 69
   private $raw_params;
   private $qry_params = [];
Johan Cwiklinski's avatar
Johan Cwiklinski committed
70 71
   private $current_page;
   private $sub_item = false;
Johan Cwiklinski's avatar
Johan Cwiklinski committed
72 73 74 75 76 77 78 79 80 81

   /**
    * Constructor
    *
    * @param CommonDBTM|null $item   Item instance
    * @param array           $params Search parameters
    */
   public function __construct($item, array $params) {
      global $DB;
      $this->db = $DB;
Johan Cwiklinski's avatar
Johan Cwiklinski committed
82 83 84 85 86 87 88 89 90
      if ($item instanceof CommonDBTM) {
         $this->item = $item;
         $this->itemtype = $item->getType();
      } else {
         $this->itemtype = $item;
         if ($item !== 'AllAssets') {
            $this->item = new $item;
         }
      }
Johan Cwiklinski's avatar
Johan Cwiklinski committed
91 92 93
      $this->raw_params = $params;
   }

moyooo's avatar
moyooo committed
94
   /**
yllen's avatar
yllen committed
95 96
    * Display search engine for an type
    *
97
    * @param string  $itemtype Item type to manage
yllen's avatar
yllen committed
98
    *
99
    * @return void
yllen's avatar
yllen committed
100
   **/
Johan Cwiklinski's avatar
Johan Cwiklinski committed
101
   public static function show($itemtype) {
moyooo's avatar
moyooo committed
102
      $params = self::manageParams($itemtype, $_GET);
Johan Cwiklinski's avatar
Johan Cwiklinski committed
103 104
      $item = $itemtype == 'AllAssets' ? $itemtype : new $itemtype;
      $inst = new self($item, $params);
Alexandre Delaunay's avatar
Alexandre Delaunay committed
105
      echo "<div class='search_page'>";
Johan Cwiklinski's avatar
Johan Cwiklinski committed
106
      $inst->showGenericSearch($itemtype, $params);
107
      if ($params['as_map'] == 1) {
Johan Cwiklinski's avatar
Johan Cwiklinski committed
108
         $inst->showMap($itemtype, $params);
109
      } else {
Johan Cwiklinski's avatar
Johan Cwiklinski committed
110
         $inst->showList($itemtype, $params);
111
      }
Alexandre Delaunay's avatar
Alexandre Delaunay committed
112
      echo "</div>";
moyooo's avatar
moyooo committed
113 114
   }

moyooo's avatar
moyooo committed
115 116 117
   /**
    * Display result table for search engine for an type
    *
Johan Cwiklinski's avatar
Johan Cwiklinski committed
118
    * @param string $itemtype item type to manage
Johan Cwiklinski's avatar
Johan Cwiklinski committed
119
    * @param array  $params   search params passed to prepareDatasForSearch function
Johan Cwiklinski's avatar
Johan Cwiklinski committed
120
    * @param array  $data     data if already processed
moyooo's avatar
moyooo committed
121
    *
Johan Cwiklinski's avatar
Johan Cwiklinski committed
122 123
    * @return void
    *
Johan Cwiklinski's avatar
Johan Cwiklinski committed
124 125
    * @since 10.0.0 Method is no longer static
    * @since 10.0.0 Added $data parameter
moyooo's avatar
moyooo committed
126
   **/
Johan Cwiklinski's avatar
Johan Cwiklinski committed
127 128 129 130 131 132 133
   public function showList($itemtype, $params, $data = []) {
      if (empty($data)) {
         $data = $this->prepareDataForSearch($itemtype, $params);
         $this->constructSQL($data);
         $this->constructData($data);
      }
      $this->displayData($data);
moyooo's avatar
moyooo committed
134
   }
moyooo's avatar
moyooo committed
135

136 137 138 139
   /**
    * Display result table for search engine for an type as a map
    *
    * @param string $itemtype item type to manage
Johan Cwiklinski's avatar
Johan Cwiklinski committed
140 141
    * @param array  $params   search params passed to prepareDataForSearch function
    * @param array  $data     data if already processed
142 143
    *
    * @return void
Johan Cwiklinski's avatar
Johan Cwiklinski committed
144
    *
Johan Cwiklinski's avatar
Johan Cwiklinski committed
145 146
    * @since 10.0.0 Method is no longer static
    * @since 10.0.0 Added $data parameter
147
   **/
Johan Cwiklinski's avatar
Johan Cwiklinski committed
148
   public function showMap($itemtype, $params, $data = []) {
149 150
      global $CFG_GLPI;

Johan Cwiklinski's avatar
Johan Cwiklinski committed
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
      if (empty($data)) {
         $params['criteria'][] = [
            'link'         => 'AND NOT',
            'field'        => ($itemtype == 'Location') ? 21 : 998,
            'searchtype'   => 'contains',
            'value'        => 'NULL'
         ];
         $params['criteria'][] = [
            'link'         => 'AND NOT',
            'field'        => ($itemtype == 'Location') ? 20 : 999,
            'searchtype'   => 'contains',
            'value'        => 'NULL'
         ];
         $data = $this->prepareDataForSearch($itemtype, $params);
         $this->constructSQL($data);
         $this->constructData($data);
      }
      $this->displayData($data);
169

Johan Cwiklinski's avatar
Johan Cwiklinski committed
170
      //TODO: adapt for new system
171 172 173 174 175 176 177
      if ($data['data']['totalcount'] > 0) {
         $target = $data['search']['target'];
         $criteria = $data['search']['criteria'];
         array_pop($criteria);
         array_pop($criteria);
         $criteria[] = [
            'link'         => 'AND',
Johan Cwiklinski's avatar
Johan Cwiklinski committed
178
            'field'        => ($itemtype == 'Location') ? 1 : ($itemtype == 'Ticket') ? 83 : 3,
179 180 181 182 183
            'searchtype'   => 'equals',
            'value'        => 'CURLOCATION'
         ];
         $globallinkto = Toolbox::append_params(
            [
Johan Cwiklinski's avatar
Johan Cwiklinski committed
184 185
               'criteria'     => $criteria,
               'metacriteria' => $data['search']['metacriteria']
186 187 188 189 190 191 192 193 194 195 196
            ],
            '&amp;'
         );
         $parameters = "as_map=0&amp;sort=".$data['search']['sort']."&amp;order=".$data['search']['order'].'&amp;'.
                        $globallinkto;

         if (strpos($target, '?') == false) {
            $fulltarget = $target."?".$parameters;
         } else {
            $fulltarget = $target."&".$parameters;
         }
197
         $typename = class_exists($itemtype) ? $itemtype::getTypeName($data['data']['totalcount']) :
198
                        ($itemtype == 'AllAssets' ? __('assets') : $itemtype);
199 200 201 202 203 204 205 206

         echo "<div class='center'><p>".__('Search results for localized items only')."</p>";
         $js = "$(function() {
               var map = initMap($('#page'), 'map', 'full');
               _loadMap(map, '$itemtype');
            });

         var _loadMap = function(map_elt, itemtype) {
207
            L.AwesomeMarkers.Icon.prototype.options.prefix = 'far';
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
            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: '<div><span>' + n + '</span></div>', className: 'marker-cluster' + c, iconSize: new L.Point(40, 40) });
                  }
               });

               $.each(_points, function(index, point) {
                  var _title = '<strong>' + point.title + '</strong><br/><a href=\''+'$fulltarget'.replace(/CURLOCATION/, point.loc_id)+'\'>".sprintf(__('%1$s %2$s'), 'COUNT', $typename)."'.replace(/COUNT/, point.count)+'</a>';
                  if (point.types) {
                     $.each(point.types, function(tindex, type) {
                        _title += '<br/>".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');
319
                  this._div.innerHTML = _message + '<br/><span id=\'reload_data\'><i class=\'fa fa-sync\'></i> ".__s('Reload')."</span>';
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
                  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 "</div>";
      }
   }

moyooo's avatar
moyooo committed
339
   /**
Johan Cwiklinski's avatar
Johan Cwiklinski committed
340
    * Get data
yllen's avatar
CS  
yllen committed
341
    *
Johan Cwiklinski's avatar
Johan Cwiklinski committed
342
    * @param array|false $sub_item Are we looking for a sub item?
moyooo's avatar
moyooo committed
343
    *
Johan Cwiklinski's avatar
Johan Cwiklinski committed
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
    * @return array
    */
   public function getData($sub_item = false) {
      $this->sub_item = $sub_item;
      $itemtype = ($this->item instanceof CommonDBTM ? $this->item->getType() : 'AllAssets');
      $params = self::manageParams($itemtype, $this->raw_params);
      if ($params['as_map'] == 1) {
         $params['criteria'][] = [
            'link'         => 'AND NOT',
            'field'        => ($itemtype == 'Location') ? 21 : 998,
            'searchtype'   => 'contains',
            'value'        => 'NULL'
         ];
         $params['criteria'][] = [
            'link'         => 'AND NOT',
            'field'        => ($itemtype == 'Location') ? 20 : 999,
            'searchtype'   => 'contains',
            'value'        => 'NULL'
         ];
      }

      if ($this->current_page === null) {
         $this->current_page = 1;
      }
yllen's avatar
CS  
yllen committed
368

Johan Cwiklinski's avatar
Johan Cwiklinski committed
369 370
      $data = $this->prepareDataForSearch($itemtype, $params, $this->sub_item);
      $this->constructSQL($data, $this->sub_item);
Johan Cwiklinski's avatar
Johan Cwiklinski committed
371
      $this->constructData($data);
moyooo's avatar
moyooo committed
372

Johan Cwiklinski's avatar
Johan Cwiklinski committed
373
      if (!isset($data['data']['totalcount'])) {
374
         Toolbox::logError("Something went wrong during $itemtype search");
Johan Cwiklinski's avatar
Johan Cwiklinski committed
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
         return;
      }

      if ($params['as_map'] != 1) {
         //no need for pagination with map view
         $limit = $_SESSION['glpilist_limit'];
         $count = $data['data']['totalcount'];

         $this->pages = $count / $limit;
         if ($count > 0) {
            $last = ceil($count / $limit);
            $previous = $this->current_page - 1;
            if ($previous < 1) {
                $previous = false;
            }

            $next = $this->current_page +1;
            if ($next > $last) {
                $next = $last;
            }
         } else {
            $previous = $next = $first = $last = false;
         }
         $pagination = [
            'start'           => $data['search']['start'],
            'limit'           => $limit,
            'count'           => $count,
            'current_page'    => $this->current_page,
            'previous_page'   => $previous,
            'next_page'       => $next,
            'last_page'       => $last,
            'pages'           => []
         ];

         $idepart = $this->current_page - 2;
         if ($idepart< 1) {
            $idepart = 1;
         }

         $ifin = $this->current_page + 2;
         if ($ifin > $last) {
            $ifin = $last;
         }

         for ($i = $idepart; $i <= $ifin; $i++) {
            $page = [
               'value' => $i,
               'title' => preg_replace("(%i)", $i, __("Page %i"))
            ];
            if ($i == $this->current_page) {
               $page['current'] = true;
               $page['title'] = preg_replace(
                  "(%i)",
                  $i,
                  __("Current page (%i)")
               );
            }
            $pagination['pages'][] = $page;
         }
         $data['pagination'] = $pagination;
      }

moyooo's avatar
moyooo committed
437 438
      return $data;
   }
yllen's avatar
CS  
yllen committed
439

moyooo's avatar
moyooo committed
440
   /**
moyooo's avatar
moyooo committed
441
    * Prepare search criteria to be used for a search
yllen's avatar
yllen committed
442
    *
Anael Mobilia's avatar
Anael Mobilia committed
443
    * @since 0.85
yllen's avatar
CS  
yllen committed
444
    *
Johan Cwiklinski's avatar
Johan Cwiklinski committed
445 446 447 448
    * @param string  $itemtype item type
    * @param array   $params   array of parameters
    *                          may include sort, order, start, list_limit, deleted, criteria, metacriteria
    * @param boolean $sub_item Are we looking for a sub item?
yllen's avatar
yllen committed
449
    *
moyooo's avatar
moyooo committed
450
    * @return array prepare to be used for a search (include criterias and others needed informations)
Johan Cwiklinski's avatar
Johan Cwiklinski committed
451
    *
Johan Cwiklinski's avatar
Johan Cwiklinski committed
452
    * @since 10.0.0 Method has been renamed is no longer static, $forcedisplay has been removed
moyooo's avatar
moyooo committed
453
   **/
Johan Cwiklinski's avatar
Johan Cwiklinski committed
454
   public function prepareDataForSearch($itemtype, array $params, $sub_item = false) {
moyooo's avatar
moyooo committed
455
      global $CFG_GLPI;
yllen's avatar
CS  
yllen committed
456

moyooo's avatar
moyooo committed
457
      // Default values of parameters
458 459
      $p['criteria']            = [];
      $p['metacriteria']        = [];
yllen's avatar
CS  
yllen committed
460 461 462 463 464
      $p['sort']                = '1'; //
      $p['order']               = 'ASC';//
      $p['start']               = 0;//
      $p['is_deleted']          = 0;
      $p['export_all']          = 0;
465 466 467 468 469
      if (class_exists($itemtype)) {
         $p['target']       = $itemtype::getSearchURL();
      } else {
         $p['target']       = Toolbox::getItemTypeSearchURL($itemtype);
      }
yllen's avatar
CS  
yllen committed
470 471
      $p['display_type']        = self::HTML_OUTPUT;
      $p['list_limit']          = $_SESSION['glpilist_limit'];
472
      $p['massiveactionparams'] = [];
Johan Cwiklinski's avatar
Johan Cwiklinski committed
473
      $p['forcedisplay']        = [];
moyooo's avatar
moyooo committed
474

475
      foreach ($params as $key => $val) {
476 477
         switch ($key) {
            case 'order':
478
               if (in_array($val, ['ASC', 'DESC'])) {
479 480 481 482
                  $p[$key] = $val;
               }
               break;
            case 'sort':
Alexandre Delaunay's avatar
Alexandre Delaunay committed
483
               $p[$key] = intval($val);
484
               if ($p[$key] < 0) {
485 486 487 488 489 490 491 492 493 494 495 496
                  $p[$key] = 1;
               }
               break;
            case 'is_deleted':
               if ($val == 1) {
                  $p[$key] = '1';
               }
               break;
            default:
               $p[$key] = $val;
               break;
         }
moyooo's avatar
moyooo committed
497
      }
yllen's avatar
CS  
yllen committed
498

moyooo's avatar
moyooo committed
499 500 501 502 503 504 505 506
      // 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;
         }
      }

507
      if ($p['export_all']) {
yllen's avatar
yllen committed
508
         $p['start'] = 0;
moyooo's avatar
moyooo committed
509
      }
yllen's avatar
CS  
yllen committed
510

511
      $data             = [];
yllen's avatar
CS  
yllen committed
512
      $data['search']   = $p;
Johan Cwiklinski's avatar
Johan Cwiklinski committed
513 514 515 516
      $data['real_itemtype'] = $itemtype;
      if ($sub_item && $sub_item['sub_item'] instanceof CommonDBRelation && $sub_item['sub_item']->getType() == $itemtype) {
         $itemtype = 'AllAssets';
      }
moyooo's avatar
moyooo committed
517 518 519
      $data['itemtype'] = $itemtype;

      // Instanciate an object to access method
520
      $data['item'] = null;
moyooo's avatar
moyooo committed
521 522 523 524

      if ($itemtype != 'AllAssets') {
         $data['item'] = getItemForItemtype($itemtype);
      }
yllen's avatar
CS  
yllen committed
525 526 527

      $data['display_type'] = $data['search']['display_type'];

moyooo's avatar
moyooo committed
528 529
      if (!$CFG_GLPI['allow_search_all']) {
         foreach ($p['criteria'] as $val) {
tsmr's avatar
tsmr committed
530
            if (isset($val['field']) && $val['field'] == 'all') {
moyooo's avatar
moyooo committed
531
               Html::displayRightError();
532 533 534
            }
         }
      }
moyooo's avatar
moyooo committed
535 536
      if (!$CFG_GLPI['allow_search_view']) {
         foreach ($p['criteria'] as $val) {
tsmr's avatar
tsmr committed
537
            if (isset($val['field']) && $val['field'] == 'view') {
moyooo's avatar
moyooo committed
538
               Html::displayRightError();
539 540 541 542
            }
         }
      }

moyooo's avatar
moyooo committed
543
      /// Get the items to display
moyooo's avatar
moyooo committed
544
      // Add searched items
yllen's avatar
CS  
yllen committed
545

moyooo's avatar
moyooo committed
546
      $forcetoview = false;
Johan Cwiklinski's avatar
Johan Cwiklinski committed
547
      if (is_array($p['forcedisplay']) && count($p['forcedisplay'])) {
moyooo's avatar
moyooo committed
548 549 550 551 552
         $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
yllen's avatar
CS  
yllen committed
553
      $data['search']['no_search']   = true;
moyooo's avatar
moyooo committed
554

Johan Cwiklinski's avatar
Johan Cwiklinski committed
555
      $data['toview'] = $this->addDefaultToView($itemtype, $params);
556
      $data['meta_toview'] = [];
moyooo's avatar
moyooo committed
557
      if (!$forcetoview) {
moyooo's avatar
moyooo committed
558
         // Add items to display depending of personal prefs
Johan Cwiklinski's avatar
Johan Cwiklinski committed
559 560 561 562 563 564 565 566 567
         $pref_itemtype = $itemtype;
         if ($sub_item && $sub_item['sub_item'] instanceof CommonDBRelation && $sub_item['sub_item']->getType() == $itemtype) {
            $pref_itemtype = 'AllAssets';
         }
         $displaypref = DisplayPreference::getForTypeUser(
            $pref_itemtype,
            Session::getLoginUserID(),
            ($sub_item !== false && count($sub_item))
         );
moyooo's avatar
moyooo committed
568 569
         if (count($displaypref)) {
            foreach ($displaypref as $val) {
570
               array_push($data['toview'], $val);
moyooo's avatar
moyooo committed
571 572
            }
         }
Alexandre Delaunay's avatar
Alexandre Delaunay committed
573
      } else {
Johan Cwiklinski's avatar
Johan Cwiklinski committed
574
         $data['toview'] = array_merge($data['toview'], $p['forcedisplay']);
moyooo's avatar
moyooo committed
575
      }
576

moyooo's avatar
moyooo committed
577
      if (count($p['criteria']) > 0) {
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
         // use a recursive clojure 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'])) {
                  return $parse_criteria($criterion['criteria']);
               }

               // 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;
                  }
moyooo's avatar
moyooo committed
599
               }
600

601 602 603 604
               if (isset($criterion['value'])
                   && (strlen($criterion['value']) > 0)) {
                  $data['search']['no_search'] = false;
               }
moyooo's avatar
moyooo committed
605
            }
606 607 608 609
         };

         // call the clojure
         $parse_criteria($p['criteria']);
moyooo's avatar
moyooo committed
610
      }
moyooo's avatar
moyooo committed
611

moyooo's avatar
moyooo committed
612 613 614
      if (count($p['metacriteria'])) {
         $data['search']['no_search'] = false;
      }
moyooo's avatar
moyooo committed
615

moyooo's avatar
moyooo committed
616 617 618 619
      // Add order item
      if (!in_array($p['sort'], $data['toview'])) {
         array_push($data['toview'], $p['sort']);
      }
moyooo's avatar
moyooo committed
620

moyooo's avatar
moyooo committed
621 622 623
      // Special case for Ticket : put ID in front
      if ($itemtype == 'Ticket') {
         array_unshift($data['toview'], 2);
moyooo's avatar
moyooo committed
624 625
      }

Johan Cwiklinski's avatar
Johan Cwiklinski committed
626
      $limitsearchopt   = $this->getCleanedOptions($this->itemtype);
moyooo's avatar
moyooo committed
627
      // Clean and reorder toview
628
      $tmpview = [];
629
      foreach ($data['toview'] as $val) {
moyooo's avatar
moyooo committed
630 631
         if (isset($limitsearchopt[$val]) && !in_array($val, $tmpview)) {
            $tmpview[] = $val;
moyooo's avatar
moyooo committed
632 633
         }
      }
moyooo's avatar
moyooo committed
634 635
      $data['toview']    = $tmpview;
      $data['tocompute'] = $data['toview'];
yllen's avatar
CS  
yllen committed
636

moyooo's avatar
moyooo committed
637 638 639 640 641 642 643
      // Force item to display
      if ($forcetoview) {
         foreach ($data['toview'] as $val) {
            if (!in_array($val, $data['tocompute'])) {
                array_push($data['tocompute'], $val);
            }
         }
yllen's avatar
CS  
yllen committed
644 645
      }

Johan Cwiklinski's avatar
Johan Cwiklinski committed
646 647 648 649
      if (!count($data['toview'])) {
         Toolbox::logWarning(
            'No columns found to display ' . $itemtype
         );
Johan Cwiklinski's avatar
Johan Cwiklinski committed
650 651 652 653 654 655 656
         global $CONTAINER;
         $flash = $CONTAINER->get(Slim\Flash\Messages::class);
         $flash->addMessage(
            'error',
            //TRANS: %1$s is an itemtype
            sprintf('No columns found to display %1$s', $itemtype)
         );
Johan Cwiklinski's avatar
Johan Cwiklinski committed
657 658
      }

moyooo's avatar
moyooo committed
659 660 661
      return $data;
   }

moyooo's avatar
moyooo committed
662

moyooo's avatar
moyooo committed
663 664 665 666 667 668 669 670
   /**
    * 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
yllen's avatar
CS  
yllen committed
671
    *
Anael Mobilia's avatar
Anael Mobilia committed
672
    * @since 0.85
yllen's avatar
CS  
yllen committed
673
    *
Johan Cwiklinski's avatar
Johan Cwiklinski committed
674 675
    * @param array            $data     array of search datas prepared to generate SQL
    * @param CommonDBTM|false $sub_item Are we calling from a sub item?
moyooo's avatar
moyooo committed
676
    *
Johan Cwiklinski's avatar
Johan Cwiklinski committed
677 678
    * @return void
    *
Johan Cwiklinski's avatar
Johan Cwiklinski committed
679
    * @since 10.0.0 Method is no longer static
moyooo's avatar
moyooo committed
680
   **/
Johan Cwiklinski's avatar
Johan Cwiklinski committed
681
   public function constructSQL(array &$data, $sub_item = false) {
Johan Cwiklinski's avatar
Johan Cwiklinski committed
682
      global $CFG_GLPI;
yllen's avatar
CS  
yllen committed
683

moyooo's avatar
moyooo committed
684 685
      if (!isset($data['itemtype'])) {
         return false;
686
      }
yllen's avatar
CS  
yllen committed
687

688
      $data['sql']['count']  = [];
moyooo's avatar
moyooo committed
689
      $data['sql']['search'] = '';
690

Johan Cwiklinski's avatar
Johan Cwiklinski committed
691
      $searchopt        = &$this->getOptions($data['itemtype']);
yllen's avatar
CS  
yllen committed
692

693
      $blacklist_tables = [];
moyooo's avatar
moyooo committed
694
      if (isset($CFG_GLPI['union_search_type'][$data['itemtype']])) {
yllen's avatar
CS  
yllen committed
695
         $itemtable          = $CFG_GLPI['union_search_type'][$data['itemtype']];
moyooo's avatar
moyooo committed
696 697 698
         $blacklist_tables[] = getTableForItemType($data['itemtype']);
      } else {
         $itemtable = getTableForItemType($data['itemtype']);
moyooo's avatar
moyooo committed
699
      }
700

moyooo's avatar
moyooo committed
701 702 703 704 705 706
      // hack for AllAssets
      if (isset($CFG_GLPI['union_search_type'][$data['itemtype']])) {
         $entity_restrict = true;
      } else {
         $entity_restrict = $data['item']->isEntityAssign();
      }
moyooo's avatar
moyooo committed
707 708 709 710

      // Construct the request

      //// 1 - SELECT
711
      // request currentuser for SQL supervision, not displayed
Johan Cwiklinski's avatar
Johan Cwiklinski committed
712 713
      $SELECT = "SELECT DISTINCT ".$this->db->quoteName("$itemtable.id")." AS id, ".$this->db->quote($_SESSION['glpiname'])." AS currentuser,
                        ".$this->addDefaultSelect($data['itemtype']);
moyooo's avatar
moyooo committed
714 715

      // Add select for all toview item
716
      foreach ($data['toview'] as $val) {
Johan Cwiklinski's avatar
Johan Cwiklinski committed
717
         $SELECT .= $this->addSelect($data['itemtype'], $val);
moyooo's avatar
moyooo committed
718 719
      }

720
      if (isset($data['search']['as_map']) && $data['search']['as_map'] == 1) {
Johan Cwiklinski's avatar
Johan Cwiklinski committed
721
         $SELECT .= ' '.$this->db->quoteName('glpi_locations.id').' AS loc_id, ';
722 723
      }

moyooo's avatar
moyooo committed
724 725
      //// 2 - FROM AND LEFT JOIN
      // Set reference table
Johan Cwiklinski's avatar
Johan Cwiklinski committed
726
      $FROM = " FROM " . $this->db->quoteName($itemtable);
moyooo's avatar
moyooo committed
727 728

      // Init already linked tables array in order not to link a table several times
729
      $already_link_tables = [];
moyooo's avatar
moyooo committed
730
      // Put reference table
yllen's avatar
yllen committed
731
      array_push($already_link_tables, $itemtable);
moyooo's avatar
moyooo committed
732 733

      // Add default join
Johan Cwiklinski's avatar
Johan Cwiklinski committed
734
      $COMMONLEFTJOIN = $this->addDefaultJoin($data['itemtype'], $itemtable, $already_link_tables);
Johan Cwiklinski's avatar
Johan Cwiklinski committed
735 736 737 738 739 740 741 742

      $itemtype = $data['itemtype'];
      $COMMONSUBLEFTJOIN = '';
      if ($sub_item !== false && method_exists($sub_item['sub_item'], 'addSubDefaultJoin') && $sub_item['sub_item']->getType() !== $itemtype) {
         $sub = $sub_item['sub_item'];
         $COMMONSUBLEFTJOIN = $sub::addSubDefaultJoin($sub_item['item'], $itemtype);
      }

yllen's avatar
yllen committed
743
      $FROM          .= $COMMONLEFTJOIN;
moyooo's avatar
moyooo committed
744 745

      // Add all table for toview items
746
      foreach ($data['tocompute'] as $val) {
moyooo's avatar
moyooo committed
747
         if (!in_array($searchopt[$val]["table"], $blacklist_tables)) {
Johan Cwiklinski's avatar
Johan Cwiklinski committed
748
            $FROM .= $this->addLeftJoin($data['itemtype'], $itemtable, $already_link_tables,
moyooo's avatar
moyooo committed
749 750 751 752
                                       $searchopt[$val]["table"],
                                       $searchopt[$val]["linkfield"], 0, 0,
                                       $searchopt[$val]["joinparams"],
                                       $searchopt[$val]["field"]);
moyooo's avatar
moyooo committed
753
         }
moyooo's avatar
moyooo committed
754
      }
yllen's avatar
CS  
yllen committed
755

moyooo's avatar
moyooo committed
756
      // Search all case :
moyooo's avatar
moyooo committed
757 758
      if ($data['search']['all_search']) {
         foreach ($searchopt as $key => $val) {
moyooo's avatar
moyooo committed
759
            // Do not search on Group Name
760
            if (is_array($val) && isset($val['table'])) {
moyooo's avatar
moyooo committed
761
               if (!in_array($searchopt[$key]["table"], $blacklist_tables)) {
Johan Cwiklinski's avatar
Johan Cwiklinski committed
762
                  $FROM .= $this->addLeftJoin($data['itemtype'], $itemtable, $already_link_tables,
moyooo's avatar
moyooo committed
763 764 765 766
                                             $searchopt[$key]["table"],
                                             $searchopt[$key]["linkfield"], 0, 0,
                                             $searchopt[$key]["joinparams"],
                                             $searchopt[$key]["field"]);
moyooo's avatar
moyooo committed
767
               }
moyooo's avatar
moyooo committed
768 769 770 771 772
            }
         }
      }

      //// 3 - WHERE
moyooo's avatar
moyooo committed
773

moyooo's avatar
moyooo committed
774
      // default string
Johan Cwiklinski's avatar
Johan Cwiklinski committed
775 776 777 778 779 780 781 782 783 784
      $COMMONWHERE = '';
      if ($sub_item !== false && method_exists($sub_item['sub_item'], 'addSubDefaultWhere')) {
         $sub = $sub_item['sub_item'];
         $COMMONSUBWHERE = $sub::addSubDefaultWhere(
            $sub_item['item'],
            $sub_item['sub_item']->getType() == $data['real_itemtype']
         );
      } else {
         $COMMONWHERE = self::addDefaultWhere($data['itemtype']);
      }
yllen's avatar
yllen committed
785
      $first       = empty($COMMONWHERE);
moyooo's avatar
moyooo committed
786 787

      // Add deleted if item have it
moyooo's avatar
moyooo committed
788
      if ($data['item'] && $data['item']->maybeDeleted()) {
789
         $LINK = " AND ";
moyooo's avatar
moyooo committed
790
         if ($first) {
yllen's avatar
yllen committed
791
            $LINK  = " ";
yllen's avatar
yllen committed
792
            $first = false;
moyooo's avatar
moyooo committed
793
         }
Johan Cwiklinski's avatar
Johan Cwiklinski committed
794
         $COMMONWHERE .= $LINK. $this->db->quoteName("$itemtable.is_deleted") . " = " . (int)$data['search']['is_deleted'] . " ";
moyooo's avatar
moyooo committed
795 796 797
      }

      // Remove template items
moyooo's avatar
moyooo committed
798
      if ($data['item'] && $data['item']->maybeTemplate()) {
799
         $LINK = " AND ";
moyooo's avatar
moyooo committed
800
         if ($first) {
yllen's avatar
yllen committed
801
            $LINK  = " ";
yllen's avatar
yllen committed
802
            $first = false;
moyooo's avatar
moyooo committed
803
         }
Johan Cwiklinski's avatar
Johan Cwiklinski committed
804
         $COMMONWHERE .= $LINK . $this->db->quoteName("$itemtable.is_template") . " = 0 ";
moyooo's avatar
moyooo committed
805 806 807 808
      }

      // Add Restrict to current entities
      if ($entity_restrict) {
809
         $LINK = " AND ";
moyooo's avatar
moyooo committed
810
         if ($first) {
yllen's avatar
yllen committed
811
            $LINK  = " ";
yllen's avatar
yllen committed
812
            $first = false;
moyooo's avatar
moyooo committed
813 814
         }

moyooo's avatar
moyooo committed
815
         if ($data['itemtype'] == 'Entity') {
yllen's avatar
yllen committed
816
            $COMMONWHERE .= getEntitiesRestrictRequest($LINK, $itemtable, 'id', '', true);
moyooo's avatar
moyooo committed
817

moyooo's avatar
moyooo committed
818
         } else if (isset($CFG_GLPI["union_search_type"][$data['itemtype']])) {
moyooo's avatar
moyooo committed
819 820
            // Will be replace below in Union/Recursivity Hack
            $COMMONWHERE .= $LINK." ENTITYRESTRICT ";
821
         } else {
yllen's avatar
yllen committed
822
            $COMMONWHERE .= getEntitiesRestrictRequest($LINK, $itemtable, '', '',
moyooo's avatar
moyooo committed
823
                                                       $data['item']->maybeRecursive());
moyooo's avatar
moyooo committed
824 825
         }
      }
yllen's avatar
yllen committed
826 827
      $WHERE  = "";
      $HAVING = "";
moyooo's avatar
moyooo committed
828 829 830

      // Add search conditions
      // If there is search items
moyooo's avatar
moyooo committed
831
      if (count($data['search']['criteria'])) {
Johan Cwiklinski's avatar
Johan Cwiklinski committed
832 833
         $WHERE  = $this->constructCriteriaSQL($data['search']['criteria'], $data, $searchopt);
         $HAVING = $this->constructCriteriaSQL($data['search']['criteria'], $data, $searchopt, true);
moyooo's avatar
moyooo committed
834

835
         // if criteria (with meta flag) need additional join/from sql
Johan Cwiklinski's avatar
Johan Cwiklinski committed
836
         $this->constructAdditionalSqlForMetacriteria($data['search']['criteria'], $SELECT, $FROM, $already_link_tables, $data);
moyooo's avatar
moyooo committed
837 838 839
      }

      //// 4 - ORDER
Johan Cwiklinski's avatar
Johan Cwiklinski committed
840
      $ORDER = " ORDER BY ".$this->db->quoteName('id'). ' ';
841
      foreach ($data['tocompute'] as $val) {
moyooo's avatar
moyooo committed
842
         if ($data['search']['sort'] == $val) {
Johan Cwiklinski's avatar
Johan Cwiklinski committed
843
            $ORDER = $this->addOrderBy(
844 845 846 847
               $data['itemtype'],
               $data['search']['sort'],
               $data['search']['order']
            );
moyooo's avatar
moyooo committed
848 849 850
         }
      }

851
      $SELECT = rtrim(trim($SELECT), ',');
moyooo's avatar
moyooo committed
852 853 854 855

      //// 7 - Manage GROUP BY
      $GROUPBY = "";
      // Meta Search / Search All / Count tickets
856 857 858 859
      $criteria_with_meta = array_filter($data['search']['criteria'], function($criterion) {
         return isset($criterion['meta'])
                && $criterion['meta'];
      });
moyooo's avatar
moyooo committed
860
      if ((count($data['search']['metacriteria']))
861
          || count($criteria_with_meta)
moyooo's avatar
moyooo committed
862 863
          || !empty($HAVING)
          || $data['search']['all_search']) {
Johan Cwiklinski's avatar
Johan Cwiklinski committed
864
         $GROUPBY = " GROUP BY " . $this->db->quoteName("$itemtable.id");
moyooo's avatar
moyooo committed
865 866 867
      }

      if (empty($GROUPBY)) {
868
         foreach ($data['toview'] as $val2) {
moyooo's avatar
moyooo committed
869 870 871 872
            if (!empty($GROUPBY)) {
               break;
            }
            if (isset($searchopt[$val2]["forcegroupby"])) {
Johan Cwiklinski's avatar
Johan Cwiklinski committed
873
               $GROUPBY = " GROUP BY " . $this->db->quoteName("$itemtable.id");;
moyooo's avatar
moyooo committed
874 875 876
            }
         }
      }
moyooo's avatar
moyooo committed
877

yllen's avatar
yllen committed
878 879
      $LIMIT   = "";
      $numrows = 0;
moyooo's avatar
moyooo committed
880
      //No search : count number of items using a simple count(ID) request and LIMIT search
moyooo's avatar
moyooo committed
881
      if ($data['search']['no_search']) {
882
         $LIMIT = " LIMIT ".(int)$data['search']['start'].", ".(int)$data['search']['list_limit'];
moyooo's avatar
moyooo committed
883 884

         // Force group by for all the type -> need to count only on table ID
moyooo's avatar
moyooo committed
885
         if (!isset($searchopt[1]['forcegroupby'])) {
moyooo's avatar
moyooo committed
886 887
            $count = "count(*)";
         } else {
Johan Cwiklinski's avatar
Johan Cwiklinski committed
888
            $count = "count(DISTINCT ".$this->db->quoteName("$itemtable.id").")";
moyooo's avatar
moyooo committed
889
         }
890
         // request currentuser for SQL supervision, not displayed
Johan Cwiklinski's avatar
Johan Cwiklinski committed
891
         $query_num_select = "SELECT $count,
Johan Cwiklinski's avatar
Johan Cwiklinski committed
892 893
                              ". $this->db->quote($_SESSION['glpiname'])." AS currentuser
                       FROM ".$this->db->quoteName($itemtable).
yllen's avatar
yllen committed
894
                       $COMMONLEFTJOIN;
Johan Cwiklinski's avatar
Johan Cwiklinski committed
895
         $query_num = '';
moyooo's avatar
moyooo committed
896

yllen's avatar
yllen committed
897
         $first     = true;
moyooo's avatar
moyooo committed
898 899

         if (!empty($COMMONWHERE)) {
900
            $LINK = " AND ";
moyooo's avatar
moyooo committed
901
            if ($first) {
yllen's avatar
yllen committed
902 903
               $LINK  = " WHERE ";
               $first = false;
moyooo's avatar
moyooo committed
904 905 906 907
            }
            $query_num .= $LINK.$COMMONWHERE;
         }
         // Union Search :
moyooo's avatar
moyooo committed
908
         if (isset($CFG_GLPI["union_search_type"][$data['itemtype']])) {
Johan Cwiklinski's avatar
Johan Cwiklinski committed
909 910
            $tmpquery = $query_num_select . $query_num;
            $numrows  = 0;
yllen's avatar
CS  
yllen committed
911

moyooo's avatar
moyooo committed
912
            foreach ($CFG_GLPI[$CFG_GLPI["union_search_type"][$data['itemtype']]] as $ctype) {
yllen's avatar
yllen committed
913
               $ctable = getTableForItemType($ctype);
yllen's avatar
yllen committed
914 915
               if (($citem = getItemForItemtype($ctype))
                   && $citem->canView()) {
moyooo's avatar
moyooo committed
916
                  // State case
moyooo's avatar
moyooo committed
917
                  if ($data['itemtype'] == 'AllAssets') {
yllen's avatar
CS  
yllen committed
918 919 920
                     $query_num  = str_replace($CFG_GLPI["union_search_type"][$data['itemtype']],
                                               $ctable, $tmpquery);
                     $query_num  = str_replace($data['itemtype'], $ctype, $query_num);
Johan Cwiklinski's avatar
Johan Cwiklinski committed
921 922 923 924 925 926 927 928 929 930

                     if ($sub_item !== false && method_exists($sub_item['sub_item'], 'addSubSelect')) {
                        $sub = $sub_item['sub_item'];
                        $sub_select = $sub::addSubSelect(
                           $sub_item['item'],
                           $ctype
                        );
                        $query_num .= "AND $ctable.id IN ($sub_select)";
                     }

Johan Cwiklinski's avatar
Johan Cwiklinski committed
931
                     $query_num .= " AND ".$this->db->quoteName("$ctable.id")." IS NOT NULL ";
932 933 934

                     // Add deleted if item have it
                     if ($citem && $citem->maybeDeleted()) {
Johan Cwiklinski's avatar
Johan Cwiklinski committed
935
                        $query_num .= " AND ".$this->db->quoteName("$ctable.is_deleted")." = 0 ";
936 937 938 939
                     }

                     // Remove template items
                     if ($citem && $citem->maybeTemplate()) {
Johan Cwiklinski's avatar
Johan Cwiklinski committed
940
                        $query_num .= " AND ".$this->db->quoteName("$ctable.is_template")." = 0 ";
941
                     }
yllen's avatar
yllen committed
942

moyooo's avatar
moyooo committed
943
                  } else {// Ref table case
moyooo's avatar
moyooo committed
944
                     $reftable = getTableForItemType($data['itemtype']);
moyooo's avatar
moyooo committed
945
                     if ($data['item'] && $data['item']->maybeDeleted()) {
Johan Cwiklinski's avatar
Johan Cwiklinski committed
946 947 948 949 950
                        $tmpquery = str_replace(
                           $this->db->quoteName($CFG_GLPI["union_search_type"][$data['itemtype']]).".".$this->db->quoteName('is_deleted'),
                           $this->db->quoteName("$reftable.is_deleted"),
                           $tmpquery
                        );
951
                     }
Johan Cwiklinski's avatar
Johan Cwiklinski committed
952 953 954 955
                     $replace  = "FROM ".$this->db->quoteName($reftable)."
                                  INNER JOIN ".$this->db->quoteName($ctable)."
                                       ON (".$this->db->quoteName("$reftable.items_id")." = ".$this->db->quoteName("$ctable.id")."
                                           AND ".$this->db->quoteName("$reftable.itemtype")." = ".$this->db->quote($ctype).")";
yllen's avatar
CS  
yllen committed
956

Johan Cwiklinski's avatar
Johan Cwiklinski committed
957 958
                     $query_num = str_replace("FROM ".
                                                $this->db->quoteName($CFG_GLPI["union_search_type"][$data['itemtype']]),
yllen's avatar
yllen committed
959
                                              $replace, $tmpquery);
yllen's avatar
CS  
yllen committed
960 961
                     $query_num = str_replace($CFG_GLPI["union_search_type"][$data['itemtype']],
                                              $ctable, $query_num);
moyooo's avatar
moyooo committed
962
                  }
yllen's avatar
yllen committed
963 964 965 966
                  $query_num = str_replace("ENTITYRESTRICT",
                                           getEntitiesRestrictRequest('', $ctable, '', '',
                                                                      $citem->maybeRecursive()),
                                           $query_num);
moyooo's avatar
moyooo committed
967
                  $data['sql']['count'][] = $query_num;
moyooo's avatar
moyooo committed
968 969
               }
            }
yllen's avatar
yllen committed
970

moyooo's avatar
moyooo committed
971
         } else {
Johan Cwiklinski's avatar
Johan Cwiklinski committed
972 973 974 975 976 977
            $query_num_select .= $COMMONSUBLEFTJOIN;
            if (!empty($COMMONSUBWHERE)) {
               $query_num .= (!empty($query_num) ? " AND ($COMMONSUBWHERE)": " WHERE $COMMONSUBWHERE");
            }

            $data['sql']['count'][] = $query_num_select . $query_num;
moyooo's avatar
moyooo committed
978 979 980 981
         }
      }

      // If export_all reset LIMIT condition
moyooo's avatar
moyooo committed
982
      if ($data['search']['export_all']) {
yllen's avatar
yllen committed
983
         $LIMIT = "";
moyooo's avatar
moyooo committed
984 985 986 987
      }

      if (!empty($WHERE) || !empty($COMMONWHERE)) {
         if (!empty($COMMONWHERE)) {
yllen's avatar
yllen committed
988
            $WHERE = ' WHERE '.$COMMONWHERE.(!empty($WHERE)?' AND ( '.$WHERE.' )':'');
moyooo's avatar
moyooo committed
989
         } else {
yllen's avatar
yllen committed
990
            $WHERE = ' WHERE '.$WHERE.' ';
moyooo's avatar
moyooo committed
991
         }
yllen's avatar
yllen committed
992
         $first = false;
moyooo's avatar
moyooo committed
993 994
      }

Johan Cwiklinski's avatar
Johan Cwiklinski committed
995 996 997 998 999
      $NOSUBWHERE = $WHERE;
      if (!empty($COMMONSUBWHERE)) {
         $WHERE .= (!empty($WHERE) ? " AND ($COMMONSUBWHERE)": " WHERE $COMMONSUBWHERE");
      }

moyooo's avatar
moyooo committed
1000
      if (!empty($HAVING)) {
yllen's avatar
yllen committed
1001
         $HAVING = ' HAVING '.$HAVING;
moyooo's avatar
moyooo committed
1002 1003 1004
      }

      // Create QUERY
moyooo's avatar
moyooo committed
1005
      if (isset($CFG_GLPI["union_search_type"][$data['itemtype']])) {
yllen's avatar
yllen committed
1006 1007
         $first = true;
         $QUERY = "";
moyooo's avatar
moyooo committed
1008
         foreach ($CFG_GLPI[$CFG_GLPI["union_search_type"][$data['itemtype']]] as $ctype) {
moyooo's avatar
moyooo committed
1009
            $ctable = getTableForItemType($ctype);
yllen's avatar
yllen committed
1010 1011
            if (($citem = getItemForItemtype($ctype))
                && $citem->canView()) {
moyooo's avatar
moyooo committed
1012
               if ($first) {
yllen's avatar
yllen committed
1013
                  $first = false;
moyooo's avatar
moyooo committed
1014
               } else {
yllen's avatar
yllen committed
1015
                  $QUERY .= " UNION ";
moyooo's avatar
moyooo committed
1016
               }
yllen's avatar
yllen committed
1017
               $tmpquery = "";
moyooo's avatar
moyooo committed
1018
               // AllAssets case
moyooo's avatar
moyooo committed
1019
               if ($data['itemtype'] == 'AllAssets') {
Johan Cwiklinski's avatar
Johan Cwiklinski committed
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
                  $tmpquery = "$SELECT, '$ctype' AS TYPE $FROM $NOSUBWHERE";

                  if ($sub_item !== false && method_exists($sub_item['sub_item'], 'addSubSelect')) {
                     $sub = $sub_item['sub_item'];
                     $sub_select = $sub::<