Scaffolding
The ORM already has a lot of information about the data represented by a DataObject
through its $db
property, so
Silverstripe CMS will use that information to scaffold some interfaces. This is done though FormScaffolder
to provide reasonable defaults based on the property type (e.g. a checkbox field for booleans). You can then further
customise those fields as required.
Form fields
An example is DataObject
, Silverstripe CMS will automatically create your CMS interface so you can modify what you need.
namespace App\Model;
use SilverStripe\ORM\DataObject;
class MyDataObject extends DataObject
{
private static $db = [
'IsActive' => 'Boolean',
'Title' => 'Varchar',
'Content' => 'Text',
];
public function getCMSFields()
{
// parent::getCMSFields() does all the hard work and creates the fields for Title, IsActive and Content.
$fields = parent::getCMSFields();
$fields->dataFieldByName('IsActive')->setTitle('Is active?');
return $fields;
}
}
To fully customise your form fields, start with an empty FieldList.
namespace App\Model;
use SilverStripe\ORM\DataObject;
class MyDataObject extends DataObject
{
// ...
public function getCMSFields()
{
$fields = FieldList::create(
TabSet::create(
'Root',
Tab::create(
'Main',
CheckboxSetField::create('IsActive', 'Is active?'),
TextField::create('Title'),
TextareaField::create('Content')
->setRows(5)
)
)
);
return $fields;
}
}
You can also alter the fields of built-in and module DataObject
classes through your own
DataExtension, and a call to DataExtension->updateCMSFields
.
FormField
scaffolding takes $field_labels
config into account as well.
Searchable fields
The $searchable_fields
property uses a mixed array format that can be used to further customise your generated admin
system. The default is a set of array values listing the fields.
$searchable_fields
will default to use the $summary_fields
config, excluding anything that isn't a database field (such as method calls) if not explicitly defined.
namespace App\Model;
use SilverStripe\ORM\DataObject;
class MyDataObject extends DataObject
{
private static $searchable_fields = [
'Name',
'ProductCode',
];
}
If you define a searchable_fields
configuration, do not specify fields that are not stored in the database (such as methods), as this will cause an error.
General search field
Tabular views such as GridField
or ModalAdmin
include a search bar. As of Silverstripe CMS 4.12, the search bar will search across all of your searchable fields by default. It will return a match if the search terms appear in any of the searchable fields.
Exclude fields from the general search
If you have fields which you do not want to be searched with this general search (e.g. date fields which need special consideration), you can mark them as being explicitly excluded by setting general
to false in the searchable fields configuration for that field:
namespace App\Model;
use SilverStripe\ORM\DataObject;
class MyDataObject extends DataObject
{
private static $searchable_fields = [
'Name',
'BirthDate' => [
'general' => false,
],
];
}
Customise the general search field name
By default the general search field uses the name "q". If you already use that field name or search query in your SearchContext, you can change this to whatever name you prefer either globally or per class:
If you set general_search_field_name
to any empty string, general search will be disabled entirely. Instead, the first field in your searchable fields configuration will be used, which was the default behaviour prior to Silverstripe CMS 4.12.
Globally change the general search field name via YAML config
SilverStripe\ORM\DataObject:
general_search_field_name: 'my_general_field_name'
Customise the general search field name via YAML or PHP config
namespace App\Model;
use SilverStripe\ORM\DataObject;
class MyDataObject extends DataObject
{
private static string $general_search_field_name = 'my_general_field_name';
}
Specify a search filter for general search
By default, the general search will search across your fields using a PartialMatchFilter regardless of what filters you have specified for those fields.
You can configure this to be a specific filter class, or else disable the general search filter. Disabling the filter will result in the filters you have specified for each field being used when searching against that field in the general search.
Like the general search field name, you can set this either globally or per class.
Globally change the general search filter via YAML config
# use a specific filter
SilverStripe\ORM\DataObject:
general_search_field_filter: 'SilverStripe\ORM\Filters\EndsWithFilter'
# or disable the filter to fall back on individual fields' filters
SilverStripe\ORM\DataObject:
general_search_field_filter: ''
Customise the general search filter via YAML or PHP config
namespace App\Model;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\Filters\EndsWithFilter;
class MyDataObject extends DataObject
{
private static string $general_search_field_filter = EndsWithFilter::class;
}
You may get unexpected results using some filters if you don't disable splitting the query into terms - for example if you use an ExactMatchFilter, each term in the query must exactly match the value in at least one field to get a match. If you disable splitting terms, the whole query must exactly match a field value instead.
Splitting search queries into individual terms
By default the general search field will split your search query on spaces into individual terms, and search across your searchable field for each term. At least one field must match each term to get a match.
For example: with the search query "farm house" at least one field must have a match for the word "farm", and at least one field must have a match for the word "house". There does not need to be a field which matches the full phrase "farm house".
You can disable this behaviour by setting DataObject.general_search_split_terms
to false. This would mean that for the example above a DataObject
would need a field that matches "farm house" to be included in the results. Simply matching "farm" or "house" alone would not be sufficient.
Like the general search field name, you can set this either globally or per class.
Globally disable splitting terms via YAML config
SilverStripe\ORM\DataObject:
general_search_split_terms: false
Disable splitting terms via YAML or PHP config
namespace App\Model;
use SilverStripe\ORM\DataObject;
class MyDataObject extends DataObject
{
private static bool $general_search_split_terms = false;
}
Use a specific single field
If you disable the global general search functionality, the general seach field will revert to searching against the first
field in your searchableFields
list.
As an example, let's look at a definition like this:
namespace App\Model;
use SilverStripe\ORM\DataObject;
class MyDataObject extends DataObject
{
private static $searchable_fields = [
'Name',
'JobTitle',
];
}
That Name
comes first in that list is actually quite a good thing. The user will likely want the
single search input to target the Name
field rather something with a more predictable value,
like JobTitle
.
By contrast, let's look at this definition:
namespace App\Model;
use SilverStripe\ORM\DataObject;
class MyDataObject extends DataObject
{
private static $searchable_fields = [
'Price',
'Description',
'Title',
];
}
It's unlikely that the user will want to search on Price
. A better candidate would be Title
or Description
. Rather than reorder the array, which may be counter-intuitive, you can use the general_search_field
configuration property.
namespace App\Model;
use SilverStripe\ORM\DataObject;
class MyDataObject extends DataObject
{
private static $general_search_field = 'Title';
}
Customise the field per GridField
You can customise the search field for a specific GridField
by calling setSearchField()
on its GridFieldFilterHeader
component instance.
$myGrid->getConfig()->getComponentByType(GridFieldFilterHeader::class)->setSearchField('Title');
This is useful if you have disabled the global general search functionality, if you have customised the SearchContext, or if you (for whatever reason) want to use a single specific search field for this GridField
.
Specify a form field or search filter
Searchable fields will appear in the search interface with a default form field (usually a TextField) and a
default search filter assigned (usually a PartialMatchFilter). To override these defaults, you can specify
additional information on $searchable_fields
:
namespace App\Model;
use SilverStripe\Forms\NumericField;
use SilverStripe\ORM\DataObject;
class MyDataObject extends DataObject
{
private static $searchable_fields = [
'Name' => 'PartialMatchFilter',
'ProductCode' => NumericField::class,
];
}
If you assign a single string value, you can set it to be either a FormField or SearchFilter. To specify both or to combine this with other configuration, you can assign an array:
namespace App\Model;
use SilverStripe\Forms\NumericField;
use SilverStripe\Forms\TextField;
use SilverStripe\ORM\DataObject;
class MyDataObject extends DataObject
{
private static $searchable_fields = [
'Name' => [
'field' => TextField::class,
'filter' => 'PartialMatchFilter',
],
'ProductCode' => [
'title' => 'Product code #',
'field' => NumericField::class,
'filter' => 'PartialMatchFilter',
],
];
}
Searching on relations
To include relations ($has_one
, $has_many
and $many_many
) in your search, you can use a dot-notation.
namespace App\Model;
use SilverStripe\ORM\DataObject;
class Team extends DataObject
{
private static $db = [
'Title' => 'Varchar',
];
private static $many_many = [
'Players' => 'Player',
];
private static $searchable_fields = [
'Title',
'Players.Name',
];
}
namespace App\Model;
use SilverStripe\ORM\DataObject;
class Player extends DataObject
{
private static $db = [
'Name' => 'Varchar',
'Birthday' => 'Date',
];
private static $belongs_many_many = [
'Teams' => 'Team',
];
}
Searching many db fields on a single search field
Use a single search field that matches on multiple database fields with 'match_any'
. This also supports specifying a field and a filter, though it is not necessary to do so.
If you don't specify a field, you must use the name of a real database field instead of a custom name so that a default field can be determined.
namespace App\Model;
use SilverStripe\Forms\TextField;
class Order extends DataObject
{
private static $db = [
'Name' => 'Varchar',
];
private static $has_one = [
'Customer' => Customer::class,
'ShippingAddress' => Address::class,
];
private static $searchable_fields = [
'CustomName' => [
'title' => 'First Name',
'field' => TextField::class,
'match_any' => [
// Searching with the "First Name" field will show Orders matching either
// Name, Customer.FirstName, or ShippingAddress.FirstName
'Name',
'Customer.FirstName',
'ShippingAddress.FirstName',
],
],
];
}
Summary fields
Summary fields can be used to show a quick overview of the data for a specific DataObject record. The most common use is their display as table columns, e.g. in the search results of a ModelAdmin CMS interface.
namespace App\Model;
use SilverStripe\ORM\DataObject;
class MyDataObject extends DataObject
{
private static $db = [
'Name' => 'Text',
'OtherProperty' => 'Text',
'ProductCode' => 'Int',
];
private static $summary_fields = [
'Name',
'ProductCode',
];
}
Relations in summary fields
To include relations or field manipulations in your summaries, you can use a dot-notation.
namespace App\Model;
use SilverStripe\ORM\DataObject;
class OtherObject extends DataObject
{
private static $db = [
'Title' => 'Varchar',
];
}
namespace App\Model;
use SilverStripe\ORM\DataObject;
class MyDataObject extends DataObject
{
private static $db = [
'Name' => 'Text',
'Description' => 'HTMLText',
];
private static $has_one = [
'OtherObject' => 'OtherObject',
];
private static $summary_fields = [
'Name' => 'Name',
'Description.Summary' => 'Description (summary)',
'OtherObject.Title' => 'Other Object Title',
];
}
Images in summary fields
Non-textual elements (such as images and their manipulations) can also be used in summaries.
namespace App\Model;
use SilverStripe\ORM\DataObject;
class MyDataObject extends DataObject
{
private static $db = [
'Name' => 'Text',
];
private static $has_one = [
'HeroImage' => 'Image',
];
private static $summary_fields = [
'Name' => 'Name',
'HeroImage.CMSThumbnail' => 'Hero Image',
];
}
Field labels
In order to re-label any summary fields, you can use the $field_labels
static. This will also affect the output of $object->fieldLabels()
and $object->fieldLabel()
.
namespace App\Model;
use SilverStripe\ORM\DataObject;
class MyDataObject extends DataObject
{
private static $db = [
'Name' => 'Text',
];
private static $has_one = [
'HeroImage' => 'Image',
];
private static $summary_fields = [
'Name',
'HeroImage.CMSThumbnail',
];
private static $field_labels = [
'Name' => 'Name',
'HeroImage.CMSThumbnail' => 'Hero',
];
}