abushyk

[HOWTO] Локальный grid_manager

Recommended Posts

Центральным местом, которое в 90% случаев обрабатывает запросы на извлечение нескольких записей-объявлений (всякого рода сетки-списки, в том числе и спецпредложениях в боковых колонках и забор данных для нанесения на карту), является файл /apps/system/lib/frontend/grid/grid_constructor.php - или Конструктор списка (КС).

В нем много разного функционала, но самый часто востребованный лежит в двух функциях transformGridData - подготовка данных к выводу и prepareRequestParams - обработка параметров поиска.

prepareRequestParams выполняет все операции связанные с тем, что бы превратить фильровочные переменные запроса, переданные в Конструктор списка, в части запроса к БД. Она имеет встроенную обработку некоторого числа параметров, но для расширения функционала иногда необходимо добавить свои. prepareRequestParams  НЕ обрабатывает параметры запроса прямо из строки браузера. Все параметры с веб-интерфейса перехватываются отдельной функцией, нормализуются и только тогда передаются в prepareRequestParams.

transformGridData адаптирует результат выборки из БД к удобоваримому виду. Поскольку результатом выборки списка являются строки из БД, то именно эта функция трансформирует значения указанные ключем, например поля select_box и select_by_query  в текстовые значения. Эта функция так же умеет обрабатывать сама некоторые "стандартные" поля, например географические - country_id, region_id,... street_id, currency_id и все поля типа select_box. "Превращение" в текст остальные ссылочных полей необходимо реализовывать самому

Как создать для шаблона локальный Grid_manager

1. Переопределением метода в шаблоне (ручное) - устаревший

В файле /template/frontend/имя_вашего_шаблона/main/main.php смотрим, есть ли функция __construct(). Если нет, то создаем ее внутри декларации class frontend_main extends SiteBill_Krascap {} в виде 

public function __construct(){
	parent::__construct();
	require SITEBILL_DOCUMENT_ROOT.'/template/frontend/'.$this->getConfigValue('theme').'/main/grid/local_grid_constructor.php';
	$this->_setGridConstructor(new Local_Grid_Constructor());
}

2. Переопределением метода в шаблоне (автоматическое) - устаревший

В файле /settings.php.ini добавляем секцию описания локального Конструктора списков

[GridConstructor]
path='/main/grid/local_grid_constructor.php'
name='Local_Grid_Constructor'

Первая строка - имя секции

вторая - путь к файлу локального Конструктора списка от корня шаблона

третья - задекларированное имя класса локального Конструктора списка

3. Настроечное переопределение - используйте, по возможности, именно этот вариант локализации

Указываем в Настройки  - Общее галочку Использовать локальный Конструктор списка (classic_local_grid)

Отличие последнего метода от остальных в том, что в нем имя класса конструктора и имя файла в котором он расположен должны быть соответственно Local_Grid_Constructor и template/frontend/имя_шаблона/grid/local_grid_constructor.php и никакими иначе.

=============================================================================================

Одним из этих способов мы указываем шаблону, что нужно использовать для построения списков наш измененный Конструктор списков. Но теперь нам необходимо создать его.

Для этого нам нужно создать файл по адресу указанному в require_once для первого способа, в path для второго и в /template/frontend/имя_шаблона/grid/local_grid_constructor.php для третьего.

Базовое наполнение этого файла будет иметь вид:

class Local_Grid_Constructor extends Grid_Constructor {

}

Уже после этого локальный КС будет работать, но так как он пока пуст, то он просто, как транслятор, будет передавать заказы в стандартный КС. Для того, что бы добавить что-то свое, нам нужно внести в него изменения.

1. Добавляем подхват текстового значения для поля типа select_by_query

Поскольку это операция трансформации из ключевого значения в текстовое, то нам понадобится функция transformGridData . Так как остальные параметры нам нужны и мы просто хотим добавить своего, то мы делаем свою функцию с вызовом родительской

public function transformGridData($ra, $_collect_user_info=false){
	$data=parent::transformGridData($ra, $_collect_user_info);/*используем "стандартный" вызов для выполнения привычных действий*/
	/*тут мы можем сделать что-то свое с данными*/
	return $data; /*возвращаемся в текущий процесс исполнения*/
}

