Фильтрация по диапазону дат в mFilter2

09 Февраля 2021
php

Задача: создание календаря(datepicker) с диапазоном дат, фильтрация мероприятий вошедших в диапазон выбранных дат по двум параметрам: 1 - ежедневность 2 - конкретная дата мероприятия.

НЕОБХОДИМО

  1. Приложения
    • pdoResources
    • msearch2
  2. Дополнительное поле(в дальнейшем 35) - ежедневность
    • Наименование -> every_day
    • Тип ввода -> списка (множественный выбор)
    • Возможные значения -> Понедельник==1||Вторник==2||Среда==3||Четверг==4||Пятница==5||Суббота==6||Воскресенье==7
  3. Дополнительное поле(в дальнейшем 36) - конкретная дата мероприятия
    • Наименование -> everyday_date
    • Тип ввода -> Текст
    • В этой тв пользователь указывает определенные даты в которые идет мероприятие, например: 11.12.2017,14.12.2017
НАЧАЛО

Создаём собственный фильтр:

  1. [[!mFilter2?
    	&element=`pdoResources`
    	&tpl=`tpl_chunk`                        // Чанк оформления всего блока фильтров и результатов.
    	&parents=`[[*id]]`                      // Список категорий, через запятую, для ограничения вывода результатов.
    	&limit=`999`                            // Лимиты
    	&depth=`0`                              // Глубина поиска
    	&filters=`tv|everyday_date:Everyday`    // Список фильтров ресурсов, через запятую. 
    	&includeTVs=`everyday_date`             // Список ТВ параметров для выборки, через запятую.
    	&sort=`resource|menuindex:asc`          // Сортировка.
    	&tplFilter.outer.tv|everyday_date=`tpl.mFilter2.filter.outer`	// Стандартный чанк оформления одной группы фильтров.
    	&tplFilter.row.tv|everyday_date=`tpl.mFilter2.filter.date`      // Стандартный чанк оформления одного фильтра в группе.
    ]]
    
  2. Указываем в настройках, в параметре mse2_filters_handler_class значение custom_filters

  3. Создаем чанк для вывода календаря tpl.mFilter2.filter.date

    <input type="hidden" name="[[+filter_key]]" id="mse2_[[+idx]]" value="[[+value]]" />
    // блок календаря
    <div id="[[+idx]]_datepicker"></div>
    
    // стилизация календаря
    <link rel="stylesheet" href="//jquery-ui-bootstrap.github.io/jquery-ui-bootstrap/css/custom-theme/jquery-ui-1.10.3.custom.css"/>
    <style>
        .ui-datepicker .selected-start:not(.selected-end) a,
        .ui-datepicker .selected-end:not(.selected-start) a {
            background: #F3FDD5;
        }
        .ui-datepicker .selected.first-of-month:not(.selected-start) a {
            border-left: 2px dotted #D4E7F6;
            padding-left: 1px;
        }
    </style>
    <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
    <script src="https://rawgit.com/Artemeey/5ebc39370e568c34f03dce1639cabee8/raw/8de40b26479c406ee9cd6f9b4b3f4ad05370a024/jquery.datepicker.extension.range.min.js"></script>
    <script type="text/javascript">
        $(function() {
    		// переводим календарь на русский язык
            $.datepicker.regional['ru'] = {
                closeText: 'Закрыть',
                prevText: '<Пред',
                nextText: 'След>',
                currentText: 'Сегодня',
                monthNames: ['Январь','Февраль','Март','Апрель','Май','Июнь',
                'Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'],
                monthNamesShort: ['Янв','Фев','Мар','Апр','Май','Июн',
                'Июл','Авг','Сен','Окт','Ноя','Дек'],
                dayNames: ['воскресенье','понедельник','вторник','среда','четверг','пятница','суббота'],
                dayNamesShort: ['вск','пнд','втр','срд','чтв','птн','сбт'],
                dayNamesMin: ['Вс','Пн','Вт','Ср','Чт','Пт','Сб'],
                dateFormat: 'yy-mm-dd',
                firstDay: 1,
                isRTL: false
            };
            $.datepicker.setDefaults($.datepicker.regional['ru']);
    		// при клике устанавливаем период
            $("#[[+idx]]_datepicker").datepicker({
                range:'period',
                onSelect:function(dateText,inst,extensionRange){
    				// записываем диапазон через _ пример: 11.12.2017_14.12.2017
                    var date=extensionRange.startDateText+"_"+extensionRange.endDateText;
    				// записываем в инпут
                    $('#mse2_[[+idx]]').val(date);
    				// обновляем фильтр
                    mSearch2.load();
                }
            });
        });
    </script>
    
  4. Создаём файл custom.class.php по пути core/components/msearch2/custom/filters/custom.class.php

    class custom_filters extends mse2FiltersHandler {
    	
    	// эта функция обязательна, она работает в паре с filterEveryday
    	public function buildEverydayFilter(array $values, $name = '', $format = 'Y-m-d', $sort = 'desc'){
    		return $this->buildDateFilter($values, $name,$format,$sort);
    	}
    	
    	
    	// В этой функции и происходит магия, в данном примере будут показываться те ресурсы, у которых в 35 тв указана ежедневность мероприятия, а в 36 тв дата мероприятия, например: указав диапазон 11.12.2017_14.12.2017 покажутся все ресурсы у которых в 36 тв есть любая дата в диапазоне 11.12.2017_14.12.2017 или те ресурсы у которых в 35 тв выбраны любой день недели в диапазоне от ПН до ЧТ(Соответствует датам 11.12.2017-14.12.2017)
    	public function filterEveryday(array $requested, array $values, array $ids, $format = 'Y-m-d'){
    		$array=array();
    		
    	// парсим даты в формате Y-m-d_Y-m-d
    		$array_date_search=explode('_',$requested[0]);
    		$date_search=$array_date_search[0];
    		$requested[0]=$date_search;
    
    	// формируем массив дней недель выбранного диапазона дат- $array_week
    		$array_week=array();
    		$days=(strtotime($array_date_search[1])-strtotime($array_date_search[0]))/(60*60*24);
    		$dweek_search_n=date('N',strtotime($array_date_search[0]));
    		for($i=0;$i<7;$i++){
    			if($i>$days){
    				break;
    			}
    			$array_week[]=$dweek_search_n;
    			$dweek_search_n++;
    			if($dweek_search_n>7){
    				$dweek_search_n=1;
    			}
    		}
    		
    	// формируем массив дат в заданом диапазоне - $array_days
    		$start  =new DateTime($array_date_search[0]);
    		$end    =new DateTime($array_date_search[1]);
    		$step   =new DateInterval('P1D');
    		$period =new DatePeriod($start, $step, $end);
    		foreach($period as $datetime) {
    			$array_days[]=$datetime->format("Y-m-d");
    		}
    		$array_days[]=$start->format("Y-m-d");
    		$array_days[]=$end->format("Y-m-d");
    
    	// получаем ид ресурсов подходящих нашей выборке
    		$sql="
    			SELECT t1.id, t2.value AS t2_value, t3.value AS t3_value 
    			FROM `modx_site_content` AS `t1` 
    			LEFT JOIN `modx_site_tmplvar_contentvalues` `t2` ON t2.contentid = t1.id AND t2.tmplvarid = 35 
    			LEFT JOIN `modx_site_tmplvar_contentvalues` `t3` ON t3.contentid = t1.id AND t3.tmplvarid = 36 
    			WHERE (
    				`t1`.`id` IN (".implode(",",$ids).")
    			)
    		";
    		foreach($this->modx->query($sql) as $row){
    		// ищем совпадения в двух массивах по дню недели
    			$t2_value_array=explode('||',$row['t2_value']);
    			$t2_value_intersect=array_intersect($array_week,$t2_value_array);
    			if(count($t2_value_intersect)>0){
    				$array[$date_search][]=$row['id'];
    			}else{
    			// ищем совпадения в двух массивах по дате
    				$t3_value_array=explode(',',$row['t3_value']);
    				$t3_value_intersect=array_intersect($array_days,$t3_value_array);
    				if(count($t3_value_intersect)>0){
    					$array[$date_search][]=$row['id'];
    				}
    			}
    		}
    
    		if(count($array_date_search)==1){
    			foreach ($values as $k => $v){
    				foreach ($v as $k_d => $v_d){
    					$array[$requested[0]][]=$v_d;
    				}
    			}
    		}
    		return $this->filterDefault($requested, $array, $ids);
    	}
    }
    

Пример: http://piterguide.ru/ekskursii/sbornyie/sbornyie-tematicheskie-ekskursii/