2014-10-28 06:42:27 +01:00
title: Scaffolding with SearchContext
summary: Configure the search form within ModelAdmin using the SearchContext class.
2011-02-07 07:48:44 +01:00
2014-10-28 06:42:27 +01:00
# SearchContext
2011-02-07 07:48:44 +01:00
2017-07-03 03:22:12 +02:00
[SearchContext ](api:SilverStripe\ORM\Search\SearchContext ) manages searching of properties on one or more [DataObject ](api:SilverStripe\ORM\DataObject ) types, based on a given set of
input parameters. [SearchContext ](api:SilverStripe\ORM\Search\SearchContext ) is intentionally decoupled from any controller-logic, it just receives a set of
2014-10-28 06:42:27 +01:00
search parameters and an object class it acts on.
2011-02-07 07:48:44 +01:00
2017-07-03 03:22:12 +02:00
The default output of a [SearchContext ](api:SilverStripe\ORM\Search\SearchContext ) is either a [SQLSelect ](api:SilverStripe\ORM\Queries\SQLSelect ) object for further refinement, or a
[DataObject ](api:SilverStripe\ORM\DataObject ) instance.
2011-02-07 07:48:44 +01:00
2014-10-28 06:42:27 +01:00
< div class = "notice" markdown = "1" >
2017-07-03 03:22:12 +02:00
[SearchContext ](api:SilverStripe\ORM\Search\SearchContext ) is mainly used by [ModelAdmin ](/developer_guides/customising_the_admin_interface/modeladmin ).
2014-10-28 06:42:27 +01:00
< / div >
2011-02-07 07:48:44 +01:00
## Usage
2014-10-28 06:42:27 +01:00
Defining search-able fields on your DataObject.
2011-02-07 07:48:44 +01:00
2017-08-03 02:51:32 +02:00
```php
2017-08-03 05:35:09 +02:00
2014-10-28 06:42:27 +01:00
class MyDataObject extends DataObject {
2011-02-07 07:48:44 +01:00
2017-08-03 05:35:09 +02:00
private static $searchable_fields = [
2014-10-28 06:42:27 +01:00
'Name',
'ProductCode'
2017-08-03 05:35:09 +02:00
];
2014-10-28 06:42:27 +01:00
}
2017-08-03 05:35:09 +02:00
2017-08-03 02:51:32 +02:00
```
2011-02-07 07:48:44 +01:00
2014-10-28 06:42:27 +01:00
## Customizing fields and filters
2011-02-07 07:48:44 +01:00
2011-03-08 22:05:51 +01:00
In this example we're defining three attributes on our MyDataObject subclass: `PublicProperty` , `HiddenProperty`
2011-02-07 07:48:44 +01:00
and `MyDate` . The attribute `HiddenProperty` should not be searchable, and `MyDate` should only search for dates
2014-10-28 06:42:27 +01:00
*after* the search entry (with a `GreaterThanFilter` ).
2011-02-07 07:48:44 +01:00
2017-08-03 02:51:32 +02:00
```php
2017-08-03 05:35:09 +02:00
2011-02-07 07:48:44 +01:00
class MyDataObject extends DataObject {
2014-10-28 06:42:27 +01:00
2017-08-03 05:35:09 +02:00
private static $db = [
2011-02-07 07:48:44 +01:00
'PublicProperty' => 'Text'
'HiddenProperty' => 'Text',
'MyDate' => 'Date'
2017-08-03 05:35:09 +02:00
];
2011-02-07 07:48:44 +01:00
2016-05-24 03:25:02 +02:00
public function getDefaultSearchContext() {
2017-08-03 05:35:09 +02:00
$fields = $this->scaffoldSearchFields([
'restrictFields' => ['PublicProperty','MyDate']
]);
2014-10-28 06:42:27 +01:00
2017-08-03 05:35:09 +02:00
$filters = [
2011-02-07 07:48:44 +01:00
'PublicProperty' => new PartialMatchFilter('PublicProperty'),
'MyDate' => new GreaterThanFilter('MyDate')
2017-08-03 05:35:09 +02:00
];
2014-10-28 06:42:27 +01:00
2011-02-07 07:48:44 +01:00
return new SearchContext(
$this->class,
$fields,
$filters
);
}
}
2017-08-03 05:35:09 +02:00
2017-08-03 02:51:32 +02:00
```
2011-02-07 07:48:44 +01:00
2014-10-28 06:42:27 +01:00
< div class = "notice" markdown = "1" >
See the [SearchFilter ](../model/searchfilters ) documentation for more information about filters to use such as the
`GreaterThanFilter` .
< / div >
< div class = "notice" markdown = "1" >
In case you need multiple contexts, consider name-spacing your request parameters by using `FieldList->namespace()` on
the `$fields` constructor parameter.
< / div >
2011-02-07 07:48:44 +01:00
### Generating a search form from the context
2017-08-03 02:51:32 +02:00
```php
2017-08-03 05:35:09 +02:00
2016-12-30 00:17:15 +01:00
// ..
2014-10-28 06:42:27 +01:00
2016-12-30 00:17:15 +01:00
class PageController extends ContentController {
2014-10-28 06:42:27 +01:00
2011-02-07 07:48:44 +01:00
public function SearchForm() {
$context = singleton('MyDataObject')->getCustomSearchContext();
$fields = $context->getSearchFields();
2014-10-28 06:42:27 +01:00
2011-02-07 07:48:44 +01:00
$form = new Form($this, "SearchForm",
$fields,
2011-10-28 03:37:27 +02:00
new FieldList(
2011-02-07 07:48:44 +01:00
new FormAction('doSearch')
)
);
2014-10-28 06:42:27 +01:00
2011-02-07 07:48:44 +01:00
return $form;
}
2014-10-28 06:42:27 +01:00
2011-02-07 07:48:44 +01:00
public function doSearch($data, $form) {
$context = singleton('MyDataObject')->getCustomSearchContext();
$results = $context->getResults($data);
2014-10-28 06:42:27 +01:00
2017-08-03 05:35:09 +02:00
return $this->customise([
2011-02-07 07:48:44 +01:00
'Results' => $results
2017-08-03 05:35:09 +02:00
])->renderWith('Page_results');
2011-02-07 07:48:44 +01:00
}
}
2017-08-03 05:35:09 +02:00
2017-08-03 02:51:32 +02:00
```
2011-02-07 07:48:44 +01:00
### Pagination
2011-03-31 03:01:04 +02:00
For pagination records on multiple pages, you need to wrap the results in a
2015-07-31 07:18:49 +02:00
`PaginatedList` object. This object is also passed the generated `SQLSelect`
2011-03-31 03:01:04 +02:00
in order to read page limit information. It is also passed the current
2016-09-09 08:43:05 +02:00
`HTTPRequest` object so it can read the current page from a GET var.
2011-02-07 07:48:44 +01:00
2017-08-03 02:51:32 +02:00
```php
2017-08-03 05:35:09 +02:00
public function getResults($searchCriteria = []) {
2015-04-30 01:04:08 +02:00
$start = ($this->getRequest()->getVar('start')) ? (int)$this->getRequest()->getVar('start') : 0;
2011-02-07 07:48:44 +01:00
$limit = 10;
$context = singleton('MyDataObject')->getCustomSearchContext();
2017-08-03 05:35:09 +02:00
$query = $context->getQuery($searchCriteria, null, ['start'=>$start,'limit'=>$limit]);
$records = $context->getResults($searchCriteria, null, ['start'=>$start,'limit'=>$limit]);
2011-03-31 03:01:04 +02:00
2011-02-07 07:48:44 +01:00
if($records) {
2015-04-30 01:04:08 +02:00
$records = new PaginatedList($records, $this->getRequest());
2011-03-31 03:01:04 +02:00
$records->setPageStart($start);
2013-12-06 03:45:38 +01:00
$records->setPageLength($limit);
$records->setTotalItems($query->unlimitedRowCount());
2011-02-07 07:48:44 +01:00
}
2011-03-31 03:01:04 +02:00
2011-02-07 07:48:44 +01:00
return $records;
}
2017-08-03 05:35:09 +02:00
2017-08-03 02:51:32 +02:00
```
2011-02-07 07:48:44 +01:00
notice that if you want to use this getResults function, you need to change the function doSearch for this one:
2017-08-03 02:51:32 +02:00
```php
2011-02-07 07:48:44 +01:00
public function doSearch($data, $form) {
$context = singleton('MyDataObject')->getCustomSearchContext();
$results = $this->getResults($data);
2017-08-03 05:35:09 +02:00
return $this->customise([
2011-02-07 07:48:44 +01:00
'Results' => $results
2017-08-03 05:35:09 +02:00
])->renderWith(['Catalogo_results', 'Page']);
2011-02-07 07:48:44 +01:00
}
2017-08-03 05:35:09 +02:00
2017-08-03 02:51:32 +02:00
```
2011-02-07 07:48:44 +01:00
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 ](/tutorials/4-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:
2014-09-15 21:44:03 +02:00
**Next 1 2 *3* 4 5 … 558**
2017-08-03 02:51:32 +02:00
```ss
2011-02-07 07:48:44 +01:00
2013-04-26 11:48:59 +02:00
< % if $Results %>
2011-02-07 07:48:44 +01:00
< ul >
2013-04-26 11:48:59 +02:00
< % loop $Results %>
2012-06-26 17:32:46 +02:00
< li > $Title, $Autor< / li >
< % end_loop %>
2011-02-07 07:48:44 +01:00
< / ul >
< % else %>
< p > Sorry, your search query did not return any results.< / p >
< % end_if %>
2013-04-26 11:48:59 +02:00
< % if $Results.MoreThanOnePage %>
2011-02-07 07:48:44 +01:00
< div id = "PageNumbers" >
< p >
2013-04-26 11:48:59 +02:00
< % if $Results.NotFirstPage %>
2011-02-07 07:48:44 +01:00
< a class = "prev" href = "$Results.PrevLink" title = "View the previous page" > Prev< / a >
< % end_if %>
< span >
2013-04-26 11:48:59 +02:00
< % loop $Results.PaginationSummary(4) %>
< % if $CurrentBool %>
2011-02-07 07:48:44 +01:00
$PageNum
< % else %>
2013-04-26 11:48:59 +02:00
< % if $Link %>
2011-02-07 07:48:44 +01:00
< a href = "$Link" title = "View page number $PageNum" > $PageNum< / a >
< % else %>
…
< % end_if %>
< % end_if %>
2012-06-26 17:32:46 +02:00
< % end_loop %>
2011-02-07 07:48:44 +01:00
< / span >
2013-04-26 11:48:59 +02:00
< % if $Results.NotLastPage %>
2011-02-07 07:48:44 +01:00
< a class = "next" href = "$Results.NextLink" title = "View the next page" > Next< / a >
< % end_if %>
< / p >
< / div >
< % end_if %>
2017-08-03 02:51:32 +02:00
```
2011-02-07 07:48:44 +01:00
## Available SearchFilters
2017-07-03 03:22:12 +02:00
See [SearchFilter ](api:SilverStripe\ORM\Filters\SearchFilter ) API Documentation
2011-02-07 07:48:44 +01:00
2014-10-28 06:42:27 +01:00
## Related Documentation
2016-01-14 11:59:53 +01:00
* [ModelAdmin ](/developer_guides/customising_the_admin_interface/modeladmin )
* [Site Search ](/tutorials/site_search )
2014-10-28 06:42:27 +01:00
2011-02-07 07:48:44 +01:00
## API Documentation
2017-07-03 03:22:12 +02:00
* [SearchContext ](api:SilverStripe\ORM\Search\SearchContext )
* [DataObject ](api:SilverStripe\ORM\DataObject )
2011-02-07 07:48:44 +01:00