2011-02-07 07:48:44 +01:00
|
|
|
# DataObject
|
|
|
|
|
|
|
|
## Introduction
|
|
|
|
|
2012-06-23 00:32:43 +02:00
|
|
|
The `[api:DataObject]` class represents a single row in a database table,
|
|
|
|
following the ["Active Record"](http://en.wikipedia.org/wiki/Active_record_pattern) design pattern.
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2012-06-23 00:32:43 +02:00
|
|
|
## Defining Properties
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2012-06-23 00:32:43 +02:00
|
|
|
Properties defined through `DataObject::$db` map to table columns,
|
|
|
|
and can be declared as different [data-types](/topics/data-types).
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2012-06-23 00:32:43 +02:00
|
|
|
## Loading and Saving Records
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2012-06-23 00:32:43 +02:00
|
|
|
The basic principles around data persistence and querying for objects
|
|
|
|
is explained in the ["datamodel" topic](/topics/datamodel).
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2012-06-23 00:32:43 +02:00
|
|
|
## Defining Form Fields
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2012-06-23 00:32:43 +02:00
|
|
|
In addition to defining how data is persisted, the class can also
|
|
|
|
help with editing it by providing form fields through `DataObject->getCMSFields()`.
|
|
|
|
The resulting `[api:FieldList]` is the centrepiece of many data administration interfaces in SilverStripe.
|
|
|
|
Many customizations of the SilverStripe CMS interface start here,
|
|
|
|
by adding, removing or configuring fields.
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2012-06-23 00:32:43 +02:00
|
|
|
Example getCMSFields implementation
|
2011-02-07 07:48:44 +01:00
|
|
|
|
|
|
|
:::php
|
2012-06-23 00:32:43 +02:00
|
|
|
class MyDataObject extends DataObject {
|
|
|
|
$db = array(
|
|
|
|
'IsActive' => 'Boolean'
|
|
|
|
);
|
|
|
|
public function getCMSFields() {
|
2012-06-28 11:43:56 +02:00
|
|
|
return new FieldList(
|
2012-06-23 00:32:43 +02:00
|
|
|
new CheckboxField('IsActive')
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2012-06-23 00:32:43 +02:00
|
|
|
There's various [form field types](/references/form-field-types), for editing text, dates,
|
|
|
|
restricting input to numbers, and much more.
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2012-06-23 00:32:43 +02:00
|
|
|
## Scaffolding Form Fields
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2012-06-23 00:32:43 +02:00
|
|
|
The ORM already has a lot of information about the data represented by a `DataObject`
|
|
|
|
through its `$db` property, so why not use it to create form fields as well?
|
|
|
|
If you call the parent implementation, the class will use `[api:FormScaffolder]`
|
|
|
|
to provide reasonable defaults based on the property type (e.g. a checkbox field for booleans).
|
|
|
|
You can then further customize those fields as required.
|
2011-02-07 07:48:44 +01:00
|
|
|
|
|
|
|
:::php
|
2012-06-23 00:32:43 +02:00
|
|
|
class MyDataObject extends DataObject {
|
|
|
|
// ...
|
|
|
|
public function getCMSFields() {
|
|
|
|
$fields = parent::getCMSFields();
|
|
|
|
$fields->fieldByName('IsActive')->setTitle('Is active?');
|
|
|
|
return $fields;
|
|
|
|
}
|
|
|
|
}
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2012-06-23 00:32:43 +02:00
|
|
|
The `[ModelAdmin](/reference/modeladmin)` class uses this approach to provide
|
|
|
|
data management interfaces with very little custom coding.
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2012-06-23 00:32:43 +02:00
|
|
|
You can also alter the fields of built-in and module `DataObject` classes through
|
|
|
|
your own `[DataExtension](/reference/dataextension)`, and a call to `[api:DataExtension->updateCMSFields()]`.
|
2013-05-16 00:34:45 +02:00
|
|
|
`[api::DataObject->beforeUpdateCMSFields()]` can also be used to interact with and add to automatically
|
|
|
|
scaffolded fields prior to being passed to extensions (See `[DataExtension](/reference/dataextension)`).
|
2011-02-07 07:48:44 +01:00
|
|
|
|
|
|
|
### Searchable Fields
|
|
|
|
|
|
|
|
The `$searchable_fields` property uses a mixed array format that can be used to further customize your generated admin
|
|
|
|
system. The default is a set of array values listing the fields.
|
|
|
|
|
|
|
|
Example: Getting predefined searchable fields
|
|
|
|
|
|
|
|
:::php
|
|
|
|
$fields = singleton('MyDataObject')->searchableFields();
|
|
|
|
|
|
|
|
|
|
|
|
Example: Simple Definition
|
|
|
|
|
|
|
|
:::php
|
|
|
|
class MyDataObject extends DataObject {
|
2013-03-21 19:48:54 +01:00
|
|
|
private static $searchable_fields = array(
|
2011-02-07 07:48:44 +01:00
|
|
|
'Name',
|
|
|
|
'ProductCode'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-03-08 22:05:51 +01:00
|
|
|
Searchable fields will be appear in the search interface with a default form field (usually a `[api:TextField]`) and a default
|
|
|
|
search filter assigned (usually an `[api:ExactMatchFilter]`). To override these defaults, you can specify additional information
|
2011-02-07 07:48:44 +01:00
|
|
|
on `$searchable_fields`:
|
|
|
|
|
|
|
|
:::php
|
|
|
|
class MyDataObject extends DataObject {
|
2013-03-21 19:48:54 +01:00
|
|
|
private static $searchable_fields = array(
|
2011-02-07 07:48:44 +01:00
|
|
|
'Name' => 'PartialMatchFilter',
|
|
|
|
'ProductCode' => 'NumericField'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-03-08 22:05:51 +01:00
|
|
|
If you assign a single string value, you can set it to be either a `[api:FormField]` or `[api:SearchFilter]`. To specify both, you can
|
2011-02-07 07:48:44 +01:00
|
|
|
assign an array:
|
|
|
|
|
|
|
|
:::php
|
|
|
|
class MyDataObject extends DataObject {
|
2013-03-21 19:48:54 +01:00
|
|
|
private static $searchable_fields = array(
|
2011-02-07 07:48:44 +01:00
|
|
|
'Name' => array(
|
|
|
|
'field' => 'TextField',
|
|
|
|
'filter' => 'PartialMatchFilter',
|
|
|
|
),
|
|
|
|
'ProductCode' => array(
|
|
|
|
'title' => 'Product code #',
|
|
|
|
'field' => 'NumericField',
|
|
|
|
'filter' => 'PartialMatchFilter',
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
To include relations (''$has_one'', `$has_many` and `$many_many`) in your search, you can use a dot-notation.
|
|
|
|
|
|
|
|
:::php
|
|
|
|
class Team extends DataObject {
|
2013-03-21 19:48:54 +01:00
|
|
|
private static $db = array(
|
2011-02-07 07:48:44 +01:00
|
|
|
'Title' => 'Varchar'
|
|
|
|
);
|
2013-03-21 19:48:54 +01:00
|
|
|
private static $many_many = array(
|
2011-02-07 07:48:44 +01:00
|
|
|
'Players' => 'Player'
|
|
|
|
);
|
2013-03-21 19:48:54 +01:00
|
|
|
private static $searchable_fields = array(
|
2011-02-07 07:48:44 +01:00
|
|
|
'Title',
|
|
|
|
'Players.Name',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
class Player extends DataObject {
|
2013-03-21 19:48:54 +01:00
|
|
|
private static $db = array(
|
2011-02-07 07:48:44 +01:00
|
|
|
'Name' => 'Varchar',
|
|
|
|
'Birthday' => 'Date'
|
|
|
|
);
|
2013-03-21 19:48:54 +01:00
|
|
|
private static $belongs_many_many = array(
|
2011-02-07 07:48:44 +01:00
|
|
|
'Teams' => 'Team'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
### Summary Fields
|
|
|
|
|
2011-03-08 22:05:51 +01:00
|
|
|
Summary fields can be used to show a quick overview of the data for a specific `[api:DataObject]` record. Most common use is
|
2011-02-07 07:48:44 +01:00
|
|
|
their display as table columns, e.g. in the search results of a `[api:ModelAdmin]` CMS interface.
|
|
|
|
|
|
|
|
Example: Getting predefined summary fields
|
|
|
|
|
|
|
|
:::php
|
|
|
|
$fields = singleton('MyDataObject')->summaryFields();
|
|
|
|
|
|
|
|
|
|
|
|
Example: Simple Definition
|
|
|
|
|
|
|
|
:::php
|
|
|
|
class MyDataObject extends DataObject {
|
2013-03-21 19:48:54 +01:00
|
|
|
private static $db = array(
|
2011-02-07 07:48:44 +01:00
|
|
|
'Name' => 'Text',
|
|
|
|
'OtherProperty' => 'Text',
|
|
|
|
'ProductCode' => 'Int',
|
|
|
|
);
|
2013-03-21 19:48:54 +01:00
|
|
|
private static $summary_fields = array(
|
2013-06-12 23:41:24 +02:00
|
|
|
'Name',
|
|
|
|
'ProductCode'
|
|
|
|
);
|
2011-02-07 07:48:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-12 23:41:24 +02:00
|
|
|
To include relations or field manipulations in your summaries, you can use a dot-notation.
|
2011-02-07 07:48:44 +01:00
|
|
|
|
|
|
|
:::php
|
|
|
|
class OtherObject extends DataObject {
|
2013-03-21 19:48:54 +01:00
|
|
|
private static $db = array(
|
2011-02-07 07:48:44 +01:00
|
|
|
'Title' => 'Varchar'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
class MyDataObject extends DataObject {
|
2013-03-21 19:48:54 +01:00
|
|
|
private static $db = array(
|
2013-06-12 23:41:24 +02:00
|
|
|
'Name' => 'Text',
|
|
|
|
'Description' => 'HTMLText'
|
2011-02-07 07:48:44 +01:00
|
|
|
);
|
2013-03-21 19:48:54 +01:00
|
|
|
private static $has_one = array(
|
2011-02-07 07:48:44 +01:00
|
|
|
'OtherObject' => 'OtherObject'
|
|
|
|
);
|
2013-06-12 23:41:24 +02:00
|
|
|
private static $summary_fields = array(
|
|
|
|
'Name' => 'Name',
|
|
|
|
'Description.Summary' => 'Description (summary)',
|
|
|
|
'OtherObject.Title' => 'Other Object Title'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Non-textual elements (such as images and their manipulations) can also be used in summaries.
|
|
|
|
|
|
|
|
:::php
|
|
|
|
class MyDataObject extends DataObject {
|
|
|
|
private static $db = array(
|
|
|
|
'Name' => 'Text'
|
|
|
|
);
|
|
|
|
private static $has_one = array(
|
|
|
|
'HeroImage' => 'Image'
|
|
|
|
);
|
|
|
|
private static $summary_fields = array(
|
2014-02-20 12:10:47 +01:00
|
|
|
'Name' => 'Name',
|
2013-06-12 23:41:24 +02:00
|
|
|
'HeroImage.CMSThumbnail' => 'Hero Image'
|
|
|
|
);
|
2011-02-07 07:48:44 +01:00
|
|
|
}
|
|
|
|
|
2013-06-12 23:41:24 +02:00
|
|
|
|
2012-12-17 00:47:30 +01:00
|
|
|
## Permissions
|
|
|
|
|
|
|
|
Models can be modified in a variety of controllers and user interfaces,
|
|
|
|
all of which can implement their own security checks. But often it makes
|
|
|
|
sense to centralize those checks on the model, regardless of the used controller.
|
|
|
|
|
|
|
|
The API provides four methods for this purpose:
|
|
|
|
`canEdit()`, `canCreate()`, `canView()` and `canDelete()`.
|
|
|
|
Since they're PHP methods, they can contain arbitrary logic
|
|
|
|
matching your own requirements. They can optionally receive a `$member` argument,
|
|
|
|
and default to the currently logged in member (through `Member::currentUser()`).
|
|
|
|
|
|
|
|
Example: Check for CMS access permissions
|
|
|
|
|
|
|
|
class MyDataObject extends DataObject {
|
|
|
|
// ...
|
|
|
|
public function canView($member = null) {
|
|
|
|
return Permission::check('CMS_ACCESS_CMSMain', 'any', $member);
|
|
|
|
}
|
|
|
|
public function canEdit($member = null) {
|
|
|
|
return Permission::check('CMS_ACCESS_CMSMain', 'any', $member);
|
|
|
|
}
|
|
|
|
public function canDelete($member = null) {
|
|
|
|
return Permission::check('CMS_ACCESS_CMSMain', 'any', $member);
|
|
|
|
}
|
|
|
|
public function canCreate($member = null) {
|
|
|
|
return Permission::check('CMS_ACCESS_CMSMain', 'any', $member);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
**Important**: These checks are not enforced on low-level ORM operations
|
|
|
|
such as `write()` or `delete()`, but rather rely on being checked in the invoking code.
|
|
|
|
The CMS default sections as well as custom interfaces like
|
|
|
|
`[ModelAdmin](/reference/modeladmin)` or `[GridField](/reference/gridfield)`
|
|
|
|
already enforce these permissions.
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2013-12-13 12:09:12 +01:00
|
|
|
## Indexes
|
|
|
|
|
|
|
|
It is sometimes desirable to add indexes to your data model, whether to
|
|
|
|
optimize queries or add a uniqueness constraint to a field. This is done
|
|
|
|
through the `DataObject::$indexes` map, which maps index names to descriptor
|
|
|
|
arrays that represent each index. There's several supported notations:
|
|
|
|
|
|
|
|
:::php
|
|
|
|
# Simple
|
|
|
|
private static $indexes = array(
|
|
|
|
'<column-name>' => true
|
|
|
|
);
|
|
|
|
|
|
|
|
# Advanced
|
|
|
|
private static $indexes = array(
|
|
|
|
'<index-name>' => array('type' => '<type>', 'value' => '"<column-name>"')
|
|
|
|
);
|
|
|
|
|
|
|
|
# SQL
|
|
|
|
private static $indexes = array(
|
|
|
|
'<index-name>' => 'unique("<column-name>")'
|
|
|
|
);
|
|
|
|
|
|
|
|
The `<index-name>` can be an an arbitrary identifier in order to allow for more than one
|
|
|
|
index on a specific database column.
|
|
|
|
The "advanced" notation supports more `<type>` notations.
|
|
|
|
These vary between database drivers, but all of them support the following:
|
|
|
|
|
|
|
|
* `index`: Standard index
|
|
|
|
* `unique`: Index plus uniqueness constraint on the value
|
|
|
|
* `fulltext`: Fulltext content index
|
|
|
|
|
|
|
|
In order to use more database specific or complex index notations,
|
|
|
|
we also support raw SQL for as a value in the `$indexes` definition.
|
|
|
|
Keep in mind this will likely make your code less portable between databases.
|
|
|
|
|
|
|
|
Example: A combined index on a two fields.
|
|
|
|
|
|
|
|
:::php
|
|
|
|
private static $db = array(
|
|
|
|
'MyField' => 'Varchar',
|
|
|
|
'MyOtherField' => 'Varchar',
|
|
|
|
);
|
|
|
|
private static $indexes = array(
|
|
|
|
'MyIndexName' => array('type' => 'index', 'value' => '"MyField","MyOtherField"'),
|
|
|
|
);
|
|
|
|
|
2011-02-07 07:48:44 +01:00
|
|
|
## API Documentation
|
|
|
|
|
|
|
|
`[api:DataObject]`
|