Итак у нас в объявлении есть поле station_id связывающее объект с некоторой станцией из внешней таблицы station в которой станции разложены по строкам вида station_id, name. Так как в данных объявления при выборке мы имеем только ключ станции, а хотим получить именно ее имя и штатный трансформатор за нас этого не делает, то мы проиводим следующее

foreach($data as $k=>$d){
	if ( $d['station_id'] > 0 ) {
		$data[$k]['station'] = $data_model->get_string_value_by_id('station', 'station_id', 'name', $d['station_id'], true);
	}else{
		$data[$k]['station']='';
	}
}

Либо

$station_ids=array();
foreach($data as $k=>$d){
	$station_ids[intval($d['station_id'])]=intval($d['station_id']);
}

if(!empty($station_ids)){
	$DBC=DBC::getInstance();
	$query='SELECT `station_id`, `name` FROM '.DB_PREFIX.'_station WHERE station_id IN ('.implode(',', $station_ids).')';
	$stmt=$DBC->query($query);
	if($stmt){
		while($ar=$DBC->fetch($stmt)){
			$station_ids[$ar['station_id']]=$ar['name'];
		}
	}
}
foreach($data as $k=>$d){
	if(isset($station_ids[intval($d['station_id'])])){
		$data[$k]['station']=$station_ids[intval($d['station_id'])];
    }else{
    	$data[$k]['station']='';
    }
}

первый способ короче, но второй на больших количествах записей более продуктивен и более удобен, если нужно получить сложные названия текстового значения, например сцепить с названием станции еще и какой-то другой признак из свойств самой станции.

Для select_by_query второй вложенности, например если нужно получить имя застройщика, которое является свойством объекта ЖК, с которым связан объект, первый вариант уже не проходит. Т.е. использовать его конечно можно, но количество дополнительных действий сразу перекрывает сложность второго способа. Поэтому используем сразу второй.

$complex_ids=array();
foreach($data as $k=>$d){
	$complex_ids[intval($d['complex_id'])]=intval($d['complex_id']);
}

if(!empty($complex_ids)){
	$DBC=DBC::getInstance();
	$query='SELECT d.`name`, c.`complex_id` FROM '.DB_PREFIX.'_complex c LEFT JOIN '.DB_PREFIX.'_developer d USING (developer_id) WHERE complex_id IN ('.implode(',', $complex_ids).')';
	$stmt=$DBC->query($query);
	if($stmt){
		while($ar=$DBC->fetch($stmt)){
			$complex_ids[$ar['complex_id']]=$ar['name'];
		}
	}
}
foreach($data as $k=>$d){
	if(isset($complex_ids[intval($d['complex_id'])])){
		$data[$k]['developer']=$complex_ids[intval($d['complex_id'])];
    }else{
    	$data[$k]['developer']='';
    }
}

Очевидно, что принцип схожий и разница заключается только в мелочах вроде запроса на выборку связанного объекта. При чем, в зависимости от сложности желаемого к получению текстового значения будет меняться и сложность запроса, которая запросто может распасться на несколько.

В итоге наш локальный КС будет выглядеть таким образом:

<?php
class Local_Grid_Constructor extends Grid_Constructor {
	public function transformGridData($ra, $_collect_user_info=false){
		$data=parent::transformGridData($ra, $_collect_user_info);/*используем "стандартный" вызов для выполнения привычных действий*/
		/*тут мы можем сделать что-то свое с данными*/
		$complex_ids=array();
		foreach($data as $k=>$d){
			$complex_ids[intval($d['complex_id'])]=intval($d['complex_id']);
		}

		if(!empty($complex_ids)){
			$DBC=DBC::getInstance();
			$query='SELECT `complex_id` FROM '.DB_PREFIX.'_complex WHERE complex_id IN ('.implode(',', $station_ids).')';
			
			
			$query='SELECT d.`name`, c.`complex_id` FROM '.DB_PREFIX.'_complex c LEFT JOIN '.DB_PREFIX.'_developer d USING (developer_id) WHERE complex_id IN ('.implode(',', $complex_ids).')';
			$stmt=$DBC->query($query);
			if($stmt){
				while($ar=$DBC->fetch($stmt)){
					$complex_ids[$ar['complex_id']]=$ar['name'];
				}
			}
		}
		foreach($data as $k=>$d){
			if(isset($complex_ids[intval($d['complex_id'])])){
				$data[$k]['developer']=$station_ids[intval($d['complex_id'])];
			}else{
				$data[$k]['developer']='';
			}
		}
		
		return $data; /*возвращаемся в текущий процесс исполнения*/
	}
}

