2019-11-18 05:58:33 +01:00
---
2014-10-22 12:47:56 +02:00
title: Extensions
summary: Extensions and DataExtensions let you modify and augment objects transparently.
2019-11-18 05:58:33 +01:00
icon: code
---
2014-10-22 12:47:56 +02:00
# Extensions and DataExtensions
2018-09-12 16:39:59 +02:00
An [Extension ](api:SilverStripe\Core\Extension ) allows for adding additional functionality to a class or modifying existing functionality
without the hassle of creating a subclass. Developers can add Extensions to any PHP class that has the [Extensible ](api:SilverStripe\Core\Extensible )
trait applied within core, modules or even their own code to make it more reusable.
2014-10-22 12:47:56 +02:00
2017-07-03 03:22:12 +02:00
Extensions are defined as subclasses of either [DataExtension ](api:SilverStripe\ORM\DataExtension ) for extending a [DataObject ](api:SilverStripe\ORM\DataObject ) subclass or
the [Extension ](api:SilverStripe\Core\Extension ) class for non DataObject subclasses (such as [Controller ](api:SilverStripe\Control\Controller ))
2014-10-22 12:47:56 +02:00
2019-11-18 05:58:33 +01:00
[info]
2018-09-12 16:39:59 +02:00
For performance reasons a few classes are excluded from receiving extensions, including `ViewableData`
2016-10-13 18:39:46 +02:00
and `RequestHandler` . You can still apply extensions to descendants of these classes.
2019-11-18 05:58:33 +01:00
[/info]
2016-10-13 18:39:46 +02:00
2018-06-25 00:39:53 +02:00
**app/code/extensions/MyMemberExtension.php**
2014-10-22 12:47:56 +02:00
2017-08-03 02:51:32 +02:00
```php
2017-10-27 04:38:27 +02:00
use SilverStripe\ORM\DataExtension;
2017-08-05 00:45:24 +02:00
2017-10-27 04:38:27 +02:00
class MyMemberExtension extends DataExtension
{
2014-10-22 12:47:56 +02:00
2017-10-27 04:38:27 +02:00
private static $db = [
2018-09-12 16:39:59 +02:00
'DateOfBirth' => 'DBDatetime'
2017-10-27 04:38:27 +02:00
];
2014-10-22 12:47:56 +02:00
2017-10-27 04:38:27 +02:00
public function SayHi()
{
// $this->owner refers to the original instance. In this case a `Member` .
return "Hi " . $this->owner->Name;
2017-08-07 05:11:17 +02:00
}
2017-10-27 04:38:27 +02:00
}
2017-08-03 02:51:32 +02:00
```
2014-10-22 12:47:56 +02:00
2019-11-18 05:58:33 +01:00
[info]
2014-10-22 12:47:56 +02:00
Convention is for extension class names to end in `Extension` . This isn't a requirement but makes it clearer
2019-11-18 05:58:33 +01:00
[/info]
2014-10-22 12:47:56 +02:00
After this class has been created, it does not yet apply it to any object. We need to tell SilverStripe what classes
we want to add the `MyMemberExtension` too. To activate this extension, add the following via the [Configuration API ](../configuration ).
2018-06-25 00:39:53 +02:00
**app/_config/app.yml**
2014-10-22 12:47:56 +02:00
2017-08-03 02:51:32 +02:00
```yml
2017-10-27 04:38:27 +02:00
SilverStripe\Security\Member:
extensions:
- MyMemberExtension
2017-08-03 02:51:32 +02:00
```
2014-10-22 12:47:56 +02:00
Alternatively, we can add extensions through PHP code (in the `_config.php` file).
2017-08-03 02:51:32 +02:00
```php
2018-11-26 00:00:02 +01:00
SilverStripe\Security\Member::add_extension(MyMemberExtension::class);
2017-08-03 02:51:32 +02:00
```
2014-10-22 12:47:56 +02:00
This class now defines a `MyMemberExtension` that applies to all `Member` instances on the website. It will have
transformed the original `Member` class in two ways:
2017-07-03 03:22:12 +02:00
* Added a new [DBDatetime ](api:SilverStripe\ORM\FieldType\DBDatetime ) for the users date of birth, and;
2014-10-22 12:47:56 +02:00
* Added a `SayHi` method to output `Hi <User>`
From within the extension we can add more functions, database fields, relations or other properties and have them added
to the underlying `DataObject` just as if they were added to the original `Member` class but without the need to edit
that file directly.
### Adding Database Fields
Extra database fields can be added with a extension in the same manner as if they were placed on the `DataObject` class
they're applied to. These will be added to the table of the base object - the extension will actually edit the $db,
$has_one etc.
2018-06-25 00:39:53 +02:00
**app/code/extensions/MyMemberExtension.php**
2014-10-22 12:47:56 +02:00
2017-08-03 02:51:32 +02:00
```php
2017-10-27 04:38:27 +02:00
use SilverStripe\ORM\DataExtension;
2017-08-05 00:45:24 +02:00
2017-10-27 04:38:27 +02:00
class MyMemberExtension extends DataExtension
{
2014-10-22 12:47:56 +02:00
2017-10-27 04:38:27 +02:00
private static $db = [
'Position' => 'Varchar',
];
2014-10-22 12:47:56 +02:00
2017-10-27 04:38:27 +02:00
private static $has_one = [
2017-11-17 17:14:28 +01:00
'Image' => Image::class,
2017-10-27 04:38:27 +02:00
];
2014-10-22 12:47:56 +02:00
2017-10-27 04:38:27 +02:00
public function SayHi()
{
// $this->owner refers to the original instance. In this case a `Member` .
return "Hi " . $this->owner->Name;
2017-08-07 05:11:17 +02:00
}
2017-10-27 04:38:27 +02:00
}
2017-08-03 02:51:32 +02:00
```
2014-10-22 12:47:56 +02:00
2018-06-25 00:39:53 +02:00
**app/templates/Page.ss**
2017-08-03 02:51:32 +02:00
```ss
2017-10-27 04:38:27 +02:00
$CurrentMember.Position
$CurrentMember.Image
2017-08-03 02:51:32 +02:00
```
2014-10-22 12:47:56 +02:00
## Adding Methods
2017-07-03 03:22:12 +02:00
Methods that have a unique name will be called as part of the `__call` method on [Object ](api:Object ). In the previous example
2014-10-22 12:47:56 +02:00
we added a `SayHi` method which is unique to our extension.
2018-06-25 00:39:53 +02:00
**app/templates/Page.ss**
2017-08-03 02:51:32 +02:00
```ss
2017-10-27 04:38:27 +02:00
< p > $CurrentMember.SayHi< / p >
// "Hi Sam"
2017-08-03 02:51:32 +02:00
```
2014-10-22 12:47:56 +02:00
2018-06-25 00:39:53 +02:00
**app/code/Page.php**
2017-08-03 02:51:32 +02:00
```php
2017-10-27 04:38:27 +02:00
use SilverStripe\Security\Security;
$member = Security::getCurrentUser();
echo $member->SayHi;
2014-10-22 12:47:56 +02:00
2017-10-27 04:38:27 +02:00
// "Hi Sam"
2017-08-03 02:51:32 +02:00
```
2014-10-22 12:47:56 +02:00
## Modifying Existing Methods
2015-04-02 04:51:51 +02:00
If the `Extension` needs to modify an existing method it's a little trickier. It requires that the method you want to
2016-03-30 02:17:28 +02:00
customise has provided an *Extension Hook* in the place where you want to modify the data. An *Extension Hook* is done
2017-08-07 02:09:39 +02:00
through the `extend()` method of the [Extensible ](api:SilverStripe\Core\Extensible ) trait.
2014-10-22 12:47:56 +02:00
2017-10-06 17:00:32 +02:00
**Member.php**
2014-10-22 12:47:56 +02:00
2017-08-03 02:51:32 +02:00
```php
2017-10-27 04:38:27 +02:00
public function getValidator()
{
// ..
$this->extend('updateValidator', $validator);
2017-08-07 05:11:17 +02:00
2017-10-27 04:38:27 +02:00
// ..
}
2017-08-03 02:51:32 +02:00
```
2014-10-22 12:47:56 +02:00
Extension Hooks can be located anywhere in the method and provide a point for any `Extension` instances to modify the
variables at that given point. In this case, the core function `getValidator` on the `Member` class provides an
`updateValidator` hook for developers to modify the core method. The `MyMemberExtension` would modify the core member's
validator by defining the `updateValidator` method.
2018-06-25 00:39:53 +02:00
**app/code/extensions/MyMemberExtension.php**
2014-10-22 12:47:56 +02:00
2017-08-03 02:51:32 +02:00
```php
2017-10-27 04:38:27 +02:00
use SilverStripe\ORM\DataExtension;
2017-08-05 00:45:24 +02:00
2017-10-27 04:38:27 +02:00
class MyMemberExtension extends DataExtension
{
public function updateValidator($validator)
2017-08-07 05:11:17 +02:00
{
2017-10-27 04:38:27 +02:00
// we want to make date of birth required for each member
$validator->addRequiredField('DateOfBirth');
2017-08-07 05:11:17 +02:00
}
2017-10-27 04:38:27 +02:00
}
2017-08-03 02:51:32 +02:00
```
2014-10-22 12:47:56 +02:00
2019-11-18 05:58:33 +01:00
[info]
2014-10-22 12:47:56 +02:00
The `$validator` parameter is passed by reference, as it is an object.
2019-11-18 05:58:33 +01:00
[/info]
2014-10-22 12:47:56 +02:00
Another common example of when you will want to modify a method is to update the default CMS fields for an object in an
extension. The `CMS` provides a `updateCMSFields` Extension Hook to tie into.
2017-08-03 02:51:32 +02:00
```php
2018-06-09 19:41:33 +02:00
use SilverStripe\Forms\FieldList;
2017-10-27 04:38:27 +02:00
use SilverStripe\Forms\TextField;
use SilverStripe\AssetAdmin\Forms\UploadField;
use SilverStripe\ORM\DataExtension;
2017-08-05 00:45:24 +02:00
2017-10-27 04:38:27 +02:00
class MyMemberExtension extends DataExtension
{
2014-10-22 12:47:56 +02:00
2017-10-27 04:38:27 +02:00
private static $db = [
'Position' => 'Varchar',
];
2014-10-22 12:47:56 +02:00
2017-10-27 04:38:27 +02:00
private static $has_one = [
'Image' => 'Image',
];
2014-10-22 12:47:56 +02:00
2017-10-27 04:38:27 +02:00
public function updateCMSFields(FieldList $fields)
{
$fields->push(new TextField('Position'));
$fields->push($upload = new UploadField('Image', 'Profile Image'));
$upload->setAllowedFileCategories('image/supported');
2017-08-07 05:11:17 +02:00
}
2017-10-27 04:38:27 +02:00
}
2017-08-03 02:51:32 +02:00
```
2014-10-22 12:47:56 +02:00
2019-11-18 05:58:33 +01:00
[notice]
2014-10-22 12:47:56 +02:00
If you're providing a module or working on code that may need to be extended by other code, it should provide a *hook*
which allows an Extension to modify the results.
2019-11-18 05:58:33 +01:00
[/notice]
2014-10-22 12:47:56 +02:00
2017-08-03 02:51:32 +02:00
```php
2017-10-27 04:38:27 +02:00
public function Foo()
{
$foo = // ..
2014-10-22 12:47:56 +02:00
2017-10-27 04:38:27 +02:00
$this->extend('updateFoo', $foo);
2014-10-22 12:47:56 +02:00
2017-10-27 04:38:27 +02:00
return $foo;
}
2017-08-03 02:51:32 +02:00
```
2014-10-22 12:47:56 +02:00
The convention for extension hooks is to provide an `update{$Function}` hook at the end before you return the result. If
you need to provide extension hooks at the beginning of the method use `before{..}` .
## Owner
2017-07-03 03:22:12 +02:00
In your [Extension ](api:SilverStripe\Core\Extension ) class you can only refer to the source object through the `owner` property on the class as
2014-10-22 12:47:56 +02:00
`$this` will refer to your `Extension` instance.
2017-08-03 02:51:32 +02:00
```php
2017-10-27 04:38:27 +02:00
use SilverStripe\ORM\DataExtension;
2017-08-05 00:45:24 +02:00
2017-10-27 04:38:27 +02:00
class MyMemberExtension extends DataExtension
{
public function updateFoo($foo)
2017-08-07 05:11:17 +02:00
{
2017-10-27 04:38:27 +02:00
// outputs the original class
var_dump($this->owner);
2017-08-07 05:11:17 +02:00
}
2017-10-27 04:38:27 +02:00
}
2017-08-03 02:51:32 +02:00
```
2014-10-22 12:47:56 +02:00
2020-01-12 22:47:28 +01:00
[notice]
2020-01-12 23:22:00 +01:00
Please note that while you can read protected properties of the source object (using `$this->owner->protectedProperty` ) you cannot call any of it's protected methods (`$this->owner->protectedMethod()` will not work). You also cannot access any of the source object's private properties or methods (`$this->owner->privateProperty` will not work either).
2020-01-12 22:47:28 +01:00
[/notice]
2014-10-22 12:47:56 +02:00
## Checking to see if an Object has an Extension
2017-08-07 02:09:39 +02:00
To see what extensions are currently enabled on an object, use the [getExtensionInstances() ](api:SilverStripe\Core\Extensible::getExtensionInstances( )) and
[hasExtension() ](api:SilverStripe\Core\Extensible::hasExtension( )) methods of the [Extensible ](api:SilverStripe\Core\Extensible ) trait.
2017-10-27 04:38:27 +02:00
2017-08-03 02:51:32 +02:00
```php
2017-10-27 04:38:27 +02:00
$member = Security::getCurrentUser();
2014-10-22 12:47:56 +02:00
2017-10-27 04:38:27 +02:00
print_r($member->getExtensionInstances());
2018-11-26 00:00:02 +01:00
if ($member->hasExtension(MyCustomMemberExtension::class)) {
2017-10-27 04:38:27 +02:00
// ..
}
2017-08-03 02:51:32 +02:00
```
2014-10-22 12:47:56 +02:00
2017-08-07 02:09:39 +02:00
## Extension injection points
2014-10-22 12:47:56 +02:00
2017-08-07 02:09:39 +02:00
`Extensible` has two additional methods, `beforeExtending` and `afterExtending` , each of which takes a method name and a
callback to be executed immediately before and after `extend()` is called on extensions.
2014-10-22 12:47:56 +02:00
This is useful in many cases where working with modules such as `Translatable` which operate on `DataObject` fields
that must exist in the `FieldList` at the time that `$this->extend('UpdateCMSFields')` is called.
2019-11-18 05:58:33 +01:00
[notice]
2014-10-22 12:47:56 +02:00
Please note that each callback is only ever called once, and then cleared, so multiple extensions to the same function
require that a callback is registered each time, if necessary.
2019-11-18 05:58:33 +01:00
[/notice]
2014-10-22 12:47:56 +02:00
Example: A class that wants to control default values during object initialization. The code needs to assign a value
if not specified in `self::$defaults` , but before extensions have been called:
2017-08-03 02:51:32 +02:00
```php
2017-10-27 04:38:27 +02:00
public function __construct()
{
$this->beforeExtending('populateDefaults', function() {
2018-11-26 00:00:02 +01:00
if (empty($this->MyField)) {
2017-10-27 04:38:27 +02:00
$this->MyField = 'Value we want as a default if not specified in $defaults, but set before extensions';
}
});
2014-10-22 12:47:56 +02:00
2017-10-27 04:38:27 +02:00
parent::__construct();
}
2017-08-03 02:51:32 +02:00
```
2014-10-22 12:47:56 +02:00
Example 2: User code can intervene in the process of extending cms fields.
2019-11-18 05:58:33 +01:00
[notice]
2014-10-22 12:47:56 +02:00
This method is preferred to disabling, enabling, and calling field extensions manually.
2019-11-18 05:58:33 +01:00
[/notice]
2014-10-22 12:47:56 +02:00
2017-08-03 02:51:32 +02:00
```php
2017-10-27 04:38:27 +02:00
public function getCMSFields()
{
2018-11-26 00:00:02 +01:00
$this->beforeUpdateCMSFields(function ($fields) {
2017-10-27 04:38:27 +02:00
// Include field which must be present when updateCMSFields is called on extensions
2018-11-26 00:00:02 +01:00
$fields->addFieldToTab('Root.Main', new TextField('Detail', 'Details', null, 255));
2017-10-27 04:38:27 +02:00
});
$fields = parent::getCMSFields();
// ... additional fields here
return $fields;
}
2017-08-03 02:51:32 +02:00
```
2014-10-22 12:47:56 +02:00
2018-11-26 00:00:02 +01:00
## Extending extensions {#extendingextensions}
Extension classes can be overloaded using the Injector, if you want to modify the way that an extension in one of
your modules works:
```yaml
SilverStripe\Core\Injector\Injector:
Company\Vendor\SomeExtension:
class: App\Project\CustomisedSomeExtension
```
**app/src/CustomisedSomeExtension.php**
```php
namespace App\Project;
use Company\Vendor\SomeExtension;
class CustomisedSomeExtension extends SomeExtension
{
public function someMethod()
{
$result = parent::someMethod();
// modify result;
return $result;
}
}
```
2019-11-18 05:58:33 +01:00
[notice]
2018-11-26 00:00:02 +01:00
Please note that modifications such as this should be done in YAML configuration only. It is not recommended
to use `Config::modify()->set()` to adjust the implementation class name of an extension after the configuration
manifest has been loaded, and may not work consistently due to the "extra methods" cache having already been
populated.
2019-11-18 05:58:33 +01:00
[/notice]
2018-11-26 00:00:02 +01:00
2017-11-27 04:39:17 +01:00
## Related Lessons
2018-11-26 00:00:02 +01:00
* [DataExtensions and SiteConfig ](https://www.silverstripe.org/learn/lessons/v4/data-extensions-and-siteconfig-1 )
2017-11-27 04:39:17 +01:00
2014-10-22 12:47:56 +02:00
## Related Documentaion
* [Injector ](injector/ )
## API Documentation
2017-07-03 03:22:12 +02:00
* [Extension ](api:SilverStripe\Core\Extension )
* [DataExtension ](api:SilverStripe\ORM\DataExtension )