Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DOC Document new filter by range functionality #687

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 87 additions & 6 deletions en/02_Developer_Guides/00_Model/11_Scaffolding.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use SilverStripe\ORM\DataObject;

class MyDataObject extends DataObject
{
// ...
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding these where appropriate in this file to indicate we're skipping some best practices for the sake of brevity - we tend to do this with new code blocks, so this just gives consistency across this file.

private static $db = [
'IsActive' => 'Boolean',
'Title' => 'Varchar',
Expand Down Expand Up @@ -226,9 +227,10 @@ use SilverStripe\ORM\DataObject;

class MyDataObject extends DataObject
{
// ...
private static $searchable_fields = [
'Name',
'ProductCode',
'Name',
'ProductCode',
];
}
```
Expand All @@ -251,6 +253,7 @@ use SilverStripe\ORM\DataObject;

class MyDataObject extends DataObject
{
// ...
private static $searchable_fields = [
'Name',
'BirthDate' => [
Expand Down Expand Up @@ -283,6 +286,7 @@ use SilverStripe\ORM\DataObject;

class MyDataObject extends DataObject
{
// ...
private static string $general_search_field_name = 'my_general_field_name';
}
```
Expand Down Expand Up @@ -317,6 +321,7 @@ use SilverStripe\ORM\Filters\EndsWithFilter;

class MyDataObject extends DataObject
{
// ...
private static string $general_search_field_filter = EndsWithFilter::class;
}
```
Expand Down Expand Up @@ -350,6 +355,7 @@ use SilverStripe\ORM\DataObject;

class MyDataObject extends DataObject
{
// ...
private static bool $general_search_split_terms = false;
}
```
Expand All @@ -368,6 +374,7 @@ use SilverStripe\ORM\DataObject;

class MyDataObject extends DataObject
{
// ...
private static $searchable_fields = [
'Name',
'JobTitle',
Expand All @@ -388,6 +395,7 @@ use SilverStripe\ORM\DataObject;

class MyDataObject extends DataObject
{
// ...
private static $searchable_fields = [
'Price',
'Description',
Expand All @@ -405,6 +413,7 @@ use SilverStripe\ORM\DataObject;

class MyDataObject extends DataObject
{
// ...
private static $general_search_field = 'Title';
}
```
Expand Down Expand Up @@ -433,15 +442,18 @@ use SilverStripe\ORM\DataObject;

class MyDataObject extends DataObject
{
// ...
private static $searchable_fields = [
'Name' => 'PartialMatchFilter',
'ProductCode' => NumericField::class,
'ProductCode' => [
'field' => NumericField::class,
],
Comment on lines -438 to +450
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if this worked at some stage and broke, but it definitely doesn't work right now and shouldn't be documented as a thing that works.

];
}
```

If you assign a single string value, you can set it to be either a [FormField](api:SilverStripe\Forms\FormField) or [SearchFilter](api:SilverStripe\ORM\Filters\SearchFilter). To specify
both or to combine this with other configuration, you can assign an array:
If you assign a single string value, you can set it to be a [`SearchFilter`](api:SilverStripe\ORM\Filters\SearchFilter) class. To specify a specific [`FormField`](api:SilverStripe\Forms\FormField) to use or
specify both a form field *and* a filter - or to combine this with other configuration - you can assign an array:

```php
namespace App\Model;
Expand All @@ -452,6 +464,7 @@ use SilverStripe\ORM\DataObject;

class MyDataObject extends DataObject
{
// ...
private static $searchable_fields = [
'Name' => [
'field' => TextField::class,
Expand All @@ -466,6 +479,62 @@ class MyDataObject extends DataObject
}
```

#### Using `WithinRangeFilter` {#searchable-fields-withinrangefilter}

If you want users to be able to filter by a field using a range, specify the [`WithinRangeFilter`](api:SilverStripe\ORM\Filters\WithinRangeFilter). This works out of the box with the numeric, date, datetime, and time fields that come in Silverstripe framework.

```php
namespace App\Model;

use SilverStripe\ORM\DataObject;
SilverStripe\ORM\Filters\WithinRangeFilter

class MyDataObject extends DataObject
{
// ...
private static array $db = [
'Price' => 'Currency',
Copy link
Member

@emteknetnz emteknetnz Feb 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The currency filter currently seems very busted, even with the framework PR. There is a card open to fix at least some of that issues there, though the PR change this example use an Int instead so when people copy it they don't think that they've done something wrong

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather just fix the field. If it's just the validation thing, I'll pull that card into in progress and fix it. If there are more problems, please open cards for them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted on silverstripe/silverstripe-framework#11602 (comment) it's related to the framework PR, so should be fixed there

];

private static array $searchable_fields = [
'Price' => [
'filter' => WithinRangeFilter::class,
],
];
}
```

This configuration will duplicate the form field, providing one form field for the "from" value, and another for the "to" value. Users can then filter within a range using the filters in the CMS.

![filter by price within a range](../../_images/withinrangefilter.png)

If a user fills in only the "from" or "to" field, the other will be populated with the minimum or maximum value defined by the relevant `DBField` class in [`getMinValue()`](api:SilverStripe\ORM\FieldType\DBField::getMinValue()) or [`getMaxValue()`](api:SilverStripe\ORM\FieldType\DBField::getMaxValue())

This can also be used with other field types, but you need to define what the default "from" and "to" values should be. You can do this with the `rangeFromDefault` and `rangeToDefault` keys as shown below.

```php
namespace App\Model;

use SilverStripe\ORM\DataObject;
SilverStripe\ORM\Filters\WithinRangeFilter

class MyDataObject extends DataObject
{
// ...
private static array $db = [
'Title' => 'Varchar',
];

private static array $searchable_fields = [
'Title' => [
'filter' => WithinRangeFilter::class,
'rangeFromDefault' => 'a',
'rangeToDefault' => 'z',
],
];
}
```

### Searching on relations

To include relations (`$has_one`, `$has_many` and `$many_many`) in your search, you can use a dot-notation.
Expand All @@ -477,6 +546,7 @@ use SilverStripe\ORM\DataObject;

class Team extends DataObject
{
// ...
private static $db = [
'Title' => 'Varchar',
];
Expand All @@ -499,6 +569,7 @@ use SilverStripe\ORM\DataObject;

class Player extends DataObject
{
// ...
private static $db = [
'Name' => 'Varchar',
'Birthday' => 'Date',
Expand All @@ -515,7 +586,7 @@ class Player extends DataObject
Use a single search field that matches on multiple database fields with `'match_any'`. This also supports specifying a `FormField` and a filter, though it is not necessary to do so.

> [!CAUTION]
> If you don't specify a `FormField`, you must use the name of a real database field as the array key instead of a custom name so that a default field class can be determined.
> If you don't specify `field` or `dataType`, you must use the name of a real database field as the array key instead of a custom name so that a default field class can be determined.
Comment on lines -518 to +589
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dataType is new and was intended for use with the range stuff, but it also works here so makes sense to document this option.


```php
namespace App\Model;
Expand All @@ -524,6 +595,7 @@ use SilverStripe\Forms\TextField;

class Order extends DataObject
{
// ...
private static $db = [
'Name' => 'Varchar',
];
Expand All @@ -537,6 +609,8 @@ class Order extends DataObject
'CustomName' => [
'title' => 'First Name',
'field' => TextField::class,
// Instead of defining "field" above, you could set "dataType" to a DBField instance like so:
// 'dataType' => DBVarchar::class,
'match_any' => [
// Searching with the "First Name" field will show Orders matching either
// Name, Customer.FirstName, or ShippingAddress.FirstName
Expand All @@ -549,6 +623,8 @@ class Order extends DataObject
}
```

You can also allow users to filter `match_any` with a range, using the configuration specified in [using `WithinRangeFilter`](#searchable-fields-withinrangefilter).

## Summary fields

Summary fields can be used to show a quick overview of the data for a specific [DataObject](api:SilverStripe\ORM\DataObject) record. The most common use
Expand All @@ -561,6 +637,7 @@ use SilverStripe\ORM\DataObject;

class MyDataObject extends DataObject
{
// ...
private static $db = [
'Name' => 'Text',
'OtherProperty' => 'Text',
Expand All @@ -585,6 +662,7 @@ use SilverStripe\ORM\DataObject;

class OtherObject extends DataObject
{
// ...
private static $db = [
'Title' => 'Varchar',
];
Expand All @@ -598,6 +676,7 @@ use SilverStripe\ORM\DataObject;

class MyDataObject extends DataObject
{
// ...
private static $db = [
'Name' => 'Text',
'Description' => 'HTMLText',
Expand Down Expand Up @@ -626,6 +705,7 @@ use SilverStripe\ORM\DataObject;

class MyDataObject extends DataObject
{
// ...
private static $db = [
'Name' => 'Text',
];
Expand All @@ -652,6 +732,7 @@ use SilverStripe\ORM\DataObject;

class MyDataObject extends DataObject
{
// ...
private static $db = [
'Name' => 'Text',
];
Expand Down
35 changes: 35 additions & 0 deletions en/08_Changelogs/6.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ title: 6.0.0 (unreleased)
- [Changes to default cache adapters](#caching)
- [Changes to scaffolded form fields](#scaffolded-fields)
- [`SiteTree` uses form field scaffolding](#sitetree-scaffolding)
- [Filter within a range with `searchable_fields`](#searchable-withinrange)
- [Changes to the templating/view layer](#view-layer)
- [Changes to `LeftAndMain` and its subclasses](#leftandmain-refactor)
- [Changes to password validation](#password-validation)
Expand Down Expand Up @@ -596,6 +597,40 @@ SilverStripe\UserForms\Model\UserDefinedForm:

</details>

### Filter within a range with `searchable_fields` {#searchable-withinrange}

Using the `searchable_fields` configuration, you can now declare that a field should be filtered using a range. This works out of the box with the numeric, date, datetime, and time fields that come in the Silverstripe framework.

> [!TIP]
> You can also provide ranges for other field types, but it requires some additional configuration.

```php
namespace App\Model;

use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\Filters\WithinRangeFilter;

class MyDataObject extends DataObject
{
// ...
private static array $db = [
'Price' => 'Currency',
];

private static array $searchable_fields = [
'Price' => WithinRangeFilter::class,
];
}
```

This configuration will duplicate the form field, providing one form field for the "from" value, and another for the "to" value. Users can then filter within a range using the filters in the CMS.

![filter by price within a range](../_images/withinrangefilter.png)

If a user fills in only the "from" or "to" field, the other will be populated with the minimum or maximum value defined by the relevant `DBField` class in [`getMinValue()`](api:SilverStripe\ORM\FieldType\DBField::getMinValue()) or [`getMaxValue()`](api:SilverStripe\ORM\FieldType\DBField::getMaxValue())

See the [searchable fields documentation](/developer_guides/model/scaffolding/#searchable-fields-withinrangefilter) for more details.

### Changes to the templating/view layer {#view-layer}

Note that the `SilverStripe\View\ViewableData` class has been renamed to [`SilverStripe\Model\ModelData`](api:SilverStripe\Model\ModelData). We will refer to it as `ModelData` in the rest of these change logs.
Expand Down
Binary file removed en/_images/changelogs/5.2.0/elemental-badge.png
Binary file not shown.
Binary file added en/_images/withinrangefilter.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.