2. Получаем дату в красивом формате

Иногда нужно подготовить дату под вывод, что бы не мучаться с однотипными действиями в каждом шаблоне. Например подготовим дату добавления в виде "12 ноябра 2013 года".

public function transformGridData($ra, $_collect_user_info=false){
	$data=parent::transformGridData($ra, $_collect_user_info);
	$months=array(
			'1'=>'января',
			'2'=>'февраля',
			'3'=>'марта',
			'4'=>'апреля',
			'5'=>'мая',
			'6'=>'июня',
			'7'=>'июля',
			'8'=>'августа',
			'9'=>'сентября',
			'10'=>'октября',
			'11'=>'ноября',
			'12'=>'декабря',
		);
	foreach($data as $k=>$d){
		$month=date('n', $d['date_added']);
		$data[$k]['pretty_date']=date('j', $d['date_added']).' '.$months[date('n', $d['date_added'])].' '.$months[date('Y', $d['date_added'])];
	}
	return $data;
}

и в поле pretty_date в шаблоне у нас будет искомая строка

3. День добавления

Подготовим дату добавления, что бы она показывала было ли добавлено объявление сегодня, вчера или в другой день.

public function transformGridData($ra, $_collect_user_info=false){
	$data=parent::transformGridData($ra, $_collect_user_info);
	$now=date('dmY');
	$yesterday=date('dmY', time()-24*3600);
	foreach($data as $k=>$d){
		if($now==date('dmY', strtotime($d['date_added']))){
			$data[$k]['pretty_adddate']='сегодня';
		}elseif($yesterday==date('dmY', strtotime($d['date_added']))){
			$data[$k]['pretty_adddate']='вчера';
		}else{
			$data[$k]['pretty_adddate']=date('d.m.Y', strtotime($d['date_added']));
		}
	}
	return $data;
}

Этот вариант можно скомбинировать с предыдущим.

4. Форматирование адресной строки

Форматируем строку адреса для списка вида "Нижний Тагил (Заводской), Лермонтова, 12" [Город (Район), Улица, Дом]

protected function transformGridData($ra, $_collect_user_info=false){
	$data=parent::transformGridData($ra, $_collect_user_info);
	foreach($data as $k=>$d){
		$addrline=array();
		if($d['city']!=''){
			if($d['district']!=''){
				$addrline[]=$d['city'].' ('.$d['district'].')';
			}else{
				$addrline[]=$d['city'];
			}
		}
		if($d['street']!=''){
			$addrline[]=$d['street'];
			if($d['number']!=''){
				$addrline[]=$d['number'];
			}
		}
		if(!empty($addrline)){
			$data[$k]['pretty_address']=implode(', ', $addrline);
		}else{
			$data[$k]['pretty_address']='';
		}
	}
	return $data;
}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Добрый всем день! Сделал все как тут написано, но... не работает! в общем, не увидел самого главного, в какой форме потом добавлять строку? была у меня необходимость добавить справочник по датам сдачи. Сделал справочник, добавил новый параметр в поиск, но теперь в выводе результатов выходит идентификатор даты вместо "имени" даты. на страницах где используется similar - все просто. а вот grid_item уже кровь всю выпил. Так в какой форме его записывать, {$grid_item.deadline}? где deadline - имя справочника дат в data.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
11 минуту назад, diz2517 сказал:

{$grid_item.deadline} почему-то пишет без "i" в скобках

{$grid_items[i].deadline}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
3 минуты назад, diz2517 сказал:

так он мне выдает идентификатор.

так выполните 1 пункт написанный выше

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Цитата

<?php
class Local_Grid_Constructor extends Grid_Constructor {

