mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merged pull request #25 from ajshort/3a1c2df4e73390c18b98902f8e07d5d36472c945.
Rename DataObjectDecorator to DataExtension
This commit is contained in:
commit
4f31f48783
@ -86,7 +86,7 @@ class LeftAndMain extends Controller {
|
|||||||
// cms menus only for logged-in members
|
// cms menus only for logged-in members
|
||||||
if(!$member) return false;
|
if(!$member) return false;
|
||||||
|
|
||||||
// alternative decorated checks
|
// alternative extended checks
|
||||||
if($this->hasMethod('alternateAccessCheck')) {
|
if($this->hasMethod('alternateAccessCheck')) {
|
||||||
$alternateAllowed = $this->alternateAccessCheck();
|
$alternateAllowed = $this->alternateAccessCheck();
|
||||||
if($alternateAllowed === FALSE) return false;
|
if($alternateAllowed === FALSE) return false;
|
||||||
@ -102,8 +102,8 @@ class LeftAndMain extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @uses LeftAndMainDecorator->init()
|
* @uses LeftAndMainExtension->init()
|
||||||
* @uses LeftAndMainDecorator->accessedCMS()
|
* @uses LeftAndMainExtension->accessedCMS()
|
||||||
* @uses CMSMenu
|
* @uses CMSMenu
|
||||||
*/
|
*/
|
||||||
function init() {
|
function init() {
|
||||||
@ -124,7 +124,7 @@ class LeftAndMain extends Controller {
|
|||||||
self::$help_link
|
self::$help_link
|
||||||
);
|
);
|
||||||
|
|
||||||
// Allow customisation of the access check by a decorator
|
// Allow customisation of the access check by a extension
|
||||||
// Also all the canView() check to execute Director::redirect()
|
// Also all the canView() check to execute Director::redirect()
|
||||||
if(!$this->canView() && !$this->response->isFinished()) {
|
if(!$this->canView() && !$this->response->isFinished()) {
|
||||||
// When access /admin/, we should try a redirect to another part of the admin rather than be locked out
|
// When access /admin/, we should try a redirect to another part of the admin rather than be locked out
|
||||||
|
@ -1,21 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Plug-ins for additional functionality in your LeftAndMain classes.
|
* @package sapphire
|
||||||
*
|
* @subpackage admin
|
||||||
* @package cms
|
* @deprecated 3.0 Use {@link LeftAndMainExtension}
|
||||||
* @subpackage core
|
|
||||||
*/
|
*/
|
||||||
abstract class LeftAndMainDecorator extends Extension {
|
abstract class LeftAndMainDecorator extends LeftAndMainExtension {
|
||||||
|
|
||||||
function init() {
|
public function __construct() {
|
||||||
}
|
user_error(
|
||||||
|
'LeftAndMainDecorator is deprecated, please use LeftAndMainExtension instead.',
|
||||||
function accessedCMS() {
|
E_USER_NOTICE
|
||||||
}
|
);
|
||||||
|
parent::__construct();
|
||||||
function augmentNewSiteTreeItem(&$item) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
|
19
admin/code/LeftAndMainExtension.php
Normal file
19
admin/code/LeftAndMainExtension.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Plug-ins for additional functionality in your LeftAndMain classes.
|
||||||
|
*
|
||||||
|
* @package cms
|
||||||
|
* @subpackage core
|
||||||
|
*/
|
||||||
|
abstract class LeftAndMainExtension extends Extension {
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
function accessedCMS() {
|
||||||
|
}
|
||||||
|
|
||||||
|
function augmentNewSiteTreeItem(&$item) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -87,7 +87,7 @@
|
|||||||
* @todo URL parameter namespacing for search-fields, limit, fields, add_fields (might all be valid dataobject properties)
|
* @todo URL parameter namespacing for search-fields, limit, fields, add_fields (might all be valid dataobject properties)
|
||||||
* e.g. you wouldn't be able to search for a "limit" property on your subclass as its overlayed with the search logic
|
* e.g. you wouldn't be able to search for a "limit" property on your subclass as its overlayed with the search logic
|
||||||
* @todo i18n integration (e.g. Page/1.xml?lang=de_DE)
|
* @todo i18n integration (e.g. Page/1.xml?lang=de_DE)
|
||||||
* @todo Access to decoratable methods/relations like SiteTree/1/Versions or SiteTree/1/Version/22
|
* @todo Access to extendable methods/relations like SiteTree/1/Versions or SiteTree/1/Version/22
|
||||||
* @todo Respect $api_access array notation in search contexts
|
* @todo Respect $api_access array notation in search contexts
|
||||||
*
|
*
|
||||||
* @package sapphire
|
* @package sapphire
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Add extension that can be added to an object with {@link Object::add_extension()}.
|
* Add extension that can be added to an object with {@link Object::add_extension()}.
|
||||||
* For {@link DataObject} extensions, use {@link DataObjectDecorator}.
|
* For {@link DataObject} extensions, use {@link DataExtension}.
|
||||||
* Each extension instance has an "owner" instance, accessible through
|
* Each extension instance has an "owner" instance, accessible through
|
||||||
* {@link getOwner()}.
|
* {@link getOwner()}.
|
||||||
* Every object instance gets its own set of extension instances,
|
* Every object instance gets its own set of extension instances,
|
||||||
@ -19,8 +19,9 @@ abstract class Extension {
|
|||||||
public static $allowed_actions = null;
|
public static $allowed_actions = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The DataObject that owns this decorator.
|
* The object this extension is applied to.
|
||||||
* @var DataObject
|
*
|
||||||
|
* @var Object
|
||||||
*/
|
*/
|
||||||
protected $owner;
|
protected $owner;
|
||||||
|
|
||||||
@ -43,7 +44,7 @@ abstract class Extension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the owner of this decorator.
|
* Set the owner of this extension.
|
||||||
* @param Object $owner The owner object,
|
* @param Object $owner The owner object,
|
||||||
* @param string $ownerBaseClass The base class that the extension is applied to; this may be
|
* @param string $ownerBaseClass The base class that the extension is applied to; this may be
|
||||||
* the class of owner, or it may be a parent. For example, if Versioned was applied to SiteTree,
|
* the class of owner, or it may be a parent. For example, if Versioned was applied to SiteTree,
|
||||||
@ -65,7 +66,7 @@ abstract class Extension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the owner of this decorator
|
* Returns the owner of this extension.
|
||||||
*
|
*
|
||||||
* @return Object
|
* @return Object
|
||||||
*/
|
*/
|
||||||
|
@ -277,7 +277,6 @@ abstract class Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!isset(self::$cached_statics[$class][$name]) || $uncached) {
|
if(!isset(self::$cached_statics[$class][$name]) || $uncached) {
|
||||||
//if($class == 'DataObjectDecoratorTest_MyObject') Debug::message("$class - $name");
|
|
||||||
$extra = $builtIn = $break = $replacedAt = false;
|
$extra = $builtIn = $break = $replacedAt = false;
|
||||||
$ancestry = array_reverse(ClassInfo::ancestry($class));
|
$ancestry = array_reverse(ClassInfo::ancestry($class));
|
||||||
|
|
||||||
@ -500,7 +499,7 @@ abstract class Object {
|
|||||||
* Keep in mind that the extension will only be applied to new
|
* Keep in mind that the extension will only be applied to new
|
||||||
* instances, not existing ones (including all instances created through {@link singleton()}).
|
* instances, not existing ones (including all instances created through {@link singleton()}).
|
||||||
*
|
*
|
||||||
* @param string $class Class that should be decorated - has to be a subclass of {@link Object}
|
* @param string $class Class that should be extended - has to be a subclass of {@link Object}
|
||||||
* @param string $extension Subclass of {@link Extension} with optional parameters
|
* @param string $extension Subclass of {@link Extension} with optional parameters
|
||||||
* as a string, e.g. "Versioned" or "Translatable('Param')"
|
* as a string, e.g. "Versioned" or "Translatable('Param')"
|
||||||
*/
|
*/
|
||||||
@ -538,11 +537,11 @@ abstract class Object {
|
|||||||
|
|
||||||
// load statics now for DataObject classes
|
// load statics now for DataObject classes
|
||||||
if(is_subclass_of($class, 'DataObject')) {
|
if(is_subclass_of($class, 'DataObject')) {
|
||||||
if(is_subclass_of($extensionClass, 'DataObjectDecorator')) {
|
if(is_subclass_of($extensionClass, 'DataExtension')) {
|
||||||
DataObjectDecorator::load_extra_statics($class, $extension);
|
DataExtension::load_extra_statics($class, $extension);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
user_error("$extensionClass cannot be applied to $class without being a DataObjectDecorator", E_USER_ERROR);
|
user_error("$extensionClass cannot be applied to $class without being a DataExtension", E_USER_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -568,11 +567,11 @@ abstract class Object {
|
|||||||
$extensionClass = $matches[1];
|
$extensionClass = $matches[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_subclass_of($extensionClass, 'DataObjectDecorator')) {
|
if(is_subclass_of($extensionClass, 'DataExtension')) {
|
||||||
DataObjectDecorator::load_extra_statics($class, $extension);
|
DataExtension::load_extra_statics($class, $extension);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
user_error("$extensionClass cannot be applied to $class without being a DataObjectDecorator", E_USER_ERROR);
|
user_error("$extensionClass cannot be applied to $class without being a DataExtension", E_USER_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -624,7 +623,7 @@ abstract class Object {
|
|||||||
* @param string $class
|
* @param string $class
|
||||||
* @param bool $includeArgumentString Include the argument string in the return array,
|
* @param bool $includeArgumentString Include the argument string in the return array,
|
||||||
* FALSE would return array("Versioned"), TRUE returns array("Versioned('Stage','Live')").
|
* FALSE would return array("Versioned"), TRUE returns array("Versioned('Stage','Live')").
|
||||||
* @return array Numeric array of either {@link DataObjectDecorator} classnames,
|
* @return array Numeric array of either {@link DataExtension} classnames,
|
||||||
* or eval'ed classname strings with constructor arguments.
|
* or eval'ed classname strings with constructor arguments.
|
||||||
*/
|
*/
|
||||||
function get_extensions($class, $includeArgumentString = false) {
|
function get_extensions($class, $includeArgumentString = false) {
|
||||||
@ -950,7 +949,7 @@ abstract class Object {
|
|||||||
* you wanted to return results, you're hosed
|
* you wanted to return results, you're hosed
|
||||||
*
|
*
|
||||||
* Currently returns an array, with an index resulting every time the function is called. Only adds returns if
|
* Currently returns an array, with an index resulting every time the function is called. Only adds returns if
|
||||||
* they're not NULL, to avoid bogus results from methods just defined on the parent decorator. This is important for
|
* they're not NULL, to avoid bogus results from methods just defined on the parent extension. This is important for
|
||||||
* permission-checks through extend, as they use min() to determine if any of the returns is FALSE. As min() doesn't
|
* permission-checks through extend, as they use min() to determine if any of the returns is FALSE. As min() doesn't
|
||||||
* do type checking, an included NULL return would fail the permission checks.
|
* do type checking, an included NULL return would fail the permission checks.
|
||||||
*
|
*
|
||||||
@ -992,7 +991,7 @@ abstract class Object {
|
|||||||
* in {@link $extension_instances}. Extension instances are initialized
|
* in {@link $extension_instances}. Extension instances are initialized
|
||||||
* at constructor time, meaning if you use {@link add_extension()}
|
* at constructor time, meaning if you use {@link add_extension()}
|
||||||
* afterwards, the added extension will just be added to new instances
|
* afterwards, the added extension will just be added to new instances
|
||||||
* of the decorated class. Use the static method {@link has_extension()}
|
* of the extended class. Use the static method {@link has_extension()}
|
||||||
* to check if a class (not an instance) has a specific extension.
|
* to check if a class (not an instance) has a specific extension.
|
||||||
* Caution: Don't use singleton(<class>)->hasExtension() as it will
|
* Caution: Don't use singleton(<class>)->hasExtension() as it will
|
||||||
* give you inconsistent results based on when the singleton was first
|
* give you inconsistent results based on when the singleton was first
|
||||||
@ -1010,7 +1009,7 @@ abstract class Object {
|
|||||||
* See {@link get_extensions()} to get all applied extension classes
|
* See {@link get_extensions()} to get all applied extension classes
|
||||||
* for this class (not the instance).
|
* for this class (not the instance).
|
||||||
*
|
*
|
||||||
* @return array Map of {@link DataObjectDecorator} instances, keyed by classname.
|
* @return array Map of {@link DataExtension} instances, keyed by classname.
|
||||||
*/
|
*/
|
||||||
public function getExtensionInstances() {
|
public function getExtensionInstances() {
|
||||||
return $this->extension_instances;
|
return $this->extension_instances;
|
||||||
|
@ -688,9 +688,9 @@ class SapphireTest extends PHPUnit_Framework_TestCase {
|
|||||||
$dbConn = DB::getConn();
|
$dbConn = DB::getConn();
|
||||||
$dbName = $dbConn->currentDatabase();
|
$dbName = $dbConn->currentDatabase();
|
||||||
if($dbName && DB::getConn()->databaseExists($dbName)) {
|
if($dbName && DB::getConn()->databaseExists($dbName)) {
|
||||||
// Some DataObjectsDecorators keep a static cache of information that needs to
|
// Some DataExtensions keep a static cache of information that needs to
|
||||||
// be reset whenever the database is killed
|
// be reset whenever the database is killed
|
||||||
foreach(ClassInfo::subclassesFor('DataObjectDecorator') as $class) {
|
foreach(ClassInfo::subclassesFor('DataExtension') as $class) {
|
||||||
$toCall = array($class, 'on_db_reset');
|
$toCall = array($class, 'on_db_reset');
|
||||||
if(is_callable($toCall)) call_user_func($toCall);
|
if(is_callable($toCall)) call_user_func($toCall);
|
||||||
}
|
}
|
||||||
@ -709,9 +709,9 @@ class SapphireTest extends PHPUnit_Framework_TestCase {
|
|||||||
$dbadmin = new DatabaseAdmin();
|
$dbadmin = new DatabaseAdmin();
|
||||||
$dbadmin->clearAllData();
|
$dbadmin->clearAllData();
|
||||||
|
|
||||||
// Some DataObjectsDecorators keep a static cache of information that needs to
|
// Some DataExtensions keep a static cache of information that needs to
|
||||||
// be reset whenever the database is cleaned out
|
// be reset whenever the database is cleaned out
|
||||||
foreach(array_merge(ClassInfo::subclassesFor('DataObjectDecorator'), ClassInfo::subclassesFor('DataObject')) as $class) {
|
foreach(array_merge(ClassInfo::subclassesFor('DataExtension'), ClassInfo::subclassesFor('DataObject')) as $class) {
|
||||||
$toCall = array($class, 'on_db_reset');
|
$toCall = array($class, 'on_db_reset');
|
||||||
if(is_callable($toCall)) call_user_func($toCall);
|
if(is_callable($toCall)) call_user_func($toCall);
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
# DataObjectDecorator
|
# DataExtension
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
Extensions (also referred to as decorators) allow for adding additional functionality to a `[api:DataObject]`.
|
Extensions allow for adding additional functionality to a `[api:DataObject]`.
|
||||||
|
|
||||||
In some cases, it can be easier to completely replace the used class throughout the core with your custom
|
In some cases, it can be easier to completely replace the used class throughout the core with your custom
|
||||||
implementation. Have a look at `[api:Object->useCustomClass()]`.
|
implementation. Have a look at `[api:Object->useCustomClass()]`.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Your Decorator will nee to be a subclass of `[api:DataObjectDecorator]` or the `[api:Extension]` class.
|
Your extension will nee to be a subclass of `[api:DataExtension]` or the `[api:Extension]` class.
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
// mysite/code/CustomMember.php
|
// mysite/code/CustomMember.php
|
||||||
|
|
||||||
class CustomMember extends DataObjectDecorator {
|
class CustomMember extends DataExtension {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,10 +24,10 @@ This defines your own extension where you can add your own functions, database f
|
|||||||
After you create this extension however it does not yet apply it to your object. Next you need to tell SilverStripe what
|
After you create this extension however it does not yet apply it to your object. Next you need to tell SilverStripe what
|
||||||
class you want to extend.
|
class you want to extend.
|
||||||
|
|
||||||
### Adding a decorator to a built-in class
|
### Adding a extension to a built-in class
|
||||||
|
|
||||||
Sometimes you will want to add decorators to classes that you didn't make. For example, you might want to add the
|
Sometimes you will want to add extension to classes that you didn't make. For example, you might want to add the
|
||||||
`[api:ForumRole]` decorator to the `[api:Member]` object.
|
`[api:ForumRole]` extension to the `[api:Member]` object.
|
||||||
|
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
@ -45,12 +45,12 @@ For example above we want to override Member with a Custom Member so we would wr
|
|||||||
|
|
||||||
### Adding extra database fields
|
### Adding extra database fields
|
||||||
|
|
||||||
Extra database fields can be added with a decorator by defining an **extraStatics()** method. These will be added to the table of the base object - the decorator will actually edit the $db, $has_one, etc static variables on load.
|
Extra database fields can be added with a extension by defining an **extraStatics()** method. These will be added to the table of the base object - the extension will actually edit the $db, $has_one, etc static variables on load.
|
||||||
|
|
||||||
The function should return a map where the keys are the names of the static variables to update:
|
The function should return a map where the keys are the names of the static variables to update:
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
class CustomMember extends DataObjectDecorator {
|
class CustomMember extends DataExtension {
|
||||||
|
|
||||||
function extraStatics() {
|
function extraStatics() {
|
||||||
return array(
|
return array(
|
||||||
@ -67,7 +67,7 @@ The function should return a map where the keys are the names of the static vari
|
|||||||
|
|
||||||
*NOTE*
|
*NOTE*
|
||||||
If you want to add has_one or db items to a particular class, then that class **must** have that static variable
|
If you want to add has_one or db items to a particular class, then that class **must** have that static variable
|
||||||
explicitly defined, even if it's just a blank array. For example, the decorator method above wouldn't work if you added
|
explicitly defined, even if it's just a blank array. For example, the extension method above wouldn't work if you added
|
||||||
to a class that didn't have static $has_one explicitly declared on the object. This is because of PHP's crappy support
|
to a class that didn't have static $has_one explicitly declared on the object. This is because of PHP's crappy support
|
||||||
for statics.
|
for statics.
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ for statics.
|
|||||||
### Modifying CMS Fields
|
### Modifying CMS Fields
|
||||||
|
|
||||||
The member class demonstrates an extension that allows you to update the default CMS fields for an object in a
|
The member class demonstrates an extension that allows you to update the default CMS fields for an object in a
|
||||||
decorator:
|
extension:
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
public function getCMSFields() {
|
public function getCMSFields() {
|
||||||
@ -97,11 +97,11 @@ The $fields parameter is passed by reference, as it is an object.
|
|||||||
|
|
||||||
### Custom database generation
|
### Custom database generation
|
||||||
|
|
||||||
Some decorators are designed to transparently add more sophisticated data-collection capabilities to your data object.
|
Some extensions are designed to transparently add more sophisticated data-collection capabilities to your data object.
|
||||||
For example, `[api:Versioned]` adds version tracking and staging to any data object that it is applied to. To do this,
|
For example, `[api:Versioned]` adds version tracking and staging to any data object that it is applied to. To do this,
|
||||||
you need to be able to create additional database tables and fields to keep your state stored in.
|
you need to be able to create additional database tables and fields to keep your state stored in.
|
||||||
|
|
||||||
To do this, define an **augmentDatabase()** method on your decorator. This will be called when db/build is visited.
|
To do this, define an **augmentDatabase()** method on your extension. This will be called when db/build is visited.
|
||||||
|
|
||||||
* You can query ``$this->owner`` for information about the data object, such as the fields it has
|
* You can query ``$this->owner`` for information about the data object, such as the fields it has
|
||||||
* You can use **DB::requireTable($tableName, $fieldList, $indexList)** to set up your new tables. This function takes
|
* You can use **DB::requireTable($tableName, $fieldList, $indexList)** to set up your new tables. This function takes
|
||||||
@ -125,18 +125,18 @@ be modified as needed by your method. Instead of a manipulation array, we have
|
|||||||
|
|
||||||
### Additional methods
|
### Additional methods
|
||||||
|
|
||||||
The other thing you may want to do with a decorator is provide a method that can be called on the `[api:DataObject]` that is
|
The other thing you may want to do with a extension is provide a method that can be called on the `[api:DataObject]` that is
|
||||||
being decorated. For instance, you may add a publish() method to every `[api:DataObject]` that is decorated with `[api:Versioned]`.
|
being extended. For instance, you may add a publish() method to every `[api:DataObject]` that is extended with `[api:Versioned]`.
|
||||||
|
|
||||||
This is as simple as defining a method called publish() on your decorator. Bear in mind, however, that instead of
|
This is as simple as defining a method called publish() on your extension. Bear in mind, however, that instead of
|
||||||
$this, you should be referring to $this->owner.
|
$this, you should be referring to $this->owner.
|
||||||
|
|
||||||
* $this = The `[api:DataObjectDecorator]` object.
|
* $this = The `[api:DataExtension]` object.
|
||||||
* $this->owner = The related `[api:DataObject]` object.
|
* $this->owner = The related `[api:DataObject]` object.
|
||||||
|
|
||||||
If you want to add your own internal properties, you can add this to the `[api:DataObjectDecorator]`, and these will be referred
|
If you want to add your own internal properties, you can add this to the `[api:DataExtension]`, and these will be referred
|
||||||
to as `$this->propertyName`. Every `[api:DataObject]` has an associated `[api:DataObjectDecorator]` instance for each class that it is
|
to as `$this->propertyName`. Every `[api:DataObject]` has an associated `[api:DataExtension]` instance for each class that it is
|
||||||
decorated by.
|
extended by.
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
class Customer extends DataObject {
|
class Customer extends DataObject {
|
||||||
@ -159,7 +159,7 @@ decorated by.
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class CustomerWorkflow extends DataObjectDecorator {
|
class CustomerWorkflow extends DataExtension {
|
||||||
|
|
||||||
function IsMarkedForDeletion() {
|
function IsMarkedForDeletion() {
|
||||||
return ($this->owner->Account()->IsMarkedForDeletion == 1) ? true : false;
|
return ($this->owner->Account()->IsMarkedForDeletion == 1) ? true : false;
|
||||||
@ -169,4 +169,4 @@ decorated by.
|
|||||||
|
|
||||||
|
|
||||||
## API Documentation
|
## API Documentation
|
||||||
`[api:DataObjectDecorator]`
|
`[api:DataExtension]`
|
@ -40,7 +40,7 @@ These calls retrieve a `[api:FieldSet]` for the area where you intend to work wi
|
|||||||
### For the Frontend
|
### For the Frontend
|
||||||
|
|
||||||
Used for simple frontend forms without relation editing or `[api:TabSet] behaviour. Uses `scaffoldFormFields()` by
|
Used for simple frontend forms without relation editing or `[api:TabSet] behaviour. Uses `scaffoldFormFields()` by
|
||||||
default. To customize, either overload this method in your subclass, or decorate it by `DataObjectDecorator->updateFormFields()`.
|
default. To customize, either overload this method in your subclass, or extend it by `DataExtension->updateFormFields()`.
|
||||||
|
|
||||||
* Requirements: SilverStripe 2.3.*
|
* Requirements: SilverStripe 2.3.*
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ Reference articles complement our auto-generated [API docs](http://api.silverstr
|
|||||||
* [ComplexTableField](complextablefield): Manage records and their relations inside the CMS
|
* [ComplexTableField](complextablefield): Manage records and their relations inside the CMS
|
||||||
* [Database Structure](database-structure): Conventions and best practices for database tables and fields
|
* [Database Structure](database-structure): Conventions and best practices for database tables and fields
|
||||||
* [DataObject](dataobject): Base class for database records
|
* [DataObject](dataobject): Base class for database records
|
||||||
* [DataObjectDecorator](dataobjectdecorator): A "mixin" system allowing to extend core classes
|
* [DataExtension](dataextension): A "mixin" system allowing to extend core classes
|
||||||
* [DataObjectSet](dataobjectset): The base collection of database records in the ORM
|
* [DataObjectSet](dataobjectset): The base collection of database records in the ORM
|
||||||
* [Director](director): Routes URLs and handles HTTP requests
|
* [Director](director): Routes URLs and handles HTTP requests
|
||||||
* [Execution Pipeline](execution-pipeline): Detailed look on the way an HTTP request takes through the system
|
* [Execution Pipeline](execution-pipeline): Detailed look on the way an HTTP request takes through the system
|
||||||
|
@ -38,7 +38,7 @@ Returns the full *Member* Object for the current user, returns *null* if user is
|
|||||||
## Subclassing
|
## Subclassing
|
||||||
|
|
||||||
<div class="warning" markdown="1">
|
<div class="warning" markdown="1">
|
||||||
This is the least desirable way of extending the `[api:Member]` class. It's better to use `[api:DataObjectDecorator]`
|
This is the least desirable way of extending the `[api:Member]` class. It's better to use `[api:DataExtension]`
|
||||||
(see below).
|
(see below).
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -86,22 +86,22 @@ For persons without login-capabilities (e.g. for an address-database), you shoul
|
|||||||
with the Member-database. This enables us to have a different subclass of `[api:Member]` for an email-address with login-data,
|
with the Member-database. This enables us to have a different subclass of `[api:Member]` for an email-address with login-data,
|
||||||
and another subclass for the same email-address in the address-database.
|
and another subclass for the same email-address in the address-database.
|
||||||
|
|
||||||
## Member Role Decorator
|
## Member Role Extension
|
||||||
|
|
||||||
Using inheritance to add extra behaviour or data fields to a member is limiting, because you can only inherit from 1
|
Using inheritance to add extra behaviour or data fields to a member is limiting, because you can only inherit from 1
|
||||||
class. A better way is to use role decorators to add this behaviour.
|
class. A better way is to use role extensions to add this behaviour.
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
DataObject::add_extension('Member', 'ForumRole');
|
Object::add_extension('Member', 'ForumRole');
|
||||||
// OR
|
// OR
|
||||||
Member::add_role('ForumRole');
|
Member::add_role('ForumRole');
|
||||||
|
|
||||||
A role decorator is simply a subclass of `[api:DataObjectDecorator]` that is designed to be used to add behaviour to `[api:Member]`.
|
A role extension is simply a subclass of `[api:DataExtension]` that is designed to be used to add behaviour to `[api:Member]`.
|
||||||
The roles affect the entire class - all members will get the additional behaviour. However, if you want to restrict
|
The roles affect the entire class - all members will get the additional behaviour. However, if you want to restrict
|
||||||
things, you should add appropriate `[api:Permission::checkMember()]` calls to the role's methods.
|
things, you should add appropriate `[api:Permission::checkMember()]` calls to the role's methods.
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
class ForumRole extends DataObjectDecorator {
|
class ForumRole extends DataExtension {
|
||||||
/**
|
/**
|
||||||
|
|
||||||
* Modify the field set to be displayed in the CMS detail pop-up
|
* Modify the field set to be displayed in the CMS detail pop-up
|
||||||
|
@ -37,7 +37,7 @@ Create a mysite/code/CustomSiteConfig.php file.
|
|||||||
:::php
|
:::php
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
class CustomSiteConfig extends DataObjectDecorator {
|
class CustomSiteConfig extends DataExtension {
|
||||||
|
|
||||||
function extraStatics() {
|
function extraStatics() {
|
||||||
return array(
|
return array(
|
||||||
|
@ -35,7 +35,7 @@ Append the option and corresponding value to your URL in your browser's address
|
|||||||
|
|
||||||
| URL Variable | | Values | | Description |
|
| URL Variable | | Values | | Description |
|
||||||
| ------------ | | ------ | | ----------- |
|
| ------------ | | ------ | | ----------- |
|
||||||
| debugmethods | | 1 | | Shows all methods available when an object is constructed (useful when extending classes or using object decorators) |
|
| debugmethods | | 1 | | Shows all methods available when an object is constructed (useful when extending classes or using object extensions) |
|
||||||
| debugfailover | | 1 | | Shows failover methods from classes extended |
|
| debugfailover | | 1 | | Shows failover methods from classes extended |
|
||||||
|
|
||||||
## Database
|
## Database
|
||||||
|
@ -453,11 +453,11 @@ See `[api:SQLQuery]` for custom *INSERT*, *UPDATE*, *DELETE* queries.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Decorating DataObjects
|
## Extending DataObjects
|
||||||
|
|
||||||
You can add properties and methods to existing `[api:DataObjects]`s like `[api:Member]` (a core class) without hacking core
|
You can add properties and methods to existing `[api:DataObjects]`s like `[api:Member]` (a core class) without hacking core
|
||||||
code or subclassing.
|
code or subclassing.
|
||||||
Please see `[api:DataObjectDecorator]` for a general description, and `[api:Hierarchy]` for our most
|
Please see `[api:DataExtension]` for a general description, and `[api:Hierarchy]` for our most
|
||||||
popular examples.
|
popular examples.
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ project, like a forum, an ecommerce package or a blog you can do it like this;
|
|||||||
|
|
||||||
Try and keep your module as generic as possible - for example if you're making a forum module, your members section
|
Try and keep your module as generic as possible - for example if you're making a forum module, your members section
|
||||||
shouldn't contain fields like 'Games You Play' or 'Your LiveJournal Name' - if people want to add these fields they can
|
shouldn't contain fields like 'Games You Play' or 'Your LiveJournal Name' - if people want to add these fields they can
|
||||||
sub-class your class, or decorate the fields on to it.
|
sub-class your class, or extend the fields on to it.
|
||||||
|
|
||||||
If you're using Requirements to include generic support files for your project like CSS or Javascript, and want to
|
If you're using Requirements to include generic support files for your project like CSS or Javascript, and want to
|
||||||
override these files to be more specific in your project, the following code is an example of how to do so using the
|
override these files to be more specific in your project, the following code is an example of how to do so using the
|
||||||
@ -54,5 +54,5 @@ adherence to conventions, writing documentation, and releasing updates. See [con
|
|||||||
* [Modules](modules)
|
* [Modules](modules)
|
||||||
* [Module Release Process](module-release-process)
|
* [Module Release Process](module-release-process)
|
||||||
* [Debugging methods](/topics/debugging)
|
* [Debugging methods](/topics/debugging)
|
||||||
* [URL Variable Tools](/reference/urlvariabletools) - Lists a number of “page options” , “rendering tools” or “special
|
* [URL Variable Tools](/reference/urlvariabletools) - Lists a number of <EFBFBD><EFBFBD><EFBFBD>page options<6E><73><EFBFBD> , <20><><EFBFBD>rendering tools<6C><73><EFBFBD> or <20><><EFBFBD>special
|
||||||
URL variables” that you can use to debug your sapphire applications
|
URL variables<EFBFBD><EFBFBD><EFBFBD> that you can use to debug your sapphire applications
|
||||||
|
@ -13,7 +13,7 @@ Object::useCustomClass(), and the like. So, by unpacking a module into site's m
|
|||||||
|
|
||||||
* You can create subclasses of base classes such as SiteTree to extend behaviour.
|
* You can create subclasses of base classes such as SiteTree to extend behaviour.
|
||||||
* You can use Object::useCustomClass() to replace a built in class with a class of your own.
|
* You can use Object::useCustomClass() to replace a built in class with a class of your own.
|
||||||
* You can use [a decorator](api:DataObjectDecorator) to extend or alter the behaviour of a built-in class without replacing
|
* You can use [an extension](api:DataExtension) to extend or alter the behaviour of a built-in class without replacing
|
||||||
it.
|
it.
|
||||||
* You can provide additional director rules to define your own controller for particular URLs.
|
* You can provide additional director rules to define your own controller for particular URLs.
|
||||||
|
|
||||||
|
@ -385,8 +385,8 @@ class Folder extends File {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the FieldSet used to edit this folder in the CMS.
|
* Return the FieldSet used to edit this folder in the CMS.
|
||||||
* You can modify this fieldset by subclassing folder, or by creating a {@link DataObjectDecorator}
|
* You can modify this fieldset by subclassing folder, or by creating a {@link DataExtension}
|
||||||
* and implemeting updateCMSFields(FieldSet $fields) on that decorator.
|
* and implemeting updateCMSFields(FieldSet $fields) on that extension.
|
||||||
*/
|
*/
|
||||||
function getCMSFields() {
|
function getCMSFields() {
|
||||||
$fileList = new AssetTableField(
|
$fileList = new AssetTableField(
|
||||||
|
231
model/DataExtension.php
Executable file
231
model/DataExtension.php
Executable file
@ -0,0 +1,231 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* An extension that adds additional functionality to a {@link DataObject}.
|
||||||
|
*
|
||||||
|
* @package sapphire
|
||||||
|
* @subpackage model
|
||||||
|
*/
|
||||||
|
abstract class DataExtension extends Extension {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Statics on a {@link DataObject} subclass
|
||||||
|
* which can be extended by an extension. This list is
|
||||||
|
* limited for security and performance reasons.
|
||||||
|
*
|
||||||
|
* Keys are the static names, and the values are whether or not the value is an array that should
|
||||||
|
* be merged.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected static $extendable_statics = array(
|
||||||
|
'db' => true,
|
||||||
|
'has_one' => true,
|
||||||
|
'belongs_to' => true,
|
||||||
|
'indexes' => true,
|
||||||
|
'defaults' => true,
|
||||||
|
'has_many' => true,
|
||||||
|
'many_many' => true,
|
||||||
|
'belongs_many_many' => true,
|
||||||
|
'many_many_extraFields' => true,
|
||||||
|
'searchable_fields' => true,
|
||||||
|
'api_access' => false,
|
||||||
|
);
|
||||||
|
|
||||||
|
private static $extra_statics_loaded = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the extra static definitions for the given extension
|
||||||
|
* class name, called by {@link Object::add_extension()}
|
||||||
|
*
|
||||||
|
* @param string $class Class name of the owner class (or owner base class)
|
||||||
|
* @param string $extension Class name of the extension class
|
||||||
|
*/
|
||||||
|
public static function load_extra_statics($class, $extension) {
|
||||||
|
if(!empty(self::$extra_statics_loaded[$class][$extension])) return;
|
||||||
|
self::$extra_statics_loaded[$class][$extension] = true;
|
||||||
|
|
||||||
|
if(preg_match('/^([^(]*)/', $extension, $matches)) {
|
||||||
|
$extensionClass = $matches[1];
|
||||||
|
} else {
|
||||||
|
user_error("Bad extenion '$extension' - can't find classname", E_USER_WARNING);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @deprecated 2.4 - use extraStatics() now, not extraDBFields()
|
||||||
|
if(method_exists($extensionClass, 'extraDBFields')) {
|
||||||
|
user_error('DataExtension::extraDBFields() is deprecated. Please use extraStatics() instead.', E_USER_NOTICE);
|
||||||
|
$extraStaticsMethod = 'extraDBFields';
|
||||||
|
} else {
|
||||||
|
$extraStaticsMethod = 'extraStatics';
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the extension has been manually applied to a subclass, we should ignore that.
|
||||||
|
if(Object::has_extension(get_parent_class($class), $extensionClass)) return;
|
||||||
|
|
||||||
|
$statics = call_user_func(array($extensionClass, $extraStaticsMethod), $class, $extension);
|
||||||
|
|
||||||
|
if($statics) {
|
||||||
|
foreach($statics as $name => $newVal) {
|
||||||
|
if(isset(self::$extendable_statics[$name])) {
|
||||||
|
|
||||||
|
// Array to be merged
|
||||||
|
if(self::$extendable_statics[$name]) {
|
||||||
|
$origVal = Object::uninherited_static($class, $name);
|
||||||
|
// Can't use add_static_var() here as it would merge the array rather than replacing
|
||||||
|
Object::set_static($class, $name, array_merge((array)$origVal, $newVal));
|
||||||
|
|
||||||
|
// Value to be overwritten
|
||||||
|
} else {
|
||||||
|
Object::set_static($class, $name, $newVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DataObject::$cache_has_own_table[$class] = null;
|
||||||
|
DataObject::$cache_has_own_table_field[$class] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edit the given query object to support queries for this extension
|
||||||
|
*
|
||||||
|
* @param SQLQuery $query Query to augment.
|
||||||
|
*/
|
||||||
|
function augmentSQL(SQLQuery &$query) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the database schema as required by this extension.
|
||||||
|
*/
|
||||||
|
function augmentDatabase() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Augment a write-record request.
|
||||||
|
*
|
||||||
|
* @param SQLQuery $manipulation Query to augment.
|
||||||
|
*/
|
||||||
|
function augmentWrite(&$manipulation) {
|
||||||
|
}
|
||||||
|
|
||||||
|
function onBeforeWrite() {
|
||||||
|
}
|
||||||
|
|
||||||
|
function onAfterWrite() {
|
||||||
|
}
|
||||||
|
|
||||||
|
function onBeforeDelete() {
|
||||||
|
}
|
||||||
|
|
||||||
|
function onAfterDelete() {
|
||||||
|
}
|
||||||
|
|
||||||
|
function requireDefaultRecords() {
|
||||||
|
}
|
||||||
|
|
||||||
|
function populateDefaults() {
|
||||||
|
}
|
||||||
|
|
||||||
|
function can($member) {
|
||||||
|
}
|
||||||
|
|
||||||
|
function canEdit($member) {
|
||||||
|
}
|
||||||
|
|
||||||
|
function canDelete($member) {
|
||||||
|
}
|
||||||
|
|
||||||
|
function canCreate($member) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define extra database fields
|
||||||
|
*
|
||||||
|
* Return a map where the keys are db, has_one, etc, and the values are
|
||||||
|
* additional fields/relations to be defined.
|
||||||
|
*
|
||||||
|
* @return array Returns a map where the keys are db, has_one, etc, and
|
||||||
|
* the values are additional fields/relations to be defined.
|
||||||
|
*/
|
||||||
|
function extraStatics() {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is used to provide modifications to the form in the CMS
|
||||||
|
* by the extension. By default, no changes are made. {@link DataObject->getCMSFields()}.
|
||||||
|
*
|
||||||
|
* Please consider using {@link updateFormFields()} to globally add
|
||||||
|
* formfields to the record. The method {@link updateCMSFields()}
|
||||||
|
* should just be used to add or modify tabs, or fields which
|
||||||
|
* are specific to the CMS-context.
|
||||||
|
*
|
||||||
|
* Caution: Use {@link FieldSet->addFieldToTab()} to add fields.
|
||||||
|
*
|
||||||
|
* @param FieldSet $fields FieldSet with a contained TabSet
|
||||||
|
*/
|
||||||
|
function updateCMSFields(FieldSet &$fields) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is used to provide modifications to the form used
|
||||||
|
* for front end forms. {@link DataObject->getFrontEndFields()}
|
||||||
|
*
|
||||||
|
* Caution: Use {@link FieldSet->push()} to add fields.
|
||||||
|
*
|
||||||
|
* @param FieldSet $fields FieldSet without TabSet nesting
|
||||||
|
*/
|
||||||
|
function updateFrontEndFields(FieldSet &$fields) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is used to provide modifications to the form actions
|
||||||
|
* used in the CMS. {@link DataObject->getCMSActions()}.
|
||||||
|
*
|
||||||
|
* @param FieldSet $actions FieldSet
|
||||||
|
*/
|
||||||
|
function updateCMSActions(FieldSet &$actions) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this function is used to provide modifications to the summary fields in CMS
|
||||||
|
* by the extension
|
||||||
|
* By default, the summaryField() of its owner will merge more fields defined in the extension's
|
||||||
|
* $extra_fields['summary_fields']
|
||||||
|
*/
|
||||||
|
function updateSummaryFields(&$fields){
|
||||||
|
$extra_fields = $this->extraStatics();
|
||||||
|
if(isset($extra_fields['summary_fields'])){
|
||||||
|
$summary_fields = $extra_fields['summary_fields'];
|
||||||
|
|
||||||
|
// if summary_fields were passed in numeric array,
|
||||||
|
// convert to an associative array
|
||||||
|
if($summary_fields && array_key_exists(0, $summary_fields)) {
|
||||||
|
$summary_fields = array_combine(array_values($summary_fields), array_values($summary_fields));
|
||||||
|
}
|
||||||
|
if($summary_fields) $fields = array_merge($fields, $summary_fields);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this function is used to provide modifications to the fields labels in CMS
|
||||||
|
* by the extension
|
||||||
|
* By default, the fieldLabels() of its owner will merge more fields defined in the extension's
|
||||||
|
* $extra_fields['field_labels']
|
||||||
|
*/
|
||||||
|
function updateFieldLabels(&$lables){
|
||||||
|
$extra_fields = $this->extraStatics();
|
||||||
|
if(isset($extra_fields['field_labels'])){
|
||||||
|
$field_labels = $extra_fields['field_labels'];
|
||||||
|
if($field_labels) $lables = array_merge($lables, $field_labels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear any internal caches.
|
||||||
|
*/
|
||||||
|
function flushCache() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
@ -2,9 +2,9 @@
|
|||||||
/**
|
/**
|
||||||
* A single database record & abstract class for the data-access-model.
|
* A single database record & abstract class for the data-access-model.
|
||||||
*
|
*
|
||||||
* <h2>Extensions and Decorators</h2>
|
* <h2>Extensions</h2>
|
||||||
*
|
*
|
||||||
* See {@link Extension} and {@link DataObjectDecorator}.
|
* See {@link Extension} and {@link DataExtension}.
|
||||||
*
|
*
|
||||||
* <h2>Permission Control</h2>
|
* <h2>Permission Control</h2>
|
||||||
*
|
*
|
||||||
@ -890,7 +890,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
*
|
*
|
||||||
* This called after {@link $this->validate()}, so you can be sure that your data is valid.
|
* This called after {@link $this->validate()}, so you can be sure that your data is valid.
|
||||||
*
|
*
|
||||||
* @uses DataObjectDecorator->onBeforeWrite()
|
* @uses DataExtension->onBeforeWrite()
|
||||||
*/
|
*/
|
||||||
protected function onBeforeWrite() {
|
protected function onBeforeWrite() {
|
||||||
$this->brokenOnWrite = false;
|
$this->brokenOnWrite = false;
|
||||||
@ -905,7 +905,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
* $this->changed will have a record
|
* $this->changed will have a record
|
||||||
* database. Don't forget to call parent::onAfterWrite(), though!
|
* database. Don't forget to call parent::onAfterWrite(), though!
|
||||||
*
|
*
|
||||||
* @uses DataObjectDecorator->onAfterWrite()
|
* @uses DataExtension->onAfterWrite()
|
||||||
*/
|
*/
|
||||||
protected function onAfterWrite() {
|
protected function onAfterWrite() {
|
||||||
$dummy = null;
|
$dummy = null;
|
||||||
@ -917,7 +917,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
* You can overload this to clean up or otherwise process data before delete this
|
* You can overload this to clean up or otherwise process data before delete this
|
||||||
* record. Don't forget to call parent::onBeforeDelete(), though!
|
* record. Don't forget to call parent::onBeforeDelete(), though!
|
||||||
*
|
*
|
||||||
* @uses DataObjectDecorator->onBeforeDelete()
|
* @uses DataExtension->onBeforeDelete()
|
||||||
*/
|
*/
|
||||||
protected function onBeforeDelete() {
|
protected function onBeforeDelete() {
|
||||||
$this->brokenOnDelete = false;
|
$this->brokenOnDelete = false;
|
||||||
@ -935,7 +935,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
* Will traverse the defaults of the current class and all its parent classes.
|
* Will traverse the defaults of the current class and all its parent classes.
|
||||||
* Called by the constructor when creating new records.
|
* Called by the constructor when creating new records.
|
||||||
*
|
*
|
||||||
* @uses DataObjectDecorator->populateDefaults()
|
* @uses DataExtension->populateDefaults()
|
||||||
*/
|
*/
|
||||||
public function populateDefaults() {
|
public function populateDefaults() {
|
||||||
$classes = array_reverse(ClassInfo::ancestry($this));
|
$classes = array_reverse(ClassInfo::ancestry($this));
|
||||||
@ -976,7 +976,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
* - Extensions such as Versioned will ammend the database-write to ensure that a version is saved.
|
* - Extensions such as Versioned will ammend the database-write to ensure that a version is saved.
|
||||||
* - Calls to {@link DataObjectLog} can be used to see everything that's been changed.
|
* - Calls to {@link DataObjectLog} can be used to see everything that's been changed.
|
||||||
*
|
*
|
||||||
* @uses DataObjectDecorator->augmentWrite()
|
* @uses DataExtension->augmentWrite()
|
||||||
*
|
*
|
||||||
* @param boolean $showDebug Show debugging information
|
* @param boolean $showDebug Show debugging information
|
||||||
* @param boolean $forceInsert Run INSERT command rather than UPDATE, even if record already exists
|
* @param boolean $forceInsert Run INSERT command rather than UPDATE, even if record already exists
|
||||||
@ -1183,7 +1183,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
* Delete this data object.
|
* Delete this data object.
|
||||||
* $this->onBeforeDelete() gets called.
|
* $this->onBeforeDelete() gets called.
|
||||||
* Note that in Versioned objects, both Stage and Live will be deleted.
|
* Note that in Versioned objects, both Stage and Live will be deleted.
|
||||||
* @uses DataObjectDecorator->augmentSQL()
|
* @uses DataExtension->augmentSQL()
|
||||||
*/
|
*/
|
||||||
public function delete() {
|
public function delete() {
|
||||||
$this->brokenOnDelete = true;
|
$this->brokenOnDelete = true;
|
||||||
@ -1983,7 +1983,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
* which returns a {@link FieldSet} suitable for a {@link Form} object.
|
* which returns a {@link FieldSet} suitable for a {@link Form} object.
|
||||||
* If not overloaded, we're using {@link scaffoldFormFields()} to automatically
|
* If not overloaded, we're using {@link scaffoldFormFields()} to automatically
|
||||||
* generate this set. To customize, overload this method in a subclass
|
* generate this set. To customize, overload this method in a subclass
|
||||||
* or decorate onto it by using {@link DataObjectDecorator->updateCMSFields()}.
|
* or extended onto it by using {@link DataExtension->updateCMSFields()}.
|
||||||
*
|
*
|
||||||
* <code>
|
* <code>
|
||||||
* klass MyCustomClass extends DataObject {
|
* klass MyCustomClass extends DataObject {
|
||||||
@ -2019,7 +2019,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* need to be overload by solid dataobject, so that the customised actions of that dataobject,
|
* need to be overload by solid dataobject, so that the customised actions of that dataobject,
|
||||||
* including that dataobject's decorator customised actions could be added to the EditForm.
|
* including that dataobject's extensions customised actions could be added to the EditForm.
|
||||||
*
|
*
|
||||||
* @return an Empty FieldSet(); need to be overload by solid subclass
|
* @return an Empty FieldSet(); need to be overload by solid subclass
|
||||||
*/
|
*/
|
||||||
@ -2034,7 +2034,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
* Used for simple frontend forms without relation editing
|
* Used for simple frontend forms without relation editing
|
||||||
* or {@link TabSet} behaviour. Uses {@link scaffoldFormFields()}
|
* or {@link TabSet} behaviour. Uses {@link scaffoldFormFields()}
|
||||||
* by default. To customize, either overload this method in your
|
* by default. To customize, either overload this method in your
|
||||||
* subclass, or decorate it by {@link DataObjectDecorator->updateFrontEndFields()}.
|
* subclass, or extend it by {@link DataExtension->updateFrontEndFields()}.
|
||||||
*
|
*
|
||||||
* @todo Decide on naming for "website|frontend|site|page" and stick with it in the API
|
* @todo Decide on naming for "website|frontend|site|page" and stick with it in the API
|
||||||
*
|
*
|
||||||
@ -2277,7 +2277,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
if($field == "LastEdited" && get_parent_class($this) == "DataObject") return "SS_Datetime";
|
if($field == "LastEdited" && get_parent_class($this) == "DataObject") return "SS_Datetime";
|
||||||
if($field == "Created" && get_parent_class($this) == "DataObject") return "SS_Datetime";
|
if($field == "Created" && get_parent_class($this) == "DataObject") return "SS_Datetime";
|
||||||
|
|
||||||
// Add fields from Versioned decorator
|
// Add fields from Versioned extension
|
||||||
if($field == 'Version' && $this->hasExtension('Versioned')) {
|
if($field == 'Version' && $this->hasExtension('Versioned')) {
|
||||||
return 'Int';
|
return 'Int';
|
||||||
}
|
}
|
||||||
@ -2408,11 +2408,11 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process tri-state responses from permission-alterting decorators. The decorators are
|
* Process tri-state responses from permission-alterting extensions. The extensions are
|
||||||
* expected to return one of three values:
|
* expected to return one of three values:
|
||||||
*
|
*
|
||||||
* - false: Disallow this permission, regardless of what other decorators say
|
* - false: Disallow this permission, regardless of what other extensions say
|
||||||
* - true: Allow this permission, as long as no other decorators return false
|
* - true: Allow this permission, as long as no other extensions return false
|
||||||
* - NULL: Don't affect the outcome
|
* - NULL: Don't affect the outcome
|
||||||
*
|
*
|
||||||
* This method itself returns a tri-state value, and is designed to be used like this:
|
* This method itself returns a tri-state value, and is designed to be used like this:
|
||||||
@ -2756,7 +2756,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
/**
|
/**
|
||||||
* Like {@link buildSQL}, but applies the extension modifications.
|
* Like {@link buildSQL}, but applies the extension modifications.
|
||||||
*
|
*
|
||||||
* @uses DataObjectDecorator->augmentSQL()
|
* @uses DataExtension->augmentSQL()
|
||||||
*
|
*
|
||||||
* @param string $filter A filter to be inserted into the WHERE clause.
|
* @param string $filter A filter to be inserted into the WHERE clause.
|
||||||
* @param string|array $sort A sort expression to be inserted into the ORDER BY clause. If omitted, self::$default_sort will be used.
|
* @param string|array $sort A sort expression to be inserted into the ORDER BY clause. If omitted, self::$default_sort will be used.
|
||||||
@ -2936,7 +2936,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
/**
|
/**
|
||||||
* Does the hard work for get_one()
|
* Does the hard work for get_one()
|
||||||
*
|
*
|
||||||
* @uses DataObjectDecorator->augmentSQL()
|
* @uses DataExtension->augmentSQL()
|
||||||
*
|
*
|
||||||
* @param string $filter A filter to be inserted into the WHERE clause
|
* @param string $filter A filter to be inserted into the WHERE clause
|
||||||
* @param string $orderby A sort expression to be inserted into the ORDER BY clause.
|
* @param string $orderby A sort expression to be inserted into the ORDER BY clause.
|
||||||
@ -3042,7 +3042,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
/**
|
/**
|
||||||
* Check the database schema and update it as necessary.
|
* Check the database schema and update it as necessary.
|
||||||
*
|
*
|
||||||
* @uses DataObjectDecorator->augmentDatabase()
|
* @uses DataExtension->augmentDatabase()
|
||||||
*/
|
*/
|
||||||
public function requireTable() {
|
public function requireTable() {
|
||||||
// Only build the table if we've actually got fields
|
// Only build the table if we've actually got fields
|
||||||
@ -3091,7 +3091,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
* this to add default records when the database is built, but make sure you
|
* this to add default records when the database is built, but make sure you
|
||||||
* call parent::requireDefaultRecords().
|
* call parent::requireDefaultRecords().
|
||||||
*
|
*
|
||||||
* @uses DataObjectDecorator->requireDefaultRecords()
|
* @uses DataExtension->requireDefaultRecords()
|
||||||
*/
|
*/
|
||||||
public function requireDefaultRecords() {
|
public function requireDefaultRecords() {
|
||||||
$defaultRecords = $this->stat('default_records');
|
$defaultRecords = $this->stat('default_records');
|
||||||
@ -3172,8 +3172,8 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
if(!$fields) $fields = array_keys($this->summaryFields());
|
if(!$fields) $fields = array_keys($this->summaryFields());
|
||||||
|
|
||||||
// we need to make sure the format is unified before
|
// we need to make sure the format is unified before
|
||||||
// augmenting fields, so decorators can apply consistent checks
|
// augmenting fields, so extensions can apply consistent checks
|
||||||
// but also after augmenting fields, because the decorator
|
// but also after augmenting fields, because the extension
|
||||||
// might use the shorthand notation as well
|
// might use the shorthand notation as well
|
||||||
|
|
||||||
// rewrite array, if it is using shorthand syntax
|
// rewrite array, if it is using shorthand syntax
|
||||||
@ -3210,7 +3210,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
|
|
||||||
$fields = $rewrite;
|
$fields = $rewrite;
|
||||||
|
|
||||||
// apply DataObjectDecorators if present
|
// apply DataExtensions if present
|
||||||
$this->extend('updateSearchableFields', $fields);
|
$this->extend('updateSearchableFields', $fields);
|
||||||
|
|
||||||
return $fields;
|
return $fields;
|
||||||
@ -3349,7 +3349,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a 'context object' that can be used to provide hints about how to process a particular get / get_one request.
|
* Sets a 'context object' that can be used to provide hints about how to process a particular get / get_one request.
|
||||||
* In particular, DataObjectDecorators can use this to amend queries more effectively.
|
* In particular, DataExtensions can use this to amend queries more effectively.
|
||||||
* Care must be taken to unset the context object after you're done with it, otherwise you will have a stale context,
|
* Care must be taken to unset the context object after you're done with it, otherwise you will have a stale context,
|
||||||
* which could cause horrible bugs.
|
* which could cause horrible bugs.
|
||||||
*/
|
*/
|
||||||
|
@ -1,235 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Plug-ins for additional functionality in your DataObjects.
|
* @package sapphire
|
||||||
*
|
|
||||||
* Note: DataObjectDecorators are not actually Decorators in the GoF Design Patterns sense of the
|
|
||||||
* word. A better name for this class would be DataExtension. However, in the interests of
|
|
||||||
* backward compatibility we haven't renamed the class.
|
|
||||||
*
|
|
||||||
* @package sapphire
|
|
||||||
* @subpackage model
|
* @subpackage model
|
||||||
|
* @deprecated 3.0 Use {@link DataExtension}.
|
||||||
*/
|
*/
|
||||||
abstract class DataObjectDecorator extends Extension {
|
abstract class DataObjectDecorator extends DataExtension {
|
||||||
|
|
||||||
/**
|
public function __construct() {
|
||||||
* Statics on a {@link DataObject} subclass
|
user_error(
|
||||||
* which can be decorated onto. This list is
|
'DataObjectDecorator is deprecated, please use DataExtension instead.',
|
||||||
* limited for security and performance reasons.
|
E_USER_NOTICE
|
||||||
*
|
);
|
||||||
* Keys are the static names, and the values are whether or not the value is an array that should
|
parent::__construct();
|
||||||
* be merged.
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected static $decoratable_statics = array(
|
|
||||||
'db' => true,
|
|
||||||
'has_one' => true,
|
|
||||||
'belongs_to' => true,
|
|
||||||
'indexes' => true,
|
|
||||||
'defaults' => true,
|
|
||||||
'has_many' => true,
|
|
||||||
'many_many' => true,
|
|
||||||
'belongs_many_many' => true,
|
|
||||||
'many_many_extraFields' => true,
|
|
||||||
'searchable_fields' => true,
|
|
||||||
'api_access' => false,
|
|
||||||
);
|
|
||||||
|
|
||||||
private static $extra_statics_loaded = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the extra static definitions for the given extension
|
|
||||||
* class name, called by {@link Object::add_extension()}
|
|
||||||
*
|
|
||||||
* @param string $class Class name of the owner class (or owner base class)
|
|
||||||
* @param string $extension Class name of the extension class
|
|
||||||
*/
|
|
||||||
public static function load_extra_statics($class, $extension) {
|
|
||||||
if(!empty(self::$extra_statics_loaded[$class][$extension])) return;
|
|
||||||
self::$extra_statics_loaded[$class][$extension] = true;
|
|
||||||
|
|
||||||
if(preg_match('/^([^(]*)/', $extension, $matches)) {
|
|
||||||
$extensionClass = $matches[1];
|
|
||||||
} else {
|
|
||||||
user_error("Bad extenion '$extension' - can't find classname", E_USER_WARNING);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @deprecated 2.4 - use extraStatics() now, not extraDBFields()
|
|
||||||
if(method_exists($extensionClass, 'extraDBFields')) {
|
|
||||||
user_error('DataObjectDecorator::extraDBFields() is deprecated. Please use extraStatics() instead.', E_USER_NOTICE);
|
|
||||||
$extraStaticsMethod = 'extraDBFields';
|
|
||||||
} else {
|
|
||||||
$extraStaticsMethod = 'extraStatics';
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the extension has been manually applied to a subclass, we should ignore that.
|
|
||||||
if(Object::has_extension(get_parent_class($class), $extensionClass)) return;
|
|
||||||
|
|
||||||
$statics = call_user_func(array($extensionClass, $extraStaticsMethod), $class, $extension);
|
|
||||||
|
|
||||||
if($statics) {
|
|
||||||
foreach($statics as $name => $newVal) {
|
|
||||||
if(isset(self::$decoratable_statics[$name])) {
|
|
||||||
|
|
||||||
// Array to be merged
|
|
||||||
if(self::$decoratable_statics[$name]) {
|
|
||||||
$origVal = Object::uninherited_static($class, $name);
|
|
||||||
// Can't use add_static_var() here as it would merge the array rather than replacing
|
|
||||||
Object::set_static($class, $name, array_merge((array)$origVal, $newVal));
|
|
||||||
|
|
||||||
// Value to be overwritten
|
|
||||||
} else {
|
|
||||||
Object::set_static($class, $name, $newVal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DataObject::$cache_has_own_table[$class] = null;
|
|
||||||
DataObject::$cache_has_own_table_field[$class] = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Edit the given query object to support queries for this extension
|
|
||||||
*
|
|
||||||
* @param SQLQuery $query Query to augment.
|
|
||||||
*/
|
|
||||||
function augmentSQL(SQLQuery &$query) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the database schema as required by this extension.
|
|
||||||
*/
|
|
||||||
function augmentDatabase() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Augment a write-record request.
|
|
||||||
*
|
|
||||||
* @param SQLQuery $manipulation Query to augment.
|
|
||||||
*/
|
|
||||||
function augmentWrite(&$manipulation) {
|
|
||||||
}
|
|
||||||
|
|
||||||
function onBeforeWrite() {
|
|
||||||
}
|
|
||||||
|
|
||||||
function onAfterWrite() {
|
|
||||||
}
|
|
||||||
|
|
||||||
function onBeforeDelete() {
|
|
||||||
}
|
|
||||||
|
|
||||||
function onAfterDelete() {
|
|
||||||
}
|
|
||||||
|
|
||||||
function requireDefaultRecords() {
|
|
||||||
}
|
|
||||||
|
|
||||||
function populateDefaults() {
|
|
||||||
}
|
|
||||||
|
|
||||||
function can($member) {
|
|
||||||
}
|
|
||||||
|
|
||||||
function canEdit($member) {
|
|
||||||
}
|
|
||||||
|
|
||||||
function canDelete($member) {
|
|
||||||
}
|
|
||||||
|
|
||||||
function canCreate($member) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define extra database fields
|
|
||||||
*
|
|
||||||
* Return a map where the keys are db, has_one, etc, and the values are
|
|
||||||
* additional fields/relations to be defined.
|
|
||||||
*
|
|
||||||
* @return array Returns a map where the keys are db, has_one, etc, and
|
|
||||||
* the values are additional fields/relations to be defined.
|
|
||||||
*/
|
|
||||||
function extraStatics() {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function is used to provide modifications to the form in the CMS
|
|
||||||
* by the decorator. By default, no changes are made. {@link DataObject->getCMSFields()}.
|
|
||||||
*
|
|
||||||
* Please consider using {@link updateFormFields()} to globally add
|
|
||||||
* formfields to the record. The method {@link updateCMSFields()}
|
|
||||||
* should just be used to add or modify tabs, or fields which
|
|
||||||
* are specific to the CMS-context.
|
|
||||||
*
|
|
||||||
* Caution: Use {@link FieldSet->addFieldToTab()} to add fields.
|
|
||||||
*
|
|
||||||
* @param FieldSet $fields FieldSet with a contained TabSet
|
|
||||||
*/
|
|
||||||
function updateCMSFields(FieldSet &$fields) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function is used to provide modifications to the form used
|
|
||||||
* for front end forms. {@link DataObject->getFrontEndFields()}
|
|
||||||
*
|
|
||||||
* Caution: Use {@link FieldSet->push()} to add fields.
|
|
||||||
*
|
|
||||||
* @param FieldSet $fields FieldSet without TabSet nesting
|
|
||||||
*/
|
|
||||||
function updateFrontEndFields(FieldSet &$fields) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is used to provide modifications to the form actions
|
|
||||||
* used in the CMS. {@link DataObject->getCMSActions()}.
|
|
||||||
*
|
|
||||||
* @param FieldSet $actions FieldSet
|
|
||||||
*/
|
|
||||||
function updateCMSActions(FieldSet &$actions) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* this function is used to provide modifications to the summary fields in CMS
|
|
||||||
* by the decorator
|
|
||||||
* By default, the summaryField() of its owner will merge more fields defined in the decorator's
|
|
||||||
* $extra_fields['summary_fields']
|
|
||||||
*/
|
|
||||||
function updateSummaryFields(&$fields){
|
|
||||||
$extra_fields = $this->extraStatics();
|
|
||||||
if(isset($extra_fields['summary_fields'])){
|
|
||||||
$summary_fields = $extra_fields['summary_fields'];
|
|
||||||
|
|
||||||
// if summary_fields were passed in numeric array,
|
|
||||||
// convert to an associative array
|
|
||||||
if($summary_fields && array_key_exists(0, $summary_fields)) {
|
|
||||||
$summary_fields = array_combine(array_values($summary_fields), array_values($summary_fields));
|
|
||||||
}
|
|
||||||
if($summary_fields) $fields = array_merge($fields, $summary_fields);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* this function is used to provide modifications to the fields labels in CMS
|
|
||||||
* by the decorator
|
|
||||||
* By default, the fieldLabels() of its owner will merge more fields defined in the decorator's
|
|
||||||
* $extra_fields['field_labels']
|
|
||||||
*/
|
|
||||||
function updateFieldLabels(&$lables){
|
|
||||||
$extra_fields = $this->extraStatics();
|
|
||||||
if(isset($extra_fields['field_labels'])){
|
|
||||||
$field_labels = $extra_fields['field_labels'];
|
|
||||||
if($field_labels) $lables = array_merge($lables, $field_labels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear any internal caches.
|
|
||||||
*/
|
|
||||||
function flushCache() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
?>
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* DataObjects that use the Hierachy decorator can be be organised as a hierachy, with children and parents.
|
* DataObjects that use the Hierachy extension can be be organised as a hierachy, with children and parents.
|
||||||
* The most obvious example of this is SiteTree.
|
* The most obvious example of this is SiteTree.
|
||||||
* @package sapphire
|
* @package sapphire
|
||||||
* @subpackage model
|
* @subpackage model
|
||||||
*/
|
*/
|
||||||
class Hierarchy extends DataObjectDecorator {
|
class Hierarchy extends DataExtension {
|
||||||
|
|
||||||
protected $markedNodes;
|
protected $markedNodes;
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* The Versioned decorator allows your DataObjects to have several versions, allowing
|
* The Versioned extension allows your DataObjects to have several versions, allowing
|
||||||
* you to rollback changes and view history. An example of this is the pages used in the CMS.
|
* you to rollback changes and view history. An example of this is the pages used in the CMS.
|
||||||
* @package sapphire
|
* @package sapphire
|
||||||
* @subpackage model
|
* @subpackage model
|
||||||
*/
|
*/
|
||||||
class Versioned extends DataObjectDecorator {
|
class Versioned extends DataExtension {
|
||||||
/**
|
/**
|
||||||
* An array of possible stages.
|
* An array of possible stages.
|
||||||
* @var array
|
* @var array
|
||||||
@ -42,7 +42,7 @@ class Versioned extends DataObjectDecorator {
|
|||||||
/**
|
/**
|
||||||
* Additional database columns for the new
|
* Additional database columns for the new
|
||||||
* "_versions" table. Used in {@link augmentDatabase()}
|
* "_versions" table. Used in {@link augmentDatabase()}
|
||||||
* and all Versioned calls decorating or creating
|
* and all Versioned calls extending or creating
|
||||||
* SELECT statements.
|
* SELECT statements.
|
||||||
*
|
*
|
||||||
* @var array $db_for_versions_table
|
* @var array $db_for_versions_table
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
* @package sapphire
|
* @package sapphire
|
||||||
* @subpackage search
|
* @subpackage search
|
||||||
*/
|
*/
|
||||||
class FulltextSearchable extends DataObjectDecorator {
|
class FulltextSearchable extends DataExtension {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var String Comma-separated list of database column names
|
* @var String Comma-separated list of database column names
|
||||||
|
@ -359,7 +359,7 @@ class Group extends DataObject {
|
|||||||
public function canEdit($member = null) {
|
public function canEdit($member = null) {
|
||||||
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
|
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
|
||||||
|
|
||||||
// decorated access checks
|
// extended access checks
|
||||||
$results = $this->extend('canEdit', $member);
|
$results = $this->extend('canEdit', $member);
|
||||||
if($results && is_array($results)) if(!min($results)) return false;
|
if($results && is_array($results)) if(!min($results)) return false;
|
||||||
|
|
||||||
@ -389,7 +389,7 @@ class Group extends DataObject {
|
|||||||
public function canView($member = null) {
|
public function canView($member = null) {
|
||||||
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
|
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
|
||||||
|
|
||||||
// decorated access checks
|
// extended access checks
|
||||||
$results = $this->extend('canView', $member);
|
$results = $this->extend('canView', $member);
|
||||||
if($results && is_array($results)) if(!min($results)) return false;
|
if($results && is_array($results)) if(!min($results)) return false;
|
||||||
|
|
||||||
@ -402,7 +402,7 @@ class Group extends DataObject {
|
|||||||
public function canDelete($member = null) {
|
public function canDelete($member = null) {
|
||||||
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
|
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
|
||||||
|
|
||||||
// decorated access checks
|
// extended access checks
|
||||||
$results = $this->extend('canDelete', $member);
|
$results = $this->extend('canDelete', $member);
|
||||||
if($results && is_array($results)) if(!min($results)) return false;
|
if($results && is_array($results)) if(!min($results)) return false;
|
||||||
|
|
||||||
|
@ -1264,7 +1264,7 @@ class Member extends DataObject {
|
|||||||
function canView($member = null) {
|
function canView($member = null) {
|
||||||
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
|
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
|
||||||
|
|
||||||
// decorated access checks
|
// extended access checks
|
||||||
$results = $this->extend('canView', $member);
|
$results = $this->extend('canView', $member);
|
||||||
if($results && is_array($results)) {
|
if($results && is_array($results)) {
|
||||||
if(!min($results)) return false;
|
if(!min($results)) return false;
|
||||||
@ -1291,7 +1291,7 @@ class Member extends DataObject {
|
|||||||
function canEdit($member = null) {
|
function canEdit($member = null) {
|
||||||
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
|
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
|
||||||
|
|
||||||
// decorated access checks
|
// extended access checks
|
||||||
$results = $this->extend('canEdit', $member);
|
$results = $this->extend('canEdit', $member);
|
||||||
if($results && is_array($results)) {
|
if($results && is_array($results)) {
|
||||||
if(!min($results)) return false;
|
if(!min($results)) return false;
|
||||||
@ -1318,7 +1318,7 @@ class Member extends DataObject {
|
|||||||
function canDelete($member = null) {
|
function canDelete($member = null) {
|
||||||
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
|
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
|
||||||
|
|
||||||
// decorated access checks
|
// extended access checks
|
||||||
$results = $this->extend('canDelete', $member);
|
$results = $this->extend('canDelete', $member);
|
||||||
if($results && is_array($results)) {
|
if($results && is_array($results)) {
|
||||||
if(!min($results)) return false;
|
if(!min($results)) return false;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*
|
*
|
||||||
* @todo tests for addStaticVars()
|
* @todo tests for addStaticVars()
|
||||||
* @todo tests for setting statics which are not defined on the object as built-in PHP statics
|
* @todo tests for setting statics which are not defined on the object as built-in PHP statics
|
||||||
* @todo tests for setting statics through decorators (#2387)
|
* @todo tests for setting statics through extensions (#2387)
|
||||||
*/
|
*/
|
||||||
class ObjectTest extends SapphireTest {
|
class ObjectTest extends SapphireTest {
|
||||||
|
|
||||||
|
@ -38,8 +38,8 @@ class FormScaffolderTest extends SapphireTest {
|
|||||||
$article1 = $this->objFromFixture('FormScaffolderTest_Article', 'article1');
|
$article1 = $this->objFromFixture('FormScaffolderTest_Article', 'article1');
|
||||||
$fields = $article1->getCMSFields();
|
$fields = $article1->getCMSFields();
|
||||||
$this->assertNotNull(
|
$this->assertNotNull(
|
||||||
$fields->dataFieldByName('AddedDecoratorField'),
|
$fields->dataFieldByName('AddedExtensionField'),
|
||||||
'getCMSFields() includes decorated fields'
|
'getCMSFields() includes extended fields'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,16 +102,16 @@ class FormScaffolderTest_Tag extends DataObject implements TestOnly {
|
|||||||
'Articles' => 'FormScaffolderTest_Article'
|
'Articles' => 'FormScaffolderTest_Article'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
class FormScaffolderTest_ArticleDecorator extends DataObjectDecorator implements TestOnly {
|
class FormScaffolderTest_ArticleExtension extends DataExtension implements TestOnly {
|
||||||
static $db = array(
|
static $db = array(
|
||||||
'DecoratedField' => 'Varchar'
|
'ExtendedField' => 'Varchar'
|
||||||
);
|
);
|
||||||
function updateCMSFields(&$fields) {
|
function updateCMSFields(&$fields) {
|
||||||
$fields->addFieldToTab('Root.Main',
|
$fields->addFieldToTab('Root.Main',
|
||||||
new TextField('AddedDecoratorField')
|
new TextField('AddedExtensionField')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DataObject::add_extension('FormScaffolderTest_Article', 'FormScaffolderTest_ArticleDecorator');
|
DataObject::add_extension('FormScaffolderTest_Article', 'FormScaffolderTest_ArticleExtension');
|
||||||
?>
|
?>
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
class i18nTestModuleDecorator extends DataObjectDecorator {
|
class i18nTestModuleExtension extends DataExtension {
|
||||||
function extraStatics() {
|
function extraStatics() {
|
||||||
return array(
|
return array(
|
||||||
'db' => array(
|
'db' => array(
|
||||||
|
@ -1,26 +1,26 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
class DataObjectDecoratorTest extends SapphireTest {
|
class DataExtensionTest extends SapphireTest {
|
||||||
static $fixture_file = 'DataObjectDecoratorTest.yml';
|
static $fixture_file = 'DataExtensionTest.yml';
|
||||||
|
|
||||||
protected $extraDataObjects = array(
|
protected $extraDataObjects = array(
|
||||||
'DataObjectDecoratorTest_Member',
|
'DataExtensionTest_Member',
|
||||||
'DataObjectDecoratorTest_Player',
|
'DataExtensionTest_Player',
|
||||||
'DataObjectDecoratorTest_RelatedObject',
|
'DataExtensionTest_RelatedObject',
|
||||||
'DataObjectDecoratorTest_MyObject',
|
'DataExtensionTest_MyObject',
|
||||||
);
|
);
|
||||||
|
|
||||||
protected $requiredExtensions = array(
|
protected $requiredExtensions = array(
|
||||||
'DataObject' => array( 'DataObjectDecoratorTest_AppliedToDO' ),
|
'DataObject' => array( 'DataExtensionTest_AppliedToDO' ),
|
||||||
);
|
);
|
||||||
|
|
||||||
function testOneToManyAssociationWithDecorator() {
|
function testOneToManyAssociationWithExtension() {
|
||||||
// Fails in RestfulServerTest
|
// Fails in RestfulServerTest
|
||||||
// Error: Object::__call() Method 'RelatedObjects' not found in class 'RestfulServerTest_Comment'
|
// Error: Object::__call() Method 'RelatedObjects' not found in class 'RestfulServerTest_Comment'
|
||||||
$contact = new DataObjectDecoratorTest_Member();
|
$contact = new DataExtensionTest_Member();
|
||||||
$contact->Website = "http://www.example.com";
|
$contact->Website = "http://www.example.com";
|
||||||
|
|
||||||
$object = new DataObjectDecoratorTest_RelatedObject();
|
$object = new DataExtensionTest_RelatedObject();
|
||||||
$object->FieldOne = "Lorem ipsum dolor";
|
$object->FieldOne = "Lorem ipsum dolor";
|
||||||
$object->FieldTwo = "Random notes";
|
$object->FieldTwo = "Random notes";
|
||||||
|
|
||||||
@ -37,28 +37,28 @@ class DataObjectDecoratorTest extends SapphireTest {
|
|||||||
unset($contact);
|
unset($contact);
|
||||||
unset($object);
|
unset($object);
|
||||||
|
|
||||||
$contact = DataObject::get_one("DataObjectDecoratorTest_Member", "\"Website\"='http://www.example.com'");
|
$contact = DataObject::get_one("DataExtensionTest_Member", "\"Website\"='http://www.example.com'");
|
||||||
$object = DataObject::get_one('DataObjectDecoratorTest_RelatedObject', "\"ContactID\" = {$contactID}");
|
$object = DataObject::get_one('DataExtensionTest_RelatedObject', "\"ContactID\" = {$contactID}");
|
||||||
|
|
||||||
$this->assertNotNull($object, 'Related object not null');
|
$this->assertNotNull($object, 'Related object not null');
|
||||||
$this->assertType('DataObjectDecoratorTest_Member', $object->Contact(), 'Related contact is a member dataobject');
|
$this->assertType('DataExtensionTest_Member', $object->Contact(), 'Related contact is a member dataobject');
|
||||||
$this->assertType('DataObjectDecoratorTest_Member', $object->getComponent('Contact'), 'getComponent does the same thing as Contact()');
|
$this->assertType('DataExtensionTest_Member', $object->getComponent('Contact'), 'getComponent does the same thing as Contact()');
|
||||||
|
|
||||||
$this->assertType('DataObjectDecoratorTest_RelatedObject', $contact->RelatedObjects()->First());
|
$this->assertType('DataExtensionTest_RelatedObject', $contact->RelatedObjects()->First());
|
||||||
$this->assertEquals("Lorem ipsum dolor", $contact->RelatedObjects()->First()->FieldOne);
|
$this->assertEquals("Lorem ipsum dolor", $contact->RelatedObjects()->First()->FieldOne);
|
||||||
$this->assertEquals("Random notes", $contact->RelatedObjects()->First()->FieldTwo);
|
$this->assertEquals("Random notes", $contact->RelatedObjects()->First()->FieldTwo);
|
||||||
$contact->delete();
|
$contact->delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
function testManyManyAssociationWithDecorator() {
|
function testManyManyAssociationWithExtension() {
|
||||||
$parent = new DataObjectDecoratorTest_MyObject();
|
$parent = new DataExtensionTest_MyObject();
|
||||||
$parent->Title = 'My Title';
|
$parent->Title = 'My Title';
|
||||||
$parent->write();
|
$parent->write();
|
||||||
|
|
||||||
$this->assertEquals(0, $parent->Faves()->Count());
|
$this->assertEquals(0, $parent->Faves()->Count());
|
||||||
|
|
||||||
$obj1 = $this->objFromFixture('DataObjectDecoratorTest_RelatedObject', 'obj1');
|
$obj1 = $this->objFromFixture('DataExtensionTest_RelatedObject', 'obj1');
|
||||||
$obj2 = $this->objFromFixture('DataObjectDecoratorTest_RelatedObject', 'obj2');
|
$obj2 = $this->objFromFixture('DataExtensionTest_RelatedObject', 'obj2');
|
||||||
|
|
||||||
$parent->Faves()->add($obj1->ID);
|
$parent->Faves()->add($obj1->ID);
|
||||||
$this->assertEquals(1, $parent->Faves()->Count());
|
$this->assertEquals(1, $parent->Faves()->Count());
|
||||||
@ -71,17 +71,17 @@ class DataObjectDecoratorTest extends SapphireTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test {@link Object::add_extension()} has loaded DataObjectDecorator statics correctly.
|
* Test {@link Object::add_extension()} has loaded DataExtension statics correctly.
|
||||||
*/
|
*/
|
||||||
function testAddExtensionLoadsStatics() {
|
function testAddExtensionLoadsStatics() {
|
||||||
// Object::add_extension() will load DOD statics directly, so let's try adding a decorator on the fly
|
// Object::add_extension() will load DOD statics directly, so let's try adding a extension on the fly
|
||||||
Object::add_extension('DataObjectDecoratorTest_Player', 'DataObjectDecoratorTest_PlayerDecorator');
|
Object::add_extension('DataExtensionTest_Player', 'DataExtensionTest_PlayerExtension');
|
||||||
|
|
||||||
// Now that we've just added the decorator, we need to rebuild the database
|
// Now that we've just added the extension, we need to rebuild the database
|
||||||
$this->resetDBSchema(true);
|
$this->resetDBSchema(true);
|
||||||
|
|
||||||
// Create a test record with decorated fields, writing to the DB
|
// Create a test record with extended fields, writing to the DB
|
||||||
$player = new DataObjectDecoratorTest_Player();
|
$player = new DataExtensionTest_Player();
|
||||||
$player->setField('Name', 'Joe');
|
$player->setField('Name', 'Joe');
|
||||||
$player->setField('DateBirth', '1990-5-10');
|
$player->setField('DateBirth', '1990-5-10');
|
||||||
$player->Address = '123 somewhere street';
|
$player->Address = '123 somewhere street';
|
||||||
@ -89,66 +89,66 @@ class DataObjectDecoratorTest extends SapphireTest {
|
|||||||
|
|
||||||
unset($player);
|
unset($player);
|
||||||
|
|
||||||
// Pull the record out of the DB and examine the decorated fields
|
// Pull the record out of the DB and examine the extended fields
|
||||||
$player = DataObject::get_one('DataObjectDecoratorTest_Player', "\"Name\" = 'Joe'");
|
$player = DataObject::get_one('DataExtensionTest_Player', "\"Name\" = 'Joe'");
|
||||||
$this->assertEquals($player->DateBirth, '1990-05-10');
|
$this->assertEquals($player->DateBirth, '1990-05-10');
|
||||||
$this->assertEquals($player->Address, '123 somewhere street');
|
$this->assertEquals($player->Address, '123 somewhere street');
|
||||||
$this->assertEquals($player->Status, 'Goalie');
|
$this->assertEquals($player->Status, 'Goalie');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that DataObject::$api_access can be set to true via a decorator
|
* Test that DataObject::$api_access can be set to true via a extension
|
||||||
*/
|
*/
|
||||||
function testApiAccessCanBeDecorated() {
|
function testApiAccessCanBeExtended() {
|
||||||
$this->assertTrue(Object::get_static('DataObjectDecoratorTest_Member', 'api_access'));
|
$this->assertTrue(Object::get_static('DataExtensionTest_Member', 'api_access'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function testPermissionDecoration() {
|
function testPermissionExtension() {
|
||||||
// testing behaviour in isolation, too many sideeffects and other checks
|
// testing behaviour in isolation, too many sideeffects and other checks
|
||||||
// in SiteTree->can*() methods to test one single feature reliably with them
|
// in SiteTree->can*() methods to test one single feature reliably with them
|
||||||
|
|
||||||
$obj = $this->objFromFixture('DataObjectDecoratorTest_MyObject', 'object1');
|
$obj = $this->objFromFixture('DataExtensionTest_MyObject', 'object1');
|
||||||
$websiteuser = $this->objFromFixture('Member', 'websiteuser');
|
$websiteuser = $this->objFromFixture('Member', 'websiteuser');
|
||||||
$admin = $this->objFromFixture('Member', 'admin');
|
$admin = $this->objFromFixture('Member', 'admin');
|
||||||
|
|
||||||
$this->assertFalse(
|
$this->assertFalse(
|
||||||
$obj->canOne($websiteuser),
|
$obj->canOne($websiteuser),
|
||||||
'Both decorators return true, but original method returns false'
|
'Both extensions return true, but original method returns false'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertFalse(
|
$this->assertFalse(
|
||||||
$obj->canTwo($websiteuser),
|
$obj->canTwo($websiteuser),
|
||||||
'One decorator returns false, original returns true, but decorator takes precedence'
|
'One extension returns false, original returns true, but extension takes precedence'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertTrue(
|
$this->assertTrue(
|
||||||
$obj->canThree($admin),
|
$obj->canThree($admin),
|
||||||
'Undefined decorator methods returning NULL dont influence the original method'
|
'Undefined extension methods returning NULL dont influence the original method'
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testPopulateDefaults() {
|
function testPopulateDefaults() {
|
||||||
$obj = new DataObjectDecoratorTest_Member();
|
$obj = new DataExtensionTest_Member();
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
$obj->Phone,
|
$obj->Phone,
|
||||||
'123',
|
'123',
|
||||||
'Defaults can be populated through decorator'
|
'Defaults can be populated through extension'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that DataObject::dbObject() works for fields applied by a decorator
|
* Test that DataObject::dbObject() works for fields applied by a extension
|
||||||
*/
|
*/
|
||||||
function testDbObjectOnDecoratedFields() {
|
function testDbObjectOnExtendedFields() {
|
||||||
$member = $this->objFromFixture('DataObjectDecoratorTest_Member', 'member1');
|
$member = $this->objFromFixture('DataExtensionTest_Member', 'member1');
|
||||||
$this->assertNotNull($member->dbObject('Website'));
|
$this->assertNotNull($member->dbObject('Website'));
|
||||||
$this->assertType('Varchar', $member->dbObject('Website'));
|
$this->assertType('Varchar', $member->dbObject('Website'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function testDecoratorCanBeAppliedToDataObject() {
|
function testExtensionCanBeAppliedToDataObject() {
|
||||||
$do = new DataObject();
|
$do = new DataObject();
|
||||||
$mo = new DataObjectDecoratorTest_MyObject();
|
$mo = new DataExtensionTest_MyObject();
|
||||||
|
|
||||||
$this->assertTrue($do->hasMethod('testMethodApplied'));
|
$this->assertTrue($do->hasMethod('testMethodApplied'));
|
||||||
$this->assertTrue($mo->hasMethod('testMethodApplied'));
|
$this->assertTrue($mo->hasMethod('testMethodApplied'));
|
||||||
@ -158,7 +158,7 @@ class DataObjectDecoratorTest extends SapphireTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DataObjectDecoratorTest_Member extends DataObject implements TestOnly {
|
class DataExtensionTest_Member extends DataObject implements TestOnly {
|
||||||
|
|
||||||
static $db = array(
|
static $db = array(
|
||||||
"Name" => "Varchar",
|
"Name" => "Varchar",
|
||||||
@ -167,7 +167,7 @@ class DataObjectDecoratorTest_Member extends DataObject implements TestOnly {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class DataObjectDecoratorTest_Player extends DataObject implements TestOnly {
|
class DataExtensionTest_Player extends DataObject implements TestOnly {
|
||||||
|
|
||||||
static $db = array(
|
static $db = array(
|
||||||
'Name' => 'Varchar'
|
'Name' => 'Varchar'
|
||||||
@ -175,12 +175,12 @@ class DataObjectDecoratorTest_Player extends DataObject implements TestOnly {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class DataObjectDecoratorTest_PlayerDecorator extends DataObjectDecorator implements TestOnly {
|
class DataExtensionTest_PlayerExtension extends DataExtension implements TestOnly {
|
||||||
|
|
||||||
function extraStatics($class) {
|
function extraStatics($class) {
|
||||||
// Only add these extensions if the $class is set to DataObjectDecoratorTest_Player, to
|
// Only add these extensions if the $class is set to DataExtensionTest_Player, to
|
||||||
// test that the argument works.
|
// test that the argument works.
|
||||||
if($class == 'DataObjectDecoratorTest_Player') {
|
if($class == 'DataExtensionTest_Player') {
|
||||||
return array(
|
return array(
|
||||||
'db' => array(
|
'db' => array(
|
||||||
'Address' => 'Text',
|
'Address' => 'Text',
|
||||||
@ -196,7 +196,7 @@ class DataObjectDecoratorTest_PlayerDecorator extends DataObjectDecorator implem
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class DataObjectDecoratorTest_ContactRole extends DataObjectDecorator implements TestOnly {
|
class DataExtensionTest_ContactRole extends DataExtension implements TestOnly {
|
||||||
|
|
||||||
function extraStatics() {
|
function extraStatics() {
|
||||||
return array(
|
return array(
|
||||||
@ -205,7 +205,7 @@ class DataObjectDecoratorTest_ContactRole extends DataObjectDecorator implements
|
|||||||
'Phone' => 'Varchar(255)',
|
'Phone' => 'Varchar(255)',
|
||||||
),
|
),
|
||||||
'has_many' => array(
|
'has_many' => array(
|
||||||
'RelatedObjects' => 'DataObjectDecoratorTest_RelatedObject'
|
'RelatedObjects' => 'DataExtensionTest_RelatedObject'
|
||||||
),
|
),
|
||||||
'defaults' => array(
|
'defaults' => array(
|
||||||
'Phone' => '123'
|
'Phone' => '123'
|
||||||
@ -216,7 +216,7 @@ class DataObjectDecoratorTest_ContactRole extends DataObjectDecorator implements
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class DataObjectDecoratorTest_RelatedObject extends DataObject implements TestOnly {
|
class DataExtensionTest_RelatedObject extends DataObject implements TestOnly {
|
||||||
|
|
||||||
static $db = array(
|
static $db = array(
|
||||||
"FieldOne" => "Varchar",
|
"FieldOne" => "Varchar",
|
||||||
@ -224,21 +224,21 @@ class DataObjectDecoratorTest_RelatedObject extends DataObject implements TestOn
|
|||||||
);
|
);
|
||||||
|
|
||||||
static $has_one = array(
|
static $has_one = array(
|
||||||
"Contact" => "DataObjectDecoratorTest_Member"
|
"Contact" => "DataExtensionTest_Member"
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DataObject::add_extension('DataObjectDecoratorTest_Member', 'DataObjectDecoratorTest_ContactRole');
|
DataObject::add_extension('DataExtensionTest_Member', 'DataExtensionTest_ContactRole');
|
||||||
|
|
||||||
class DataObjectDecoratorTest_MyObject extends DataObject implements TestOnly {
|
class DataExtensionTest_MyObject extends DataObject implements TestOnly {
|
||||||
|
|
||||||
static $db = array(
|
static $db = array(
|
||||||
'Title' => 'Varchar',
|
'Title' => 'Varchar',
|
||||||
);
|
);
|
||||||
|
|
||||||
function canOne($member = null) {
|
function canOne($member = null) {
|
||||||
// decorated access checks
|
// extended access checks
|
||||||
$results = $this->extend('canOne', $member);
|
$results = $this->extend('canOne', $member);
|
||||||
if($results && is_array($results)) if(!min($results)) return false;
|
if($results && is_array($results)) if(!min($results)) return false;
|
||||||
|
|
||||||
@ -246,7 +246,7 @@ class DataObjectDecoratorTest_MyObject extends DataObject implements TestOnly {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function canTwo($member = null) {
|
function canTwo($member = null) {
|
||||||
// decorated access checks
|
// extended access checks
|
||||||
$results = $this->extend('canTwo', $member);
|
$results = $this->extend('canTwo', $member);
|
||||||
if($results && is_array($results)) if(!min($results)) return false;
|
if($results && is_array($results)) if(!min($results)) return false;
|
||||||
|
|
||||||
@ -254,7 +254,7 @@ class DataObjectDecoratorTest_MyObject extends DataObject implements TestOnly {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function canThree($member = null) {
|
function canThree($member = null) {
|
||||||
// decorated access checks
|
// extended access checks
|
||||||
$results = $this->extend('canThree', $member);
|
$results = $this->extend('canThree', $member);
|
||||||
if($results && is_array($results)) if(!min($results)) return false;
|
if($results && is_array($results)) if(!min($results)) return false;
|
||||||
|
|
||||||
@ -262,7 +262,7 @@ class DataObjectDecoratorTest_MyObject extends DataObject implements TestOnly {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DataObjectDecoratorTest_Ext1 extends DataObjectDecorator implements TestOnly {
|
class DataExtensionTest_Ext1 extends DataExtension implements TestOnly {
|
||||||
|
|
||||||
function canOne($member = null) {
|
function canOne($member = null) {
|
||||||
return true;
|
return true;
|
||||||
@ -277,7 +277,7 @@ class DataObjectDecoratorTest_Ext1 extends DataObjectDecorator implements TestOn
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class DataObjectDecoratorTest_Ext2 extends DataObjectDecorator implements TestOnly {
|
class DataExtensionTest_Ext2 extends DataExtension implements TestOnly {
|
||||||
|
|
||||||
function canOne($member = null) {
|
function canOne($member = null) {
|
||||||
return true;
|
return true;
|
||||||
@ -292,23 +292,23 @@ class DataObjectDecoratorTest_Ext2 extends DataObjectDecorator implements TestOn
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class DataObjectDecoratorTest_Faves extends DataObjectDecorator implements TestOnly {
|
class DataExtensionTest_Faves extends DataExtension implements TestOnly {
|
||||||
public function extraStatics() {
|
public function extraStatics() {
|
||||||
return array(
|
return array(
|
||||||
'many_many' => array(
|
'many_many' => array(
|
||||||
'Faves' => 'DataObjectDecoratorTest_RelatedObject'
|
'Faves' => 'DataExtensionTest_RelatedObject'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DataObjectDecoratorTest_AppliedToDO extends DataObjectDecorator implements TestOnly {
|
class DataExtensionTest_AppliedToDO extends DataExtension implements TestOnly {
|
||||||
public function testMethodApplied() {
|
public function testMethodApplied() {
|
||||||
return "hello world";
|
return "hello world";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DataObject::add_extension('DataObjectDecoratorTest_MyObject', 'DataObjectDecoratorTest_Ext1');
|
DataObject::add_extension('DataExtensionTest_MyObject', 'DataExtensionTest_Ext1');
|
||||||
DataObject::add_extension('DataObjectDecoratorTest_MyObject', 'DataObjectDecoratorTest_Ext2');
|
DataObject::add_extension('DataExtensionTest_MyObject', 'DataExtensionTest_Ext2');
|
||||||
DataObject::add_extension('DataObjectDecoratorTest_MyObject', 'DataObjectDecoratorTest_Faves');
|
DataObject::add_extension('DataExtensionTest_MyObject', 'DataExtensionTest_Faves');
|
||||||
?>
|
?>
|
@ -1,4 +1,4 @@
|
|||||||
DataObjectDecoratorTest_RelatedObject:
|
DataExtensionTest_RelatedObject:
|
||||||
obj1:
|
obj1:
|
||||||
FieldOne: Obj1
|
FieldOne: Obj1
|
||||||
obj2:
|
obj2:
|
||||||
@ -15,10 +15,10 @@ Member:
|
|||||||
Groups: =>Group.admingroup
|
Groups: =>Group.admingroup
|
||||||
websiteuser:
|
websiteuser:
|
||||||
Email: websiteuser@test.com
|
Email: websiteuser@test.com
|
||||||
DataObjectDecoratorTest_Member:
|
DataExtensionTest_Member:
|
||||||
member1:
|
member1:
|
||||||
Name: Sam
|
Name: Sam
|
||||||
Website: http://www.example.org
|
Website: http://www.example.org
|
||||||
DataObjectDecoratorTest_MyObject:
|
DataExtensionTest_MyObject:
|
||||||
object1:
|
object1:
|
||||||
Title: Object 1
|
Title: Object 1
|
@ -22,11 +22,11 @@ DataObjectTest_SubTeam:
|
|||||||
subteam1:
|
subteam1:
|
||||||
Title: Subteam 1
|
Title: Subteam 1
|
||||||
SubclassDatabaseField: Subclassed 1
|
SubclassDatabaseField: Subclassed 1
|
||||||
DecoratedDatabaseField: Decorated 1
|
ExtendedDatabaseField: Extended 1
|
||||||
subteam2_with_player_relation:
|
subteam2_with_player_relation:
|
||||||
Title: Subteam 2
|
Title: Subteam 2
|
||||||
SubclassDatabaseField: Subclassed 2
|
SubclassDatabaseField: Subclassed 2
|
||||||
DecoratedHasOneRelationship: =>DataObjectTest_Player.player1
|
ExtendeHasOneRelationship: =>DataObjectTest_Player.player1
|
||||||
subteam3_with_empty_fields:
|
subteam3_with_empty_fields:
|
||||||
Title: Subteam 3
|
Title: Subteam 3
|
||||||
|
|
||||||
|
@ -455,9 +455,9 @@ class DataObjectTest extends SapphireTest {
|
|||||||
//$this->assertFalse($teamInstance->hasField('SubclassDatabaseField'), 'hasField() doesnt find subclass fields in parentclass instances');
|
//$this->assertFalse($teamInstance->hasField('SubclassDatabaseField'), 'hasField() doesnt find subclass fields in parentclass instances');
|
||||||
$this->assertTrue($teamInstance->hasField('DynamicField'), 'hasField() finds dynamic getters in instances');
|
$this->assertTrue($teamInstance->hasField('DynamicField'), 'hasField() finds dynamic getters in instances');
|
||||||
$this->assertTrue($teamInstance->hasField('HasOneRelationshipID'), 'hasField() finds foreign keys in instances');
|
$this->assertTrue($teamInstance->hasField('HasOneRelationshipID'), 'hasField() finds foreign keys in instances');
|
||||||
$this->assertTrue($teamInstance->hasField('DecoratedDatabaseField'), 'hasField() finds decorated fields in instances');
|
$this->assertTrue($teamInstance->hasField('ExtendedDatabaseField'), 'hasField() finds extended fields in instances');
|
||||||
$this->assertTrue($teamInstance->hasField('DecoratedHasOneRelationshipID'), 'hasField() finds decorated foreign keys in instances');
|
$this->assertTrue($teamInstance->hasField('ExtendedHasOneRelationshipID'), 'hasField() finds extended foreign keys in instances');
|
||||||
//$this->assertTrue($teamInstance->hasField('DecoratedDynamicField'), 'hasField() includes decorated dynamic getters in instances');
|
//$this->assertTrue($teamInstance->hasField('ExtendedDynamicField'), 'hasField() includes extended dynamic getters in instances');
|
||||||
|
|
||||||
/* hasField() subclass checks */
|
/* hasField() subclass checks */
|
||||||
$this->assertTrue($subteamInstance->hasField('ID'), 'hasField() finds built-in fields in subclass instances');
|
$this->assertTrue($subteamInstance->hasField('ID'), 'hasField() finds built-in fields in subclass instances');
|
||||||
@ -466,8 +466,8 @@ class DataObjectTest extends SapphireTest {
|
|||||||
$this->assertTrue($subteamInstance->hasField('SubclassDatabaseField'), 'hasField() finds custom fields in subclass instances');
|
$this->assertTrue($subteamInstance->hasField('SubclassDatabaseField'), 'hasField() finds custom fields in subclass instances');
|
||||||
$this->assertTrue($subteamInstance->hasField('DynamicField'), 'hasField() finds dynamic getters in subclass instances');
|
$this->assertTrue($subteamInstance->hasField('DynamicField'), 'hasField() finds dynamic getters in subclass instances');
|
||||||
$this->assertTrue($subteamInstance->hasField('HasOneRelationshipID'), 'hasField() finds foreign keys in subclass instances');
|
$this->assertTrue($subteamInstance->hasField('HasOneRelationshipID'), 'hasField() finds foreign keys in subclass instances');
|
||||||
$this->assertTrue($subteamInstance->hasField('DecoratedDatabaseField'), 'hasField() finds decorated fields in subclass instances');
|
$this->assertTrue($subteamInstance->hasField('ExtendedDatabaseField'), 'hasField() finds extended fields in subclass instances');
|
||||||
$this->assertTrue($subteamInstance->hasField('DecoratedHasOneRelationshipID'), 'hasField() finds decorated foreign keys in subclass instances');
|
$this->assertTrue($subteamInstance->hasField('ExtendedHasOneRelationshipID'), 'hasField() finds extended foreign keys in subclass instances');
|
||||||
|
|
||||||
/* hasDatabaseField() singleton checks */
|
/* hasDatabaseField() singleton checks */
|
||||||
//$this->assertTrue($teamSingleton->hasDatabaseField('ID'), 'hasDatabaseField() finds built-in fields in singletons');
|
//$this->assertTrue($teamSingleton->hasDatabaseField('ID'), 'hasDatabaseField() finds built-in fields in singletons');
|
||||||
@ -481,9 +481,9 @@ class DataObjectTest extends SapphireTest {
|
|||||||
$this->assertFalse($teamInstance->hasDatabaseField('SubclassDatabaseField'), 'hasDatabaseField() doesnt find subclass fields in parentclass instances');
|
$this->assertFalse($teamInstance->hasDatabaseField('SubclassDatabaseField'), 'hasDatabaseField() doesnt find subclass fields in parentclass instances');
|
||||||
//$this->assertFalse($teamInstance->hasDatabaseField('DynamicField'), 'hasDatabaseField() doesnt dynamic getters in instances');
|
//$this->assertFalse($teamInstance->hasDatabaseField('DynamicField'), 'hasDatabaseField() doesnt dynamic getters in instances');
|
||||||
$this->assertTrue($teamInstance->hasDatabaseField('HasOneRelationshipID'), 'hasDatabaseField() finds foreign keys in instances');
|
$this->assertTrue($teamInstance->hasDatabaseField('HasOneRelationshipID'), 'hasDatabaseField() finds foreign keys in instances');
|
||||||
$this->assertTrue($teamInstance->hasDatabaseField('DecoratedDatabaseField'), 'hasDatabaseField() finds decorated fields in instances');
|
$this->assertTrue($teamInstance->hasDatabaseField('ExtendedDatabaseField'), 'hasDatabaseField() finds extended fields in instances');
|
||||||
$this->assertTrue($teamInstance->hasDatabaseField('DecoratedHasOneRelationshipID'), 'hasDatabaseField() finds decorated foreign keys in instances');
|
$this->assertTrue($teamInstance->hasDatabaseField('ExtendedHasOneRelationshipID'), 'hasDatabaseField() finds extended foreign keys in instances');
|
||||||
$this->assertFalse($teamInstance->hasDatabaseField('DecoratedDynamicField'), 'hasDatabaseField() doesnt include decorated dynamic getters in instances');
|
$this->assertFalse($teamInstance->hasDatabaseField('ExtendedDynamicField'), 'hasDatabaseField() doesnt include extended dynamic getters in instances');
|
||||||
|
|
||||||
/* hasDatabaseField() subclass checks */
|
/* hasDatabaseField() subclass checks */
|
||||||
$this->assertTrue($subteamInstance->hasField('DatabaseField'), 'hasField() finds custom fields in subclass instances');
|
$this->assertTrue($subteamInstance->hasField('DatabaseField'), 'hasField() finds custom fields in subclass instances');
|
||||||
@ -507,12 +507,12 @@ class DataObjectTest extends SapphireTest {
|
|||||||
//'LastEdited',
|
//'LastEdited',
|
||||||
'Title',
|
'Title',
|
||||||
'DatabaseField',
|
'DatabaseField',
|
||||||
'DecoratedDatabaseField',
|
'ExtendedDatabaseField',
|
||||||
'CaptainID',
|
'CaptainID',
|
||||||
'HasOneRelationshipID',
|
'HasOneRelationshipID',
|
||||||
'DecoratedHasOneRelationshipID'
|
'ExtendedHasOneRelationshipID'
|
||||||
),
|
),
|
||||||
'inheritedDatabaseFields() contains all fields defined on instance, including base fields, decorated fields and foreign keys'
|
'inheritedDatabaseFields() contains all fields defined on instance, including base fields, extended fields and foreign keys'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
@ -524,12 +524,12 @@ class DataObjectTest extends SapphireTest {
|
|||||||
'LastEdited',
|
'LastEdited',
|
||||||
'Title',
|
'Title',
|
||||||
'DatabaseField',
|
'DatabaseField',
|
||||||
'DecoratedDatabaseField',
|
'ExtendedDatabaseField',
|
||||||
'CaptainID',
|
'CaptainID',
|
||||||
'HasOneRelationshipID',
|
'HasOneRelationshipID',
|
||||||
'DecoratedHasOneRelationshipID'
|
'ExtendedHasOneRelationshipID'
|
||||||
),
|
),
|
||||||
'databaseFields() contains only fields defined on instance, including base fields, decorated fields and foreign keys'
|
'databaseFields() contains only fields defined on instance, including base fields, extended fields and foreign keys'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
@ -542,12 +542,12 @@ class DataObjectTest extends SapphireTest {
|
|||||||
'SubclassDatabaseField',
|
'SubclassDatabaseField',
|
||||||
'Title',
|
'Title',
|
||||||
'DatabaseField',
|
'DatabaseField',
|
||||||
'DecoratedDatabaseField',
|
'ExtendedDatabaseField',
|
||||||
'CaptainID',
|
'CaptainID',
|
||||||
'HasOneRelationshipID',
|
'HasOneRelationshipID',
|
||||||
'DecoratedHasOneRelationshipID',
|
'ExtendedHasOneRelationshipID',
|
||||||
),
|
),
|
||||||
'inheritedDatabaseFields() on subclass contains all fields defined on instance, including base fields, decorated fields and foreign keys'
|
'inheritedDatabaseFields() on subclass contains all fields defined on instance, including base fields, extended fields and foreign keys'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
@ -803,8 +803,8 @@ class DataObjectTest extends SapphireTest {
|
|||||||
"hasOwnDatabaseField() doesn't detect non-existend fields"
|
"hasOwnDatabaseField() doesn't detect non-existend fields"
|
||||||
);
|
);
|
||||||
$this->assertTrue(
|
$this->assertTrue(
|
||||||
$team->hasDatabaseField('DecoratedDatabaseField'),
|
$team->hasDatabaseField('ExtendedDatabaseField'),
|
||||||
"hasOwnDatabaseField() works with decorated fields"
|
"hasOwnDatabaseField() works with extended fields"
|
||||||
);
|
);
|
||||||
$this->assertFalse(
|
$this->assertFalse(
|
||||||
$team->hasDatabaseField('SubclassDatabaseField'),
|
$team->hasDatabaseField('SubclassDatabaseField'),
|
||||||
@ -1087,21 +1087,21 @@ class DataObjectTest_FieldlessSubTable extends DataObjectTest_Team implements Te
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class DataObjectTest_Team_Decorator extends DataObjectDecorator implements TestOnly {
|
class DataObjectTest_Team_Extension extends DataExtension implements TestOnly {
|
||||||
|
|
||||||
function extraStatics() {
|
function extraStatics() {
|
||||||
return array(
|
return array(
|
||||||
'db' => array(
|
'db' => array(
|
||||||
'DecoratedDatabaseField' => 'Varchar'
|
'ExtendedDatabaseField' => 'Varchar'
|
||||||
),
|
),
|
||||||
'has_one' => array(
|
'has_one' => array(
|
||||||
'DecoratedHasOneRelationship' => 'DataObjectTest_Player'
|
'ExtendedHasOneRelationship' => 'DataObjectTest_Player'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDecoratedDynamicField() {
|
function getExtendedDynamicField() {
|
||||||
return "decorated dynamic field";
|
return "extended dynamic field";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1159,6 +1159,6 @@ class DataObjectTest_TeamComment extends DataObject {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
DataObject::add_extension('DataObjectTest_Team', 'DataObjectTest_Team_Decorator');
|
DataObject::add_extension('DataObjectTest_Team', 'DataObjectTest_Team_Extension');
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
@ -23,11 +23,11 @@ DataObjectTest_SubTeam:
|
|||||||
subteam1:
|
subteam1:
|
||||||
Title: Subteam 1
|
Title: Subteam 1
|
||||||
SubclassDatabaseField: Subclassed 1
|
SubclassDatabaseField: Subclassed 1
|
||||||
DecoratedDatabaseField: Decorated 1
|
ExtendedDatabaseField: Extended 1
|
||||||
subteam2_with_player_relation:
|
subteam2_with_player_relation:
|
||||||
Title: Subteam 2
|
Title: Subteam 2
|
||||||
SubclassDatabaseField: Subclassed 2
|
SubclassDatabaseField: Subclassed 2
|
||||||
DecoratedHasOneRelationship: =>DataObjectTest_Player.player1
|
ExtendedHasOneRelationship: =>DataObjectTest_Player.player1
|
||||||
subteam3_with_empty_fields:
|
subteam3_with_empty_fields:
|
||||||
Title: Subteam 3
|
Title: Subteam 3
|
||||||
|
|
||||||
|
@ -457,7 +457,7 @@ class MemberTest extends FunctionalTest {
|
|||||||
$this->session()->inst_set('loggedInAs', null);
|
$this->session()->inst_set('loggedInAs', null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDecoratedCan() {
|
public function testExtendedCan() {
|
||||||
$extensions = $this->removeExtensions(Object::get_extensions('Member'));
|
$extensions = $this->removeExtensions(Object::get_extensions('Member'));
|
||||||
$member = $this->objFromFixture('Member', 'test');
|
$member = $this->objFromFixture('Member', 'test');
|
||||||
|
|
||||||
@ -466,7 +466,7 @@ class MemberTest extends FunctionalTest {
|
|||||||
$this->assertFalse($member->canDelete());
|
$this->assertFalse($member->canDelete());
|
||||||
$this->assertFalse($member->canEdit());
|
$this->assertFalse($member->canEdit());
|
||||||
|
|
||||||
/* Apply a decorator that allows viewing in any case (most likely the case for member profiles) */
|
/* Apply a extension that allows viewing in any case (most likely the case for member profiles) */
|
||||||
Object::add_extension('Member', 'MemberTest_ViewingAllowedExtension');
|
Object::add_extension('Member', 'MemberTest_ViewingAllowedExtension');
|
||||||
$member2 = $this->objFromFixture('Member', 'staffmember');
|
$member2 = $this->objFromFixture('Member', 'staffmember');
|
||||||
|
|
||||||
@ -474,7 +474,7 @@ class MemberTest extends FunctionalTest {
|
|||||||
$this->assertFalse($member2->canDelete());
|
$this->assertFalse($member2->canDelete());
|
||||||
$this->assertFalse($member2->canEdit());
|
$this->assertFalse($member2->canEdit());
|
||||||
|
|
||||||
/* Apply a decorator that denies viewing of the Member */
|
/* Apply a extension that denies viewing of the Member */
|
||||||
Object::remove_extension('Member', 'MemberTest_ViewingAllowedExtension');
|
Object::remove_extension('Member', 'MemberTest_ViewingAllowedExtension');
|
||||||
Object::add_extension('Member', 'MemberTest_ViewingDeniedExtension');
|
Object::add_extension('Member', 'MemberTest_ViewingDeniedExtension');
|
||||||
$member3 = $this->objFromFixture('Member', 'managementmember');
|
$member3 = $this->objFromFixture('Member', 'managementmember');
|
||||||
@ -483,7 +483,7 @@ class MemberTest extends FunctionalTest {
|
|||||||
$this->assertFalse($member3->canDelete());
|
$this->assertFalse($member3->canDelete());
|
||||||
$this->assertFalse($member3->canEdit());
|
$this->assertFalse($member3->canEdit());
|
||||||
|
|
||||||
/* Apply a decorator that allows viewing and editing but denies deletion */
|
/* Apply a extension that allows viewing and editing but denies deletion */
|
||||||
Object::remove_extension('Member', 'MemberTest_ViewingDeniedExtension');
|
Object::remove_extension('Member', 'MemberTest_ViewingDeniedExtension');
|
||||||
Object::add_extension('Member', 'MemberTest_EditingAllowedDeletingDeniedExtension');
|
Object::add_extension('Member', 'MemberTest_EditingAllowedDeletingDeniedExtension');
|
||||||
$member4 = $this->objFromFixture('Member', 'accountingmember');
|
$member4 = $this->objFromFixture('Member', 'accountingmember');
|
||||||
@ -589,21 +589,21 @@ class MemberTest extends FunctionalTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
class MemberTest_ViewingAllowedExtension extends DataObjectDecorator implements TestOnly {
|
class MemberTest_ViewingAllowedExtension extends DataExtension implements TestOnly {
|
||||||
|
|
||||||
public function canView() {
|
public function canView() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
class MemberTest_ViewingDeniedExtension extends DataObjectDecorator implements TestOnly {
|
class MemberTest_ViewingDeniedExtension extends DataExtension implements TestOnly {
|
||||||
|
|
||||||
public function canView() {
|
public function canView() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
class MemberTest_EditingAllowedDeletingDeniedExtension extends DataObjectDecorator implements TestOnly {
|
class MemberTest_EditingAllowedDeletingDeniedExtension extends DataExtension implements TestOnly {
|
||||||
|
|
||||||
public function canView() {
|
public function canView() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -2924,7 +2924,7 @@ class SSTemplateParser extends Parser {
|
|||||||
* 'Arguments' an array of the Argument match rule result arrays
|
* 'Arguments' an array of the Argument match rule result arrays
|
||||||
*
|
*
|
||||||
* Once a block has successfully been matched against, it will then look for the actual handler, which should
|
* Once a block has successfully been matched against, it will then look for the actual handler, which should
|
||||||
* be on this class (either defined or decorated on) as ClosedBlock_Handler_Name(&$res), where Name is the
|
* be on this class (either defined or extended on) as ClosedBlock_Handler_Name(&$res), where Name is the
|
||||||
* tag name, first letter captialized (i.e Control, Loop, With, etc).
|
* tag name, first letter captialized (i.e Control, Loop, With, etc).
|
||||||
*
|
*
|
||||||
* This function will be called with the match rule result array as it's first argument. It should return
|
* This function will be called with the match rule result array as it's first argument. It should return
|
||||||
|
@ -601,7 +601,7 @@ class SSTemplateParser extends Parser {
|
|||||||
* 'Arguments' an array of the Argument match rule result arrays
|
* 'Arguments' an array of the Argument match rule result arrays
|
||||||
*
|
*
|
||||||
* Once a block has successfully been matched against, it will then look for the actual handler, which should
|
* Once a block has successfully been matched against, it will then look for the actual handler, which should
|
||||||
* be on this class (either defined or decorated on) as ClosedBlock_Handler_Name(&$res), where Name is the
|
* be on this class (either defined or extended on) as ClosedBlock_Handler_Name(&$res), where Name is the
|
||||||
* tag name, first letter captialized (i.e Control, Loop, With, etc).
|
* tag name, first letter captialized (i.e Control, Loop, With, etc).
|
||||||
*
|
*
|
||||||
* This function will be called with the match rule result array as it's first argument. It should return
|
* This function will be called with the match rule result array as it's first argument. It should return
|
||||||
|
Loading…
Reference in New Issue
Block a user