Building complex filters with predefined filters in pt_extlist

For a current project, I needed to create a more complex filter like the one below:

Normally I would tell anybody asking me to write a filter class for this problem and solve it by implementing a special filter. But since I did not use pt_extlist's standard controller here but my own controller, I came up with another idea: mixing existing filters in my own template.

First of all, you set up you filter configuration in your TypoScript configuration as usual:

filters {

	registrationAdminFilters {

		filterConfigs {

			## Username filter
			10 < plugin.tx_ptextlist.prototype.filter.string
			10 {
				filterClassName = Tx_JdavSv_Extlist_Filters_RegistrationsByUsernameAdminFilter
				filterIdentifier = userFilter
				label = Name
				fieldIdentifier = attendee
			}

			## Event filter
			20 < plugin.tx_ptextlist.prototype.filter.string
			20 {
				filterClassName = Tx_JdavSv_Extlist_Filters_RegistrationsByEventAdminFilter
				filterIdentifier = eventFilter
				label = Veranstaltung
				fieldIdentifier = event
			}

			## Date filter
			30 < plugin.tx_ptextlist.prototype.filter.dateRange
			30 {
				fieldIdentifier = date
				filterIdentifier = dateFilter
			}

		}

	}

}

Within my controller / action, I use extlist context as described in my previous article and assign the filters to my view / template:

/**
 * Displays all Registrations
 *
 * @return string The rendered list view
 */
public function listAction() {
	$extlistContext = Tx_PtExtlist_ExtlistContext_ExtlistContextFactory::getContextByCustomConfiguration(
		$this->settings['listConfig']['registrationsAdmin'], 'registrationsAdmin'
	);

	$this->view->assign('listData', $extlistContext->getListData());
	$this->view->assign('listHeader', $extlistContext->getList()->getListHeader());
	$this->view->assign('listCaptions', $extlistContext->getRendererChain()
		->renderCaptions($extlistContext->getList()->getListHeader()));
	$this->view->assign('pager', $extlistContext->getPager());
	$this->view->assign('pagerCollection', $extlistContext->getPagerCollection());
	$this->view->assign('eventFilter', $extlistContext->getFilterBoxCollection()
		->getFilterboxByFilterboxIdentifier('registrationAdminFilters')->getFilterByFilterIdentifier('eventFilter'));
	$this->view->assign('dateFilter', $extlistContext->getFilterBoxCollection()
		->getFilterboxByFilterboxIdentifier('registrationAdminFilters')->getFilterByFilterIdentifier('dateFilter'));
	$this->view->assign('userFilter', $extlistContext->getFilterBoxCollection()
		->getFilterboxByFilterboxIdentifier('registrationAdminFilters')->getFilterByFilterIdentifier('userFilter'));
}

Now comes the "tricky part": Using the right form elements within your template:

<f:form class="well form-inline" controller="RegistrationAdmin" action="list">
	<strong>Filter</strong>
	<table>
		<tr>
			<td>
				<span>Teilnehmername:</span><br>
				<f:form.textfield class="span3" id="{userFilter.filterIdentifier}" property="filterValue"
								  value="{userFilter.filterValue}"
								  name="{extlist:namespace.FormElementName(object:'{userFilter}' property:'filterValue')}"
								  size="{userFilter.filterConfig.settings.size}"
								  maxlength="{userFilter.filterConfig.settings.maxLength}"/>
				&nbsp;
			</td>
			<td>
				<span>Veranstaltung:</span><br>
				<ptextbase:form.select class="span4" id="{eventFilter.filterIdentifier}" property="filterValue"
								  value="{eventFilter.filterValue}"
								  name="{extlist:namespace.FormElementName(object:'{eventFilter}' property:'filterValue')}"
								  options="{eventFilter.events}"
								  optionValueField="uid"
								  optionLabelField="fullName"
								  emptyOption="[Keine Veranstaltung gewählt]"
						/>
				&nbsp;
			</td>
			<td>
				<span>von:</span><br>
				<f:form.textfield class="span2" id="{dateFilter.filterIdentifier}From" property="filterValueFrom"
								  value="{dateFilter.filterValueFrom ->f:format.date(format: 'd.m.Y')}"
								  name="{extlist:namespace.FormElementName(object:'{dateFilter}' property:'filterValueFrom')}" />
				&nbsp;
			</td>
			<td>
				<span>bis:</span><br>
				<f:form.textfield class="span2" id="{dateFilter.filterIdentifier}to" property="filterValueTo"
								  value="{dateFilter.filterValueTo -> f:format.date(format:'d.m.Y')}"
								  name="{extlist:namespace.FormElementName(object:'{dateFilter}' property:'filterValueTo')}" />
				&nbsp;
			</td>
			<td>
				<span>&nbsp;</span><br>
				<f:form.submit class="btn btn-primary" value="Filter anwenden"/>
				&nbsp;
				<f:link.action class="btn btn-primary" action="list" arguments="{restFilters: 1}"><i
						class="icon-white icon-remove"></i> Filter zurücksetzen
				</f:link.action>
			</td>
		</tr>
	</table>
</f:form>

Make sure to have pt_extlist's ViewHelper namespace included via {namespace extlist=Tx_PtExtlist_ViewHelpers} at the beginning of your template!

So what happens here. There are 3 filters passed to our template:

 

  • userFilter, accessed by {userFilter.<property>}
  • eventFilter, accessed by {eventFilter.<property>}
  • dateFilter, accessed by {dateFilter.<property>}

Filter values can be accessed via {<filterName>.filterValue} on single value filters (name and event) and via {dateFilter.filterValueFrom} and {dateFilter.filterValueTo} on the date filter.

To enable pt_extlist to automatically map your form data on the filter objects, some conventions need to hold:

 

  1. The name of the input field must match pt_extlist's namespace for GP-Vars. This can be achieved by using pt_extlist's namespace ViewHelper: name="{extlist:namespace.FormElementName(object:'{eventFilter}' property:'filterValue')}"
  2. The property name of the input field must match the filterValue property of the filter object: property="filterValue" on userName and eventFilter, property="filterValueTo" and property="filterValueFrom" on dateFilter
  3. The value for the input field can be taken from the filter object's property directly via value="{userFilter.filterValue}". Mind the usage of the inline ViewHelper for rendering date formats on the dateFilter: value="{dateFilter.filterValueFrom ->f:format.date(format: 'd.m.Y')}"

So - that's it. As you can see, a complex filter can be combined out of simple, already available filters by simply putting them together within your template.


 
Inhalt © Michael Knoll 2009-2017  •  Powered by TYPO3  •  TypoScript Blogging by Fabrizio Branca  •  TYPO3 Photo Gallery Management by yag  •  Impressum