    public function transformGridData($ra, $_collect_user_info=false){
    $data=parent::transformGridData($ra, $_collect_user_info);/*используем "стандартный" вызов для выполнения привычных действий*/
    /*тут мы можем сделать что-то свое с данными*/
    $date1_ids=array();
foreach($data as $k=>$d){
    $date1_ids[intval($d['deadline'])]=intval($d['deadline']);
}

if(!empty($date1_ids)){
    $DBC=DBC::getInstance();
    $query='SELECT `data_id`, `data333` FROM '.DB_PREFIX.'_station WHERE deadline IN ('.implode(',', $date1_ids).')';
    $stmt=$DBC->query($query);
    if($stmt){
        while($ar=$DBC->fetch($stmt)){
            $date1_ids[$ar['data_id']]=$ar['data333'];
        }
    }
}
foreach($data as $k=>$d){
    if(isset($date1_ids[intval($d['data_id'])])){
        $data[$k]['data333']=$date1_ids[intval($d['deadline'])];
    }else{
        $data[$k]['data333']='';
    }
}
    return $data; /*возвращаемся в текущий процесс исполнения*/
    }

}

вот мой локал грид

data111 - таблица для справочника

data_id - поле с идентификатором

data333 - поле с именем

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Цитата

[Settings]
estate_folder=
[GridConstructor]
path='/main/grid/local_grid_constructor.php'
name='Local_Grid_Constructor'

содержимое settings.ini.php

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

1. У вас версия system одна из последних? Или давно обновлялась?

2. Посмотрите в Настройки - core.listing есть ли там текстареа под именем "Список select_by_query-полей необходимых для подбора(core.listing.select_query_fields)" .

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В 31.10.2018 в 08:59, diz2517 сказал:

data111 - таблица для справочника

data_id - поле с идентификатором

data333 - поле с именем

я понял так:

есть отдельная таблица data111 в которой содержатся даты, ключ в этой таблице data_id, а варианты в data333.

в таблице объектов data есть поле deadline, которое указывает на один из упомянутых выше вариантов даты и это поле имеет тип select_by_query.

Верно?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В 31.10.2018 в 08:59, diz2517 сказал:

 $query='SELECT `data_id`, `data333` FROM '.DB_PREFIX.'_station WHERE deadline IN ('.implode(',', $date1_ids).')';

вот эта строка что-то мне не нравится. обычно с полями выбора из другой таблицы у нас есть таблица-источник, в которой есть поле-ключ и поле-значение. ну там может еще пару других, но они не имеют значения в контексте выбора вариантов. и в таблице, для кторой мы подключаем этот выбор, в качестве значения мы используем именно знначение-ключ. Т.е. если у вас таблица дат состоит из полей data_id, data333 где первое - это ключ, то все операции по выбору будут крутиться вокруг этих двух полей и самы важным будет именно поле-ключ. Почему у вас фигурирует еще и deadline поле из таблицы data111 - я пока не пойму.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В 01.11.2018 в 14:45, abushyk сказал:

я понял так:

есть отдельная таблица data111 в которой содержатся даты, ключ в этой таблице data_id, а варианты в data333.

в таблице объектов data есть поле deadline, которое указывает на один из упомянутых выше вариантов даты и это поле имеет тип select_by_query.

Верно?

да

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В 01.11.2018 в 14:54, abushyk сказал:

вот эта строка что-то мне не нравится. обычно с полями выбора из другой таблицы у нас есть таблица-источник, в которой есть поле-ключ и поле-значение. ну там может еще пару других, но они не имеют значения в контексте выбора вариантов. и в таблице, для кторой мы подключаем этот выбор, в качестве значения мы используем именно знначение-ключ. Т.е. если у вас таблица дат состоит из полей data_id, data333 где первое - это ключ, то все операции по выбору будут крутиться вокруг этих двух полей и самы важным будет именно поле-ключ. Почему у вас фигурирует еще и deadline поле из таблицы data111 - я пока не пойму.

потому что делал по аналогии как в начале этой темы, но не понял самого главного - суть этих элементов, какой за что отвечает. т.к. в примере поля-ключи имеют одинаковое название

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В 01.11.2018 в 14:54, abushyk сказал:

