2019-02-01 17:44:31 +01:00
|
|
|
<?php
|
2020-09-07 15:04:06 +02:00
|
|
|
/*
|
|
|
|
* OpenSTAManager: il software gestionale open source per l'assistenza tecnica e la fatturazione
|
2021-01-20 15:08:51 +01:00
|
|
|
* Copyright (C) DevCode s.r.l.
|
2020-09-07 15:04:06 +02:00
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2019-02-01 17:44:31 +01:00
|
|
|
|
|
|
|
namespace Util;
|
|
|
|
|
|
|
|
use Auth;
|
|
|
|
use Modules;
|
|
|
|
use Translator;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Classe per la gestione delle interazione di base per le query dinamiche.
|
|
|
|
*
|
|
|
|
* @since 2.4.7
|
|
|
|
*/
|
|
|
|
class Query
|
|
|
|
{
|
2019-02-02 08:38:06 +01:00
|
|
|
protected static $segments = true;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Imposta l'utilizzo o meno dei segmenti per le query.
|
|
|
|
*
|
|
|
|
* @param bool $segments
|
|
|
|
*/
|
|
|
|
public static function setSegments($segments)
|
|
|
|
{
|
|
|
|
self::$segments = $segments;
|
|
|
|
}
|
|
|
|
|
2019-02-01 17:44:31 +01:00
|
|
|
/**
|
|
|
|
* Restituisce un'insieme di array comprendenti le informazioni per la costruzione della query del modulo indicato.
|
|
|
|
*
|
2019-02-02 08:38:06 +01:00
|
|
|
* @param array $element
|
2019-02-01 17:44:31 +01:00
|
|
|
*
|
|
|
|
* @throws \Exception
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public static function readQuery($element)
|
|
|
|
{
|
2020-10-29 16:48:37 +01:00
|
|
|
if (string_contains($element['option'], '|select|')) {
|
2019-02-01 17:44:31 +01:00
|
|
|
$result = self::readNewQuery($element);
|
|
|
|
} else {
|
|
|
|
$result = self::readOldQuery($element);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sostituisce i valori previsti all'interno delle query di moduli/plugin.
|
|
|
|
*
|
|
|
|
* @param string $query
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public static function replacePlaceholder($query)
|
|
|
|
{
|
|
|
|
$id_parent = filter('id_parent');
|
|
|
|
|
|
|
|
$id_module = Modules::getCurrent()['id'];
|
2019-02-02 08:38:06 +01:00
|
|
|
$segment = !empty(self::$segments) ? $_SESSION['module_'.$id_module]['id_segment'] : null;
|
2019-02-01 17:44:31 +01:00
|
|
|
|
|
|
|
$user = Auth::user();
|
|
|
|
|
2019-03-22 11:35:26 +01:00
|
|
|
// Sostituzione periodi temporali
|
|
|
|
preg_match('|date_period\((.+?)\)|', $query, $matches);
|
2020-09-22 20:28:37 +02:00
|
|
|
$date_query = $date_filter = null;
|
|
|
|
if (!empty($matches)) {
|
|
|
|
$dates = explode(',', $matches[1]);
|
|
|
|
$date_filter = $matches[0];
|
|
|
|
|
|
|
|
$filters = [];
|
|
|
|
if ($dates[0] != 'custom') {
|
|
|
|
foreach ($dates as $date) {
|
|
|
|
$filters[] = $date." BETWEEN '|period_start|' AND '|period_end|'";
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
foreach ($dates as $k => $v) {
|
|
|
|
if ($k < 1) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
$filters[] = $v;
|
2019-05-03 15:32:28 -07:00
|
|
|
}
|
|
|
|
}
|
2020-09-22 20:28:37 +02:00
|
|
|
$date_query = !empty($filters) && !empty(self::$segments) ? ' AND ('.implode(' OR ', $filters).')' : '';
|
2019-05-03 15:32:28 -07:00
|
|
|
}
|
2019-03-22 11:35:26 +01:00
|
|
|
|
2019-07-09 12:29:39 +02:00
|
|
|
// Sostituzione periodi temporali
|
|
|
|
preg_match('|segment\((.+?)\)|', $query, $matches);
|
|
|
|
$segment_name = !empty($matches[1]) ? $matches[1] : 'id_segment';
|
|
|
|
$segment_filter = !empty($matches[0]) ? $matches[0] : 'segment';
|
|
|
|
|
2019-02-01 17:44:31 +01:00
|
|
|
// Elenco delle sostituzioni
|
|
|
|
$replace = [
|
|
|
|
// Identificatori
|
|
|
|
'|id_anagrafica|' => prepare($user['idanagrafica']),
|
|
|
|
'|id_utente|' => prepare($user['id']),
|
|
|
|
'|id_parent|' => prepare($id_parent),
|
|
|
|
|
2019-03-22 11:35:26 +01:00
|
|
|
// Filtro temporale
|
|
|
|
'|'.$date_filter.'|' => $date_query,
|
|
|
|
|
2019-02-01 17:44:31 +01:00
|
|
|
// Date
|
|
|
|
'|period_start|' => $_SESSION['period_start'],
|
2021-01-05 15:16:37 +01:00
|
|
|
'|period_end|' => $_SESSION['period_end'].' 23:59:59',
|
2019-02-01 17:44:31 +01:00
|
|
|
|
|
|
|
// Segmenti
|
2019-07-09 12:29:39 +02:00
|
|
|
'|'.$segment_filter.'|' => !empty($segment) ? ' AND '.$segment_name.' = '.prepare($segment) : '',
|
2020-08-27 11:10:55 +02:00
|
|
|
|
|
|
|
// Filtro dinamico per il modulo Giacenze sedi
|
2020-09-22 20:28:37 +02:00
|
|
|
'|giacenze_sedi_idsede|' => prepare(isset($_SESSION['giacenze_sedi']) ? $_SESSION['giacenze_sedi']['idsede'] : null),
|
2019-02-01 17:44:31 +01:00
|
|
|
];
|
|
|
|
|
|
|
|
// Sostituzione dei formati
|
|
|
|
$patterns = formatter()->getSQLPatterns();
|
|
|
|
|
|
|
|
foreach ($patterns as $key => $value) {
|
|
|
|
$replace['|'.$key.'_format|'] = "'".$value."'";
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sostituzione effettiva
|
|
|
|
$query = replace($query, $replace);
|
|
|
|
|
|
|
|
return $query;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Genera la query prevista dalla struttura indicata.
|
|
|
|
*
|
|
|
|
* @param $structure
|
|
|
|
* @param array $search
|
|
|
|
* @param array $order
|
|
|
|
* @param array $limit
|
|
|
|
*
|
|
|
|
* @throws \Exception
|
|
|
|
*
|
|
|
|
* @return mixed|string
|
|
|
|
*/
|
|
|
|
public static function getQuery($structure, $search = [], $order = [], $limit = [])
|
|
|
|
{
|
|
|
|
$total = self::readQuery($structure);
|
|
|
|
|
|
|
|
// Lettura parametri modulo
|
|
|
|
$query = $total['query'];
|
|
|
|
|
|
|
|
if (empty($query) || $query == 'menu' || $query == 'custom') {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
2020-07-16 17:31:30 +02:00
|
|
|
// Filtri di ricerca
|
2019-02-01 17:44:31 +01:00
|
|
|
$search_filters = [];
|
2020-07-16 17:31:30 +02:00
|
|
|
foreach ($search as $field => $original_value) {
|
2019-02-01 17:44:31 +01:00
|
|
|
$pos = array_search($field, $total['fields']);
|
2021-07-27 11:37:04 +02:00
|
|
|
$value = is_array($original_value) ? $original_value : trim($original_value);
|
2019-02-01 17:44:31 +01:00
|
|
|
|
|
|
|
if (isset($value) && $pos !== false) {
|
|
|
|
$search_query = $total['search_inside'][$pos];
|
|
|
|
|
2019-02-02 08:23:12 +01:00
|
|
|
// Campo con ricerca personalizzata
|
2020-10-29 16:48:37 +01:00
|
|
|
if (string_contains($search_query, '|search|')) {
|
2019-02-01 17:44:31 +01:00
|
|
|
$pieces = explode(',', $value);
|
|
|
|
foreach ($pieces as $piece) {
|
|
|
|
$piece = trim($piece);
|
|
|
|
$search_filters[] = str_replace('|search|', prepare('%'.$piece.'%'), $search_query);
|
|
|
|
}
|
2019-02-02 08:23:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Campi tradizionali: ricerca tramite like
|
|
|
|
else {
|
|
|
|
// Ricerca nei titoli icon_title_* per le icone icon_*
|
2019-02-01 17:44:31 +01:00
|
|
|
if (preg_match('/^icon_(.+?)$/', $field, $m)) {
|
|
|
|
$search_query = '`icon_title_'.$m[1].'`';
|
|
|
|
}
|
|
|
|
|
2019-02-02 08:23:12 +01:00
|
|
|
// Ricerca nei titoli color_title_* per i colori color_*
|
2019-02-01 17:44:31 +01:00
|
|
|
elseif (preg_match('/^color_(.+?)$/', $field, $m)) {
|
|
|
|
$search_query = '`color_title_'.$m[1].'`';
|
|
|
|
}
|
|
|
|
|
2019-03-07 17:28:57 +01:00
|
|
|
// Gestione confronti
|
|
|
|
$real_value = trim(str_replace(['<', '>'], ['<', '>'], $value));
|
2020-10-29 16:48:37 +01:00
|
|
|
$more = string_starts_with($real_value, '>=') || string_starts_with($real_value, '> =') || string_starts_with($real_value, '>');
|
|
|
|
$minus = string_starts_with($real_value, '<=') || string_starts_with($real_value, '< =') || string_starts_with($real_value, '<');
|
|
|
|
$equal = string_starts_with($real_value, '=');
|
2019-03-07 17:28:57 +01:00
|
|
|
|
2020-01-09 18:40:12 +01:00
|
|
|
if ($minus || $more || $equal) {
|
2020-10-29 16:48:37 +01:00
|
|
|
$sign = string_contains($real_value, '=') ? '=' : '';
|
2019-03-07 17:28:57 +01:00
|
|
|
if ($more) {
|
|
|
|
$sign = '>'.$sign;
|
2020-01-09 18:40:12 +01:00
|
|
|
} elseif ($minus) {
|
2019-03-07 17:28:57 +01:00
|
|
|
$sign = '<'.$sign;
|
2020-01-09 18:40:12 +01:00
|
|
|
} else {
|
|
|
|
$sign = '=';
|
2019-03-07 17:28:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$value = trim(str_replace(['<', '=', '>'], '', $value));
|
2020-01-09 18:40:12 +01:00
|
|
|
|
2020-01-11 13:36:43 +01:00
|
|
|
if ($more || $minus) {
|
2020-01-09 18:40:12 +01:00
|
|
|
$search_filters[] = 'CAST('.$search_query.' AS UNSIGNED) '.$sign.' '.prepare($value);
|
|
|
|
} else {
|
|
|
|
$search_filters[] = $search_query.' = '.prepare($value);
|
|
|
|
}
|
2019-03-07 17:28:57 +01:00
|
|
|
} else {
|
|
|
|
$search_filters[] = $search_query.' LIKE '.prepare('%'.$value.'%');
|
|
|
|
}
|
2019-02-01 17:44:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-16 15:15:43 +01:00
|
|
|
// Campo id: ricerca tramite comparazione
|
|
|
|
elseif ($field == 'id') {
|
2020-07-16 17:31:30 +02:00
|
|
|
// Filtro per una serie di ID
|
|
|
|
if (is_array($original_value)) {
|
|
|
|
if (!empty($original_value)) {
|
|
|
|
$search_filters[] = $field.' IN ('.implode(', ', $original_value).')';
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$search_filters[] = $field.' = '.prepare($value);
|
|
|
|
}
|
2019-03-16 15:15:43 +01:00
|
|
|
}
|
|
|
|
|
2019-02-01 17:44:31 +01:00
|
|
|
// Ricerca
|
|
|
|
if (!empty($search_filters)) {
|
|
|
|
$query = str_replace('2=2', '2=2 AND ('.implode(' AND ', $search_filters).') ', $query);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ordinamento dei risultati
|
|
|
|
if (isset($order['dir']) && isset($order['column'])) {
|
2019-12-20 09:24:52 +01:00
|
|
|
//$pos = array_search($order['column'], $total['fields']);
|
|
|
|
$pos = $order['column'];
|
2019-02-01 17:44:31 +01:00
|
|
|
|
|
|
|
if ($pos !== false) {
|
|
|
|
$pieces = explode('ORDER', $query);
|
|
|
|
|
|
|
|
$count = count($pieces);
|
|
|
|
if ($count > 1) {
|
|
|
|
unset($pieces[$count - 1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
$query = implode('ORDER', $pieces).' ORDER BY '.$total['order_by'][$order['column']].' '.$order['dir'];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Paginazione
|
2019-03-04 18:37:10 +01:00
|
|
|
if (!empty($limit) && intval($limit['length']) > 0) {
|
2019-02-01 17:44:31 +01:00
|
|
|
$query .= ' LIMIT '.$limit['start'].', '.$limit['length'];
|
|
|
|
}
|
|
|
|
|
|
|
|
return $query;
|
|
|
|
}
|
|
|
|
|
2019-02-22 10:37:37 +01:00
|
|
|
public static function executeAndCount($query)
|
|
|
|
{
|
|
|
|
$database = database();
|
|
|
|
|
|
|
|
// Esecuzione della query
|
|
|
|
$query = self::str_replace_once('SELECT', 'SELECT SQL_CALC_FOUND_ROWS', $query);
|
|
|
|
$results = $database->fetchArray($query);
|
|
|
|
|
|
|
|
// Conteggio dei record filtrati
|
|
|
|
$count = $database->fetchOne('SELECT FOUND_ROWS() AS count');
|
|
|
|
|
|
|
|
return [
|
|
|
|
'results' => $results,
|
|
|
|
'count' => $count['count'],
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2019-02-01 17:44:31 +01:00
|
|
|
/**
|
|
|
|
* Restituisce le somme richieste dalla query prevista dalla struttura.
|
|
|
|
*
|
|
|
|
* @param $structure
|
|
|
|
* @param array $search
|
|
|
|
*
|
|
|
|
* @throws \Exception
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public static function getSums($structure, $search = [])
|
|
|
|
{
|
2020-07-16 17:31:30 +02:00
|
|
|
$total = self::readQuery($structure);
|
2019-02-01 17:44:31 +01:00
|
|
|
|
|
|
|
// Calcolo di eventuali somme
|
|
|
|
if (empty($total['summable'])) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
|
|
|
$result_query = self::getQuery($structure, $search);
|
|
|
|
|
2019-07-08 13:19:52 +02:00
|
|
|
// Filtri derivanti dai permessi (eventuali)
|
|
|
|
if (empty($structure->originalModule)) {
|
|
|
|
$result_query = Modules::replaceAdditionals($structure->id, $result_query);
|
|
|
|
}
|
|
|
|
|
2019-02-22 10:37:37 +01:00
|
|
|
$query = self::str_replace_once('SELECT', 'SELECT '.implode(', ', $total['summable']).' FROM(SELECT ', $result_query).') AS `z`';
|
2019-02-01 17:44:31 +01:00
|
|
|
$sums = database()->fetchOne($query);
|
|
|
|
|
|
|
|
$results = [];
|
|
|
|
if (!empty($sums)) {
|
|
|
|
foreach ($sums as $key => $sum) {
|
2020-10-29 16:48:37 +01:00
|
|
|
if (string_contains($key, 'sum_')) {
|
2019-02-01 17:44:31 +01:00
|
|
|
$results[str_replace('sum_', '', $key)] = Translator::numberToLocale($sum);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $results;
|
|
|
|
}
|
|
|
|
|
2019-02-22 10:37:37 +01:00
|
|
|
/**
|
|
|
|
* Sostituisce la prima occorenza di una determinata stringa.
|
|
|
|
*
|
|
|
|
* @param string $str_pattern
|
|
|
|
* @param string $str_replacement
|
|
|
|
* @param string $string
|
|
|
|
*
|
|
|
|
* @since 2.3
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
protected static function str_replace_once($str_pattern, $str_replacement, $string)
|
|
|
|
{
|
|
|
|
if (strpos($string, $str_pattern) !== false) {
|
|
|
|
$occurrence = strpos($string, $str_pattern);
|
|
|
|
|
|
|
|
return substr_replace($string, $str_replacement, strpos($string, $str_pattern), strlen($str_pattern));
|
|
|
|
}
|
|
|
|
|
|
|
|
return $string;
|
|
|
|
}
|
|
|
|
|
2019-02-01 17:44:31 +01:00
|
|
|
/**
|
|
|
|
* Interpreta lo standard modulare per l'individuazione delle query di un modulo/plugin del progetto.
|
|
|
|
*
|
|
|
|
* @param $element
|
|
|
|
*
|
|
|
|
* @throws \Exception
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
protected static function readNewQuery($element)
|
|
|
|
{
|
|
|
|
$fields = [];
|
|
|
|
$summable = [];
|
|
|
|
$search_inside = [];
|
|
|
|
$search = [];
|
|
|
|
$format = [];
|
|
|
|
$slow = [];
|
|
|
|
$order_by = [];
|
|
|
|
|
|
|
|
$query = $element['option'];
|
2019-06-12 12:49:49 +02:00
|
|
|
|
|
|
|
// Aggiunta eventuali filtri dai segmenti per eseguire la query filtrata
|
2019-11-05 16:18:45 +01:00
|
|
|
$query = str_replace('1=1', '1=1 '.Modules::getAdditionalsQuery($element['attributes']['name'], null, self::$segments), $query);
|
2019-02-01 17:44:31 +01:00
|
|
|
$views = self::getViews($element);
|
|
|
|
|
|
|
|
$select = [];
|
|
|
|
|
|
|
|
foreach ($views as $view) {
|
|
|
|
$select[] = $view['query'].(!empty($view['name']) ? " AS '".$view['name']."'" : '');
|
|
|
|
|
|
|
|
if (!empty($view['visible'])) {
|
|
|
|
$view['name'] = trim($view['name']);
|
|
|
|
$view['search_inside'] = trim($view['search_inside']);
|
|
|
|
$view['order_by'] = trim($view['order_by']);
|
|
|
|
|
|
|
|
$fields[] = trim($view['name']);
|
|
|
|
|
|
|
|
$search_inside[] = !empty($view['search_inside']) ? $view['search_inside'] : '`'.$view['name'].'`';
|
|
|
|
$order_by[] = !empty($view['order_by']) ? $view['order_by'] : '`'.$view['name'].'`';
|
|
|
|
$search[] = $view['search'];
|
|
|
|
$slow[] = $view['slow'];
|
|
|
|
$format[] = $view['format'];
|
|
|
|
|
|
|
|
if ($view['summable']) {
|
|
|
|
$summable[] = 'SUM(`'.trim($view['name']."`) AS 'sum_".(count($fields) - 1)."'");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$select = empty($select) ? '*' : implode(', ', $select);
|
|
|
|
|
|
|
|
$query = str_replace('|select|', $select, $query);
|
|
|
|
|
|
|
|
return [
|
|
|
|
'query' => self::replacePlaceholder($query),
|
|
|
|
'fields' => $fields,
|
|
|
|
'search_inside' => $search_inside,
|
|
|
|
'order_by' => $order_by,
|
|
|
|
'search' => $search,
|
|
|
|
'slow' => $slow,
|
|
|
|
'format' => $format,
|
|
|
|
'summable' => $summable,
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Interpreta lo standard JSON per l'individuazione delle query di un modulo/plugin del progetto.
|
|
|
|
*
|
|
|
|
* @param array $element
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
protected static function readOldQuery($element)
|
|
|
|
{
|
|
|
|
$options = str_replace(["\r", "\n", "\t"], ' ', $element['option']);
|
|
|
|
$options = json_decode($options, true);
|
|
|
|
$options = $options['main_query'][0];
|
|
|
|
|
|
|
|
$fields = [];
|
|
|
|
$order_by = [];
|
|
|
|
|
|
|
|
$search = [];
|
|
|
|
$slow = [];
|
|
|
|
$format = [];
|
|
|
|
|
|
|
|
$query = $options['query'];
|
|
|
|
$views = explode(',', $options['fields']);
|
|
|
|
foreach ($views as $view) {
|
|
|
|
$fields[] = trim($view);
|
|
|
|
$order_by[] = '`'.trim($view).'`';
|
|
|
|
|
|
|
|
$search[] = 1;
|
|
|
|
$slow[] = 0;
|
|
|
|
$format[] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
$search_inside = $order_by;
|
|
|
|
|
|
|
|
return [
|
|
|
|
'query' => self::replacePlaceholder($query),
|
|
|
|
'fields' => $fields,
|
|
|
|
'search_inside' => $search_inside,
|
|
|
|
'order_by' => $order_by,
|
|
|
|
'search' => $search,
|
|
|
|
'slow' => $slow,
|
|
|
|
'format' => $format,
|
|
|
|
'summable' => [],
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Restituisce le singole componenti delle query per un determinato modulo/plugin.
|
|
|
|
*
|
|
|
|
* @param $element
|
|
|
|
*
|
|
|
|
* @throws \Exception
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
protected static function getViews($element)
|
|
|
|
{
|
|
|
|
$database = database();
|
|
|
|
|
|
|
|
$user = Auth::user();
|
|
|
|
|
|
|
|
$views = $database->fetchArray('SELECT * FROM `zz_views` WHERE `id_module`='.prepare($element['id']).' AND
|
|
|
|
`id` IN (
|
|
|
|
SELECT `id_vista` FROM `zz_group_view` WHERE `id_gruppo`=(
|
|
|
|
SELECT `idgruppo` FROM `zz_users` WHERE `id`='.prepare($user['id']).'
|
|
|
|
))
|
|
|
|
ORDER BY `order` ASC');
|
|
|
|
|
|
|
|
return $views;
|
|
|
|
}
|
|
|
|
}
|