AgelxNash/DocLister

Grouping by months

Closed this issue · 8 comments

pmfx commented

Question: is it possible to group list by months?

Details: I have a list of future events that I would like to be grouped by months so it would look like this:

January
- Event 1 title
- Event 2 title
- Event 3 title
February
- Event 4 title
- Event 5 title
August
- Event 6 title
- Event 7 title

Is it possible with DocLister?

Resources are using template variables: event_date_start, event_date_end

pmfx commented

Thanks, but could you please give here an example of a call of DLReflect and DLReflectFilter to get the result I need?

Give more information about your task

pmfx commented

I have a list of future events that I would like to be grouped by months.

Right now it is just a simple list (DocLister) with future events outputed like this:

Event 1 (March 15)
Event 2 (March 21)
Event 3 (June 18)

I need it like this:

March:
Event 1 (March 15)
Event 2 (March 21)

June:
Event 3 (June 18)

More information:

I use two template variables
event_date_start event_date_end.

To filter out past events I use this:
$params['filters'] = 'AND(tvdate:event_date_end:>:'.$current_date.')';

You should't use only a month for filtering.

  • December 2017
  • January 2018
  • December 2018

DLReflect will build a month + year list.
DLReflectFilter will filter documents by month + year.
To build one list, you need a snippet that combines the functional DLReflect + DLReflectFilter

Wait for the news. I will do it specifically for you :-)

pmfx commented

Thanks @AgelxNash, really appreciate it.

<?php
$months = $modx->runSnippet('DocLister', array(
	'tvList'		=> 'event_date_start',
	'orderBy'		=> 'event_date_start ASC',
	'saveDLObject'	=> 'DLAPI',
	'api'			=> 'id',
	'tvSortType'	=> 'TVDATETIME',
	'addWhereList'	=> "STR_TO_DATE(`dltv_event_date_start_1`.`value`,'%d-%m-%Y %H:%i:%s') >= now()",
	'selectFields'	=> "DATE_FORMAT(STR_TO_DATE(`dltv_event_date_start_1`.`value`,'%d-%m-%Y %H:%i:%s'), '%m-%Y') as `id`"
));
$months = json_decode($months, true);

if (is_null($months)) $months = array();
$months = new DLCollection($modx, $months);
/**
 * Filtering and sorting with PHP
 * Not necessary!!!
 */
// <FilterAndSort>
$months->filter(function ($el) {
    return !empty($el['id']);
})->filter(function($el) {
	$aDate = DateTime::createFromFormat('m-Y', $el['id']);
    return $aDate->getTimestamp() >= time();
})->sort(function ($a, $b) use ($dateFormat) {
    $aDate = DateTime::createFromFormat('m-Y', $a['id']);
    $bDate = DateTime::createFromFormat('m-Y', $b['id']);
    return $aDate->getTimestamp() - $bDate->getTimestamp();
})->reindex()->unique();
// </FilterAndSort>

$DLAPI = $modx->getPlaceholder('DLAPI');
$DLAPI->loadLang('months');
$out = '';
foreach($months	 as $item){
	list($vMonth, $vYear) = explode('-', $item['id'], 2);
	$filter = "STR_TO_DATE(`dltv_event_date_start_1`.`value`,'%d-%m-%Y %H:%i:%s') >= NOW() AND
				DATE_FORMAT(STR_TO_DATE(`dltv_event_date_start_1`.`value`,'%d-%m-%Y %H:%i:%s'), '%m-%Y') ='".$item['id']."'";
	$docs = $modx->runSnippet('DocLister', array(
    	'tvList'		=> 'event_date_start',
		'orderBy'		=> 'event_date_start ASC',
		'tvSortType'	=> 'TVDATETIME',
		'addWhereList'	=> $filter,
		'tpl'			=> '@CODE: <li>[+title+]</li>',
		'ownerTPL'		=> '@CODE: <ul>[+dl.wrap+]</ul>'
	));

	$data = array(
		'monthNum'	=> $vMonth,
        'monthName'	=> $DLAPI->getMsg('months.' . (int)$vMonth),
        'year'		=> $vYear,
        'docs'		=> $docs
	);
	$out .= $DLAPI->parseChunk('@CODE: <li>[+monthName+] ([+monthNum+]) [+year+] [+docs+]</li>', $data);
}
if(!empty($out)){
	$out = $DLAPI->parseChunk('@CODE: <ul>[+out+]</ul>', compact('out'));
}else{
	$out = 'N\A';
}
return $out;

This example can form many nested calls to the DocLister. You can optimize using only 2 calls DocLister calls and DLCollection filtering.

pmfx commented

That's perfect! Exactly what I needed and works great. Thank you for your effort! I owe you a 🍺