SearchContext

Introduction

Manages searching of properties on one or more DataObject types, based on a given set of input parameters. SearchContext is intentionally decoupled from any controller-logic, it just receives a set of search parameters and an object class it acts on.

The default output of a SearchContext is either a SQLQuery object for further refinement, or a DataObjectSet that can be used to display search results, e.g. in a TableListField instance.

In case you need multiple contexts, consider namespacing your request parameters by using FieldSet→namespace() on the $fields constructor parameter.

SearchContext is mainly used by ModelAdmin, our generic data administration interface. Another implementation can be found in generic frontend search forms through genericviews.

Requirements

  • SilverStripe 2.3

Usage

Getting results

singleton('MyDataObject')->getDefaultSearchContext();

Defining fields on your DataObject

Customizing fields and filters

In this example we’re defining three attributes on our MyDataObject subclasss: PublicProperty, HiddenProperty and MyDate. The attribute HiddenProperty should not be searchable, and MyDate should only search for dates *after* the search entry (with a GreaterThanFilter). Similiar to the built-in DataObject→getDefaultSearchContext() method, we’re building our own getCustomSearchContext() variant.

class MyDataObject extends DataObject {
	static $db = array(
		'PublicProperty' => 'Text'
		'HiddenProperty' => 'Text',
		'MyDate' => 'Date'
	);
	
	public function getCustomSearchContext() {
		$fields = $this->scaffoldSearchFields(array(
			'restrictFields' => array('PublicProperty','MyDate')
		));
		$filters = array(
			'PublicProperty' => new PartialMatchFilter('PublicProperty'),
			'MyDate' => new GreaterThanFilter('MyDate')
		);
		return new SearchContext(
			$this->class, 
			$fields, 
			$filters
		);
	}
}

Generating a search form from the context

class Page_Controller extends ContentController {
	public function SearchForm() {
		$context = singleton('MyDataObject')->getCustomSearchContext();
		$fields = $context->getSearchFields();
		$form = new Form($this, "SearchForm",
			$fields,
			new FieldSet(
				new FormAction('doSearch')
			)
		);
		return $form;
	}
	public function doSearch($data, $form) {
		$context = singleton('MyDataObject')->getCustomSearchContext();
		$results = $context->getResults($data);
		return $this->customise(array(
			'Results' => $results
		))->renderWith('Page_results');
	}
}

For paginating records on multiple pages, you need to get the generated SQLQuery before firing off the actual search. This way we can set the “page limits” on the result through setPageLimits(), and only retrieve a fraction of the whole result set.

function getResults($searchCriteria = array()) {
	$start = ($this->request->getVar('start')) ? (int)$this->request->getVar('start') : 0;
	$limit = 10;
		
	$context = singleton('MyDataObject')->getCustomSearchContext();
	$query = $context->getQuery($searchCriteria, null, array('start'=>$start,'limit'=>$limit));
	$records = $context->getResults($searchCriteria, null, array('start'=>$start,'limit'=>$limit));
	if($records) {
		$records->setPageLimits($start, $limit, $query->unlimitedRowCount());
	}
		
	return $records;
}

notice that if you want to use this getResults function, you need to change the function doSearch for this one:

public function doSearch($data, $form) {
	$context = singleton('MyDataObject')->getCustomSearchContext();
	$results = $this->getResults($data);
	return $this->customise(array(
		'Results' => $results
	))->renderWith(array('Catalogo_results', 'Page'));
}

The change is in $results = $this→getResults($data);, because you are using a custom getResults function.

Another thing you cant forget is to check the name of the singleton you are using in your project. the example uses MyDataObject, you need to change it for the one you are using

For more information on how to paginate your results within the template, see Tutorial: Site Search.

The Pagination Template

to show the results of your custom search you need at least this content in your template, notice that Results.PaginationSummary(4) defines how many pages the search will show in the search results. something like:

Next 1 2 3 4 5 … 558

<% if Results %>
	<ul>
		<% control Results %>
			<li>$Titulo, $Autor</li>
		<% end_control %>
	</ul>
<% else %>
	<p>Sorry, your search query did not return any results.</p>
<% end_if %>
 
<% if Results.MoreThanOnePage %>
	<div id="PageNumbers">
		<p>
			<% if Results.NotFirstPage %>
				<a class="prev" href="$Results.PrevLink" title="View the previous page">Prev</a>
			<% end_if %>
		
			<span>
		    		<% control Results.PaginationSummary(4) %>
					<% if CurrentBool %>
						$PageNum
					<% else %>
						<% if Link %>
							<a href="$Link" title="View page number $PageNum">$PageNum</a>
						<% else %>
							&hellip;
						<% end_if %>
					<% end_if %>
				<% end_control %>
			</span>
		
			<% if Results.NotLastPage %>
				<a class="next" href="$Results.NextLink" title="View the next page">Next</a>
			<% end_if %>
		</p>
	</div>
<% end_if %>

Available SearchFilters

  • EndsWithFilter: Matches textual content with a substring match on a text fragment leading to the end of the string.
  • ExactMatchFilter: Selects textual content with an exact match between columnname and keyword.
  • ExactMatchMultiFilter: Checks if a value is in a given set. SQL syntax used: Column IN (’val1’,’val2’)
  • FulltextFilter: Filters by full-text matching on the given field. Full-text indexes are only available with MyISAM tables. The following column types are supported: Char, Varchar, Text. To enable full-text matching on fields, you also need to add an index to the database table, using the {$indexes} hash in your DataObject subclass.
  • GreaterThanFilter: Selects numerical/date content greater than the input
  • LessThanFilter: Selects numerical/date content smaller than the input
  • NegationFilter: Matches on rows where the field is not equal to the given value.
  • PartialMatchFilter: Matches textual content with a LIKE ‘%keyword%’ construct.
  • StartsWithFilter: Matches textual content with a substring match from the beginning of the string.
  • StartsWithMultiFilter: Checks if a value starts with one of the items of in a given set. SQL syntax used: Column IN (’val1’,’val2’)
  • SubstringFilter: Uses a substring match against content in column rows.
  • WithinRangeFilter: Incomplete

API Documentation

Related

 
searchcontext.txt · Last modified: 2009/09/01 14:15 by ezero

Please use comments for notes, tips and corrections about the described functionality.
Use the Silverstripe Forum to ask questions.

blog comments powered by Disqus
 
Creative Commons LicenseSilverStripe Documentation by SilverStripe is licensed under a Creative Commons Attribution 3.0 New Zealand License.
Based on a work at doc.silverstripe.com
Recent changes RSS feed Driven by DokuWiki