вот эта строка что-то мне не нравится. обычно с полями выбора из другой таблицы у нас есть таблица-источник, в которой есть поле-ключ и поле-значение. ну там может еще пару других, но они не имеют значения в контексте выбора вариантов. и в таблице, для кторой мы подключаем этот выбор, в качестве значения мы используем именно знначение-ключ. Т.е. если у вас таблица дат состоит из полей data_id, data333 где первое - это ключ, то все операции по выбору будут крутиться вокруг этих двух полей и самы важным будет именно поле-ключ. Почему у вас фигурирует еще и deadline поле из таблицы data111 - я пока не пойму.

так же уже после заметил что в этой строчке _station взята у меня из примера. изменил все на 

Цитата

$query='SELECT `deadline`, `data_name` FROM '.DB_PREFIX.'_data111 WHERE deadline IN ('.implode(',', $date1_ids).')';

не помогло..

 

изменил название поля data333 на более звучное data_name и теперь все выглядит вот так:

Цитата

<?php
class Local_Grid_Constructor extends Grid_Constructor {

    public function transformGridData($ra, $_collect_user_info=false){
    $data=parent::transformGridData($ra, $_collect_user_info);/*используем "стандартный" вызов для выполнения привычных действий*/
    /*тут мы можем сделать что-то свое с данными*/
    $date1_ids=array();
foreach($data as $k=>$d){
    $date1_ids[intval($d['deadline'])]=intval($d['deadline']);
}

if(!empty($date1_ids)){
    $DBC=DBC::getInstance();
    $query='SELECT `data_id`, `data_name` FROM '.DB_PREFIX.'_data111 WHERE data_id IN ('.implode(',', $date1_ids).')';
    $stmt=$DBC->query($query);
    if($stmt){
        while($ar=$DBC->fetch($stmt)){
            $date1_ids[$ar['data_id']]=$ar['data_name'];
        }
    }
}
foreach($data as $k=>$d){
    if(isset($date1_ids[intval($d['deadilne'])])){
        $data[$k]['data_name']=$date1_ids[intval($d['deadline'])];
    }else{
        $data[$k]['data111']='';
    }

/* foreach($data as $k=>$d){
    if ( $d['deadline'] > 0 ) {
        $data[$k]['data111'] = $data_model->get_string_value_by_id('data111', 'deadline', 'data_name', $d['deadline'], true);
    }else{
        $data[$k]['data111']='';
    }
}*/
    return $data; /*возвращаемся в текущий процесс исполнения*/
    }

}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В 01.11.2018 в 14:42, abushyk сказал:

1. У вас версия system одна из последних? Или давно обновлялась?

2. Посмотрите в Настройки - core.listing есть ли там текстареа под именем "Список select_by_query-полей необходимых для подбора(core.listing.select_query_fields)" .

все обновлено. ареа эта есть!)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В 01.11.2018 в 14:42, abushyk сказал:

1. У вас версия system одна из последних? Или давно обновлялась?

2. Посмотрите в Настройки - core.listing есть ли там текстареа под именем "Список select_by_query-полей необходимых для подбора(core.listing.select_query_fields)" .

сделал через core.listing! спасибо за наводку! значит local grid не нужен больше и его можно убрать?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Люди, пожалуйтса, тыкните пальцем где посмотреть как сделать чтобы мои даты можно было выбирать не по одному а сразу несколько? мультивыбор так сказать?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В 07.11.2018 в 15:11, diz2517 сказал:

Люди, пожалуйтса, тыкните пальцем где посмотреть как сделать чтобы мои даты можно было выбирать не по одному а сразу несколько? мультивыбор так сказать?

Можно прикрутить такой плагин для мультивыбора

http://plugindetector.com/ru/multiselect

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В 09.11.2018 в 15:22, rumantic сказал:

Можно прикрутить такой плагин для мультивыбора

http://plugindetector.com/ru/multiselect

 

к сожалению, совершенно непонятно как это дело прикрутить к имеющимся зарисовкам, да и вообще куда и как...

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
10 часов назад, diz2517 сказал:

к сожалению, совершенно непонятно как это дело прикрутить к имеющимся зарисовкам, да и вообще куда и как...

Может тогда фриланс?

https://www.sitebill.ru/s/forum/21-фриланс/

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте аккаунт или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!

Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас