mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
API CHANGE: Renamed DataObjectDecorator to DataExtension.
API CHANGE: Renamed LeftAndMainDecorator to LeftAndMainExtension. MINOR: Replaced all references to decorators with extension.
This commit is contained in:
parent
44dabbb865
commit
3a1c2df4e7
@ -86,7 +86,7 @@ class LeftAndMain extends Controller {
|
||||
// cms menus only for logged-in members
|
||||
if(!$member) return false;
|
||||
|
||||
// alternative decorated checks
|
||||
// alternative extended checks
|
||||
if($this->hasMethod('alternateAccessCheck')) {
|
||||
$alternateAllowed = $this->alternateAccessCheck();
|
||||
if($alternateAllowed === FALSE) return false;
|
||||
@ -102,8 +102,8 @@ class LeftAndMain extends Controller {
|
||||
}
|
||||
|
||||
/**
|
||||
* @uses LeftAndMainDecorator->init()
|
||||
* @uses LeftAndMainDecorator->accessedCMS()
|
||||
* @uses LeftAndMainExtension->init()
|
||||
* @uses LeftAndMainExtension->accessedCMS()
|
||||
* @uses CMSMenu
|
||||
*/
|
||||
function init() {
|
||||
@ -124,7 +124,7 @@ class LeftAndMain extends Controller {
|
||||
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()
|
||||
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
|
||||
|
@ -1,21 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* Plug-ins for additional functionality in your LeftAndMain classes.
|
||||
*
|
||||
* @package cms
|
||||
* @subpackage core
|
||||
* @package sapphire
|
||||
* @subpackage admin
|
||||
* @deprecated 3.0 Use {@link LeftAndMainExtension}
|
||||
*/
|
||||
abstract class LeftAndMainDecorator extends Extension {
|
||||
|
||||
function init() {
|
||||
abstract class LeftAndMainDecorator extends LeftAndMainExtension {
|
||||
|
||||
public function __construct() {
|
||||
user_error(
|
||||
'LeftAndMainDecorator is deprecated, please use LeftAndMainExtension instead.',
|
||||
E_USER_NOTICE
|
||||
);
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
function accessedCMS() {
|
||||
}
|
||||
|
||||
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)
|
||||
* 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 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
|
||||
*
|
||||
* @package sapphire
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* 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
|
||||
* {@link getOwner()}.
|
||||
* Every object instance gets its own set of extension instances,
|
||||
@ -19,8 +19,9 @@ abstract class Extension {
|
||||
public static $allowed_actions = null;
|
||||
|
||||
/**
|
||||
* The DataObject that owns this decorator.
|
||||
* @var DataObject
|
||||
* The object this extension is applied to.
|
||||
*
|
||||
* @var Object
|
||||
*/
|
||||
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 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,
|
||||
@ -65,7 +66,7 @@ abstract class Extension {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the owner of this decorator
|
||||
* Returns the owner of this extension.
|
||||
*
|
||||
* @return Object
|
||||
*/
|
||||
|
@ -277,7 +277,6 @@ abstract class Object {
|
||||
}
|
||||
|
||||
if(!isset(self::$cached_statics[$class][$name]) || $uncached) {
|
||||
//if($class == 'DataObjectDecoratorTest_MyObject') Debug::message("$class - $name");
|
||||
$extra = $builtIn = $break = $replacedAt = false;
|
||||
$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
|
||||
* 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
|
||||
* as a string, e.g. "Versioned" or "Translatable('Param')"
|
||||
*/
|
||||
@ -538,11 +537,11 @@ abstract class Object {
|
||||
|
||||
// load statics now for DataObject classes
|
||||
if(is_subclass_of($class, 'DataObject')) {
|
||||
if(is_subclass_of($extensionClass, 'DataObjectDecorator')) {
|
||||
DataObjectDecorator::load_extra_statics($class, $extension);
|
||||
if(is_subclass_of($extensionClass, 'DataExtension')) {
|
||||
DataExtension::load_extra_statics($class, $extension);
|
||||
}
|
||||
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];
|
||||
}
|
||||
|
||||
if(is_subclass_of($extensionClass, 'DataObjectDecorator')) {
|
||||
DataObjectDecorator::load_extra_statics($class, $extension);
|
||||
if(is_subclass_of($extensionClass, 'DataExtension')) {
|
||||
DataExtension::load_extra_statics($class, $extension);
|
||||
}
|
||||
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 bool $includeArgumentString Include the argument string in the return array,
|
||||
* 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.
|
||||
*/
|
||||
function get_extensions($class, $includeArgumentString = false) {
|
||||
@ -950,7 +949,7 @@ abstract class Object {
|
||||
* 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
|
||||
* 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
|
||||
* 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
|
||||
* at constructor time, meaning if you use {@link add_extension()}
|
||||
* 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.
|
||||
* Caution: Don't use singleton(<class>)->hasExtension() as it will
|
||||
* 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
|
||||
* 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() {
|
||||
return $this->extension_instances;
|
||||
|
@ -688,9 +688,9 @@ class SapphireTest extends PHPUnit_Framework_TestCase {
|
||||
$dbConn = DB::getConn();
|
||||
$dbName = $dbConn->currentDatabase();
|
||||
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
|
||||
foreach(ClassInfo::subclassesFor('DataObjectDecorator') as $class) {
|
||||
foreach(ClassInfo::subclassesFor('DataExtension') as $class) {
|
||||
$toCall = array($class, 'on_db_reset');
|
||||
if(is_callable($toCall)) call_user_func($toCall);
|
||||
}
|
||||
@ -709,9 +709,9 @@ class SapphireTest extends PHPUnit_Framework_TestCase {
|
||||
$dbadmin = new DatabaseAdmin();
|
||||
$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
|
||||
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');
|
||||
if(is_callable($toCall)) call_user_func($toCall);
|
||||
}
|
||||
|
@ -1,22 +1,22 @@
|
||||
# DataObjectDecorator
|
||||
# DataExtension
|
||||
|
||||
## 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
|
||||
implementation. Have a look at `[api:Object->useCustomClass()]`.
|
||||
|
||||
## 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
|
||||
|
||||
// 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
|
||||
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
|
||||
`[api:ForumRole]` decorator to the `[api:Member]` object.
|
||||
Sometimes you will want to add extension to classes that you didn't make. For example, you might want to add the
|
||||
`[api:ForumRole]` extension to the `[api:Member]` object.
|
||||
|
||||
|
||||
:::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
|
||||
|
||||
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:
|
||||
|
||||
:::php
|
||||
class CustomMember extends DataObjectDecorator {
|
||||
class CustomMember extends DataExtension {
|
||||
|
||||
function extraStatics() {
|
||||
return array(
|
||||
@ -67,7 +67,7 @@ The function should return a map where the keys are the names of the static vari
|
||||
|
||||
*NOTE*
|
||||
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
|
||||
for statics.
|
||||
|
||||
@ -75,7 +75,7 @@ for statics.
|
||||
### Modifying CMS Fields
|
||||
|
||||
The member class demonstrates an extension that allows you to update the default CMS fields for an object in a
|
||||
decorator:
|
||||
extension:
|
||||
|
||||
:::php
|
||||
public function getCMSFields() {
|
||||
@ -97,11 +97,11 @@ The $fields parameter is passed by reference, as it is an object.
|
||||
|
||||
### 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,
|
||||
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 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
|
||||
|
||||
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
|
||||
being decorated. For instance, you may add a publish() method to every `[api:DataObject]` that is decorated with `[api:Versioned]`.
|
||||
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 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 = The `[api:DataObjectDecorator]` object.
|
||||
* $this = The `[api:DataExtension]` 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
|
||||
to as `$this->propertyName`. Every `[api:DataObject]` has an associated `[api:DataObjectDecorator]` instance for each class that it is
|
||||
decorated by.
|
||||
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:DataExtension]` instance for each class that it is
|
||||
extended by.
|
||||
|
||||
:::php
|
||||
class Customer extends DataObject {
|
||||
@ -159,7 +159,7 @@ decorated by.
|
||||
|
||||
}
|
||||
|
||||
class CustomerWorkflow extends DataObjectDecorator {
|
||||
class CustomerWorkflow extends DataExtension {
|
||||
|
||||
function IsMarkedForDeletion() {
|
||||
return ($this->owner->Account()->IsMarkedForDeletion == 1) ? true : false;
|
||||
@ -169,4 +169,4 @@ decorated by.
|
||||
|
||||
|
||||
## 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
|
||||
|
||||
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.*
|
||||
|
||||
|
@ -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
|
||||
* [Database Structure](database-structure): Conventions and best practices for database tables and fields
|
||||
* [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
|
||||
* [Director](director): Routes URLs and handles HTTP requests
|
||||
* [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
|
||||
|
||||
<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).
|
||||
</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,
|
||||
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
|
||||
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
|
||||
DataObject::add_extension('Member', 'ForumRole');
|
||||
Object::add_extension('Member', 'ForumRole');
|
||||
// OR
|
||||
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
|
||||
things, you should add appropriate `[api:Permission::checkMember()]` calls to the role's methods.
|
||||
|
||||
:::php
|
||||
class ForumRole extends DataObjectDecorator {
|
||||
class ForumRole extends DataExtension {
|
||||
/**
|
||||
|
||||
* 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
|
||||
|
||||
class CustomSiteConfig extends DataObjectDecorator {
|
||||
class CustomSiteConfig extends DataExtension {
|
||||
|
||||
function extraStatics() {
|
||||
return array(
|
||||
|
@ -35,7 +35,7 @@ Append the option and corresponding value to your URL in your browser's address
|
||||
|
||||
| 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 |
|
||||
|
||||
## 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
|
||||
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.
|
||||
|
||||
|
||||
|
@ -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
|
||||
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
|
||||
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)
|
||||
* [Module Release Process](module-release-process)
|
||||
* [Debugging methods](/topics/debugging)
|
||||
* [URL Variable Tools](/reference/urlvariabletools) - Lists a number of “page options” , “rendering tools” or “special
|
||||
URL variables” that you can use to debug your sapphire applications
|
||||
* [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<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 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.
|
||||
* 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.
|
||||
* You can modify this fieldset by subclassing folder, or by creating a {@link DataObjectDecorator}
|
||||
* and implemeting updateCMSFields(FieldSet $fields) on that decorator.
|
||||
* You can modify this fieldset by subclassing folder, or by creating a {@link DataExtension}
|
||||
* and implemeting updateCMSFields(FieldSet $fields) on that extension.
|
||||
*/
|
||||
function getCMSFields() {
|
||||
$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.
|
||||
*
|
||||
* <h2>Extensions and Decorators</h2>
|
||||
* <h2>Extensions</h2>
|
||||
*
|
||||
* See {@link Extension} and {@link DataObjectDecorator}.
|
||||
* See {@link Extension} and {@link DataExtension}.
|
||||
*
|
||||
* <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.
|
||||
*
|
||||
* @uses DataObjectDecorator->onBeforeWrite()
|
||||
* @uses DataExtension->onBeforeWrite()
|
||||
*/
|
||||
protected function onBeforeWrite() {
|
||||
$this->brokenOnWrite = false;
|
||||
@ -905,7 +905,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
* $this->changed will have a record
|
||||
* database. Don't forget to call parent::onAfterWrite(), though!
|
||||
*
|
||||
* @uses DataObjectDecorator->onAfterWrite()
|
||||
* @uses DataExtension->onAfterWrite()
|
||||
*/
|
||||
protected function onAfterWrite() {
|
||||
$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
|
||||
* record. Don't forget to call parent::onBeforeDelete(), though!
|
||||
*
|
||||
* @uses DataObjectDecorator->onBeforeDelete()
|
||||
* @uses DataExtension->onBeforeDelete()
|
||||
*/
|
||||
protected function onBeforeDelete() {
|
||||
$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.
|
||||
* Called by the constructor when creating new records.
|
||||
*
|
||||
* @uses DataObjectDecorator->populateDefaults()
|
||||
* @uses DataExtension->populateDefaults()
|
||||
*/
|
||||
public function populateDefaults() {
|
||||
$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.
|
||||
* - 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 $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.
|
||||
* $this->onBeforeDelete() gets called.
|
||||
* Note that in Versioned objects, both Stage and Live will be deleted.
|
||||
* @uses DataObjectDecorator->augmentSQL()
|
||||
* @uses DataExtension->augmentSQL()
|
||||
*/
|
||||
public function delete() {
|
||||
$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.
|
||||
* If not overloaded, we're using {@link scaffoldFormFields()} to automatically
|
||||
* 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>
|
||||
* 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,
|
||||
* 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
|
||||
*/
|
||||
@ -2034,7 +2034,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
* Used for simple frontend forms without relation editing
|
||||
* or {@link TabSet} behaviour. Uses {@link scaffoldFormFields()}
|
||||
* 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
|
||||
*
|
||||
@ -2277,7 +2277,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
if($field == "LastEdited" && 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')) {
|
||||
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:
|
||||
*
|
||||
* - false: Disallow this permission, regardless of what other decorators say
|
||||
* - true: Allow this permission, as long as no other decorators return false
|
||||
* - false: Disallow this permission, regardless of what other extensions say
|
||||
* - true: Allow this permission, as long as no other extensions return false
|
||||
* - NULL: Don't affect the outcome
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @uses DataObjectDecorator->augmentSQL()
|
||||
* @uses DataExtension->augmentSQL()
|
||||
*
|
||||
* @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.
|
||||
@ -2936,7 +2936,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
/**
|
||||
* 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 $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.
|
||||
*
|
||||
* @uses DataObjectDecorator->augmentDatabase()
|
||||
* @uses DataExtension->augmentDatabase()
|
||||
*/
|
||||
public function requireTable() {
|
||||
// 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
|
||||
* call parent::requireDefaultRecords().
|
||||
*
|
||||
* @uses DataObjectDecorator->requireDefaultRecords()
|
||||
* @uses DataExtension->requireDefaultRecords()
|
||||
*/
|
||||
public function requireDefaultRecords() {
|
||||
$defaultRecords = $this->stat('default_records');
|
||||
@ -3172,8 +3172,8 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
if(!$fields) $fields = array_keys($this->summaryFields());
|
||||
|
||||
// we need to make sure the format is unified before
|
||||
// augmenting fields, so decorators can apply consistent checks
|
||||
// but also after augmenting fields, because the decorator
|
||||
// augmenting fields, so extensions can apply consistent checks
|
||||
// but also after augmenting fields, because the extension
|
||||
// might use the shorthand notation as well
|
||||
|
||||
// rewrite array, if it is using shorthand syntax
|
||||
@ -3210,7 +3210,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
|
||||
$fields = $rewrite;
|
||||
|
||||
// apply DataObjectDecorators if present
|
||||
// apply DataExtensions if present
|
||||
$this->extend('updateSearchableFields', $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.
|
||||
* 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,
|
||||
* which could cause horrible bugs.
|
||||
*/
|
||||
|
@ -1,235 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* Plug-ins for additional functionality in your DataObjects.
|
||||
*
|
||||
* 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
|
||||
* @package sapphire
|
||||
* @subpackage model
|
||||
* @deprecated 3.0 Use {@link DataExtension}.
|
||||
*/
|
||||
abstract class DataObjectDecorator extends Extension {
|
||||
abstract class DataObjectDecorator extends DataExtension {
|
||||
|
||||
/**
|
||||
* Statics on a {@link DataObject} subclass
|
||||
* which can be decorated onto. 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 $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) {
|
||||
public function __construct() {
|
||||
user_error(
|
||||
'DataObjectDecorator is deprecated, please use DataExtension instead.',
|
||||
E_USER_NOTICE
|
||||
);
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
/**
|
||||
* 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.
|
||||
* @package sapphire
|
||||
* @subpackage model
|
||||
*/
|
||||
class Hierarchy extends DataObjectDecorator {
|
||||
class Hierarchy extends DataExtension {
|
||||
|
||||
protected $markedNodes;
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
<?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.
|
||||
* @package sapphire
|
||||
* @subpackage model
|
||||
*/
|
||||
class Versioned extends DataObjectDecorator {
|
||||
class Versioned extends DataExtension {
|
||||
/**
|
||||
* An array of possible stages.
|
||||
* @var array
|
||||
@ -42,7 +42,7 @@ class Versioned extends DataObjectDecorator {
|
||||
/**
|
||||
* Additional database columns for the new
|
||||
* "_versions" table. Used in {@link augmentDatabase()}
|
||||
* and all Versioned calls decorating or creating
|
||||
* and all Versioned calls extending or creating
|
||||
* SELECT statements.
|
||||
*
|
||||
* @var array $db_for_versions_table
|
||||
|
@ -11,7 +11,7 @@
|
||||
* @package sapphire
|
||||
* @subpackage search
|
||||
*/
|
||||
class FulltextSearchable extends DataObjectDecorator {
|
||||
class FulltextSearchable extends DataExtension {
|
||||
|
||||
/**
|
||||
* @var String Comma-separated list of database column names
|
||||
|
@ -359,7 +359,7 @@ class Group extends DataObject {
|
||||
public function canEdit($member = null) {
|
||||
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
|
||||
|
||||
// decorated access checks
|
||||
// extended access checks
|
||||
$results = $this->extend('canEdit', $member);
|
||||
if($results && is_array($results)) if(!min($results)) return false;
|
||||
|
||||
@ -389,7 +389,7 @@ class Group extends DataObject {
|
||||
public function canView($member = null) {
|
||||
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
|
||||
|
||||
// decorated access checks
|
||||
// extended access checks
|
||||
$results = $this->extend('canView', $member);
|
||||
if($results && is_array($results)) if(!min($results)) return false;
|
||||
|
||||
@ -402,7 +402,7 @@ class Group extends DataObject {
|
||||
public function canDelete($member = null) {
|
||||
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
|
||||
|
||||
// decorated access checks
|
||||
// extended access checks
|
||||
$results = $this->extend('canDelete', $member);
|
||||
if($results && is_array($results)) if(!min($results)) return false;
|
||||
|
||||
|
@ -1264,7 +1264,7 @@ class Member extends DataObject {
|
||||
function canView($member = null) {
|
||||
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
|
||||
|
||||
// decorated access checks
|
||||
// extended access checks
|
||||
$results = $this->extend('canView', $member);
|
||||
if($results && is_array($results)) {
|
||||
if(!min($results)) return false;
|
||||
@ -1291,7 +1291,7 @@ class Member extends DataObject {
|
||||
function canEdit($member = null) {
|
||||
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
|
||||
|
||||
// decorated access checks
|
||||
// extended access checks
|
||||
$results = $this->extend('canEdit', $member);
|
||||
if($results && is_array($results)) {
|
||||
if(!min($results)) return false;
|
||||
@ -1318,7 +1318,7 @@ class Member extends DataObject {
|
||||
function canDelete($member = null) {
|
||||
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
|
||||
|
||||
// decorated access checks
|
||||
// extended access checks
|
||||
$results = $this->extend('canDelete', $member);
|
||||
if($results && is_array($results)) {
|
||||
if(!min($results)) return false;
|
||||
|
@ -5,7 +5,7 @@
|
||||
*
|
||||
* @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 through decorators (#2387)
|
||||
* @todo tests for setting statics through extensions (#2387)
|
||||
*/
|
||||
class ObjectTest extends SapphireTest {
|
||||
|
||||
|
@ -38,8 +38,8 @@ class FormScaffolderTest extends SapphireTest {
|
||||
$article1 = $this->objFromFixture('FormScaffolderTest_Article', 'article1');
|
||||
$fields = $article1->getCMSFields();
|
||||
$this->assertNotNull(
|
||||
$fields->dataFieldByName('AddedDecoratorField'),
|
||||
'getCMSFields() includes decorated fields'
|
||||
$fields->dataFieldByName('AddedExtensionField'),
|
||||
'getCMSFields() includes extended fields'
|
||||
);
|
||||
}
|
||||
|
||||
@ -102,16 +102,16 @@ class FormScaffolderTest_Tag extends DataObject implements TestOnly {
|
||||
'Articles' => 'FormScaffolderTest_Article'
|
||||
);
|
||||
}
|
||||
class FormScaffolderTest_ArticleDecorator extends DataObjectDecorator implements TestOnly {
|
||||
class FormScaffolderTest_ArticleExtension extends DataExtension implements TestOnly {
|
||||
static $db = array(
|
||||
'DecoratedField' => 'Varchar'
|
||||
'ExtendedField' => 'Varchar'
|
||||
);
|
||||
function updateCMSFields(&$fields) {
|
||||
$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
|
||||
class i18nTestModuleDecorator extends DataObjectDecorator {
|
||||
class i18nTestModuleExtension extends DataExtension {
|
||||
function extraStatics() {
|
||||
return array(
|
||||
'db' => array(
|
||||
|
@ -1,26 +1,26 @@
|
||||
<?php
|
||||
|
||||
class DataObjectDecoratorTest extends SapphireTest {
|
||||
static $fixture_file = 'DataObjectDecoratorTest.yml';
|
||||
class DataExtensionTest extends SapphireTest {
|
||||
static $fixture_file = 'DataExtensionTest.yml';
|
||||
|
||||
protected $extraDataObjects = array(
|
||||
'DataObjectDecoratorTest_Member',
|
||||
'DataObjectDecoratorTest_Player',
|
||||
'DataObjectDecoratorTest_RelatedObject',
|
||||
'DataObjectDecoratorTest_MyObject',
|
||||
'DataExtensionTest_Member',
|
||||
'DataExtensionTest_Player',
|
||||
'DataExtensionTest_RelatedObject',
|
||||
'DataExtensionTest_MyObject',
|
||||
);
|
||||
|
||||
protected $requiredExtensions = array(
|
||||
'DataObject' => array( 'DataObjectDecoratorTest_AppliedToDO' ),
|
||||
'DataObject' => array( 'DataExtensionTest_AppliedToDO' ),
|
||||
);
|
||||
|
||||
function testOneToManyAssociationWithDecorator() {
|
||||
function testOneToManyAssociationWithExtension() {
|
||||
// Fails in RestfulServerTest
|
||||
// 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";
|
||||
|
||||
$object = new DataObjectDecoratorTest_RelatedObject();
|
||||
$object = new DataExtensionTest_RelatedObject();
|
||||
$object->FieldOne = "Lorem ipsum dolor";
|
||||
$object->FieldTwo = "Random notes";
|
||||
|
||||
@ -37,28 +37,28 @@ class DataObjectDecoratorTest extends SapphireTest {
|
||||
unset($contact);
|
||||
unset($object);
|
||||
|
||||
$contact = DataObject::get_one("DataObjectDecoratorTest_Member", "\"Website\"='http://www.example.com'");
|
||||
$object = DataObject::get_one('DataObjectDecoratorTest_RelatedObject', "\"ContactID\" = {$contactID}");
|
||||
$contact = DataObject::get_one("DataExtensionTest_Member", "\"Website\"='http://www.example.com'");
|
||||
$object = DataObject::get_one('DataExtensionTest_RelatedObject', "\"ContactID\" = {$contactID}");
|
||||
|
||||
$this->assertNotNull($object, 'Related object not null');
|
||||
$this->assertType('DataObjectDecoratorTest_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->Contact(), 'Related contact is a member dataobject');
|
||||
$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("Random notes", $contact->RelatedObjects()->First()->FieldTwo);
|
||||
$contact->delete();
|
||||
}
|
||||
|
||||
function testManyManyAssociationWithDecorator() {
|
||||
$parent = new DataObjectDecoratorTest_MyObject();
|
||||
function testManyManyAssociationWithExtension() {
|
||||
$parent = new DataExtensionTest_MyObject();
|
||||
$parent->Title = 'My Title';
|
||||
$parent->write();
|
||||
|
||||
$this->assertEquals(0, $parent->Faves()->Count());
|
||||
|
||||
$obj1 = $this->objFromFixture('DataObjectDecoratorTest_RelatedObject', 'obj1');
|
||||
$obj2 = $this->objFromFixture('DataObjectDecoratorTest_RelatedObject', 'obj2');
|
||||
$obj1 = $this->objFromFixture('DataExtensionTest_RelatedObject', 'obj1');
|
||||
$obj2 = $this->objFromFixture('DataExtensionTest_RelatedObject', 'obj2');
|
||||
|
||||
$parent->Faves()->add($obj1->ID);
|
||||
$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() {
|
||||
// Object::add_extension() will load DOD statics directly, so let's try adding a decorator on the fly
|
||||
Object::add_extension('DataObjectDecoratorTest_Player', 'DataObjectDecoratorTest_PlayerDecorator');
|
||||
// Object::add_extension() will load DOD statics directly, so let's try adding a extension on the fly
|
||||
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);
|
||||
|
||||
// Create a test record with decorated fields, writing to the DB
|
||||
$player = new DataObjectDecoratorTest_Player();
|
||||
// Create a test record with extended fields, writing to the DB
|
||||
$player = new DataExtensionTest_Player();
|
||||
$player->setField('Name', 'Joe');
|
||||
$player->setField('DateBirth', '1990-5-10');
|
||||
$player->Address = '123 somewhere street';
|
||||
@ -89,66 +89,66 @@ class DataObjectDecoratorTest extends SapphireTest {
|
||||
|
||||
unset($player);
|
||||
|
||||
// Pull the record out of the DB and examine the decorated fields
|
||||
$player = DataObject::get_one('DataObjectDecoratorTest_Player', "\"Name\" = 'Joe'");
|
||||
// Pull the record out of the DB and examine the extended fields
|
||||
$player = DataObject::get_one('DataExtensionTest_Player', "\"Name\" = 'Joe'");
|
||||
$this->assertEquals($player->DateBirth, '1990-05-10');
|
||||
$this->assertEquals($player->Address, '123 somewhere street');
|
||||
$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() {
|
||||
$this->assertTrue(Object::get_static('DataObjectDecoratorTest_Member', 'api_access'));
|
||||
function testApiAccessCanBeExtended() {
|
||||
$this->assertTrue(Object::get_static('DataExtensionTest_Member', 'api_access'));
|
||||
}
|
||||
|
||||
function testPermissionDecoration() {
|
||||
function testPermissionExtension() {
|
||||
// testing behaviour in isolation, too many sideeffects and other checks
|
||||
// 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');
|
||||
$admin = $this->objFromFixture('Member', 'admin');
|
||||
|
||||
$this->assertFalse(
|
||||
$obj->canOne($websiteuser),
|
||||
'Both decorators return true, but original method returns false'
|
||||
'Both extensions return true, but original method returns false'
|
||||
);
|
||||
|
||||
$this->assertFalse(
|
||||
$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(
|
||||
$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() {
|
||||
$obj = new DataObjectDecoratorTest_Member();
|
||||
$obj = new DataExtensionTest_Member();
|
||||
$this->assertEquals(
|
||||
$obj->Phone,
|
||||
'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() {
|
||||
$member = $this->objFromFixture('DataObjectDecoratorTest_Member', 'member1');
|
||||
function testDbObjectOnExtendedFields() {
|
||||
$member = $this->objFromFixture('DataExtensionTest_Member', 'member1');
|
||||
$this->assertNotNull($member->dbObject('Website'));
|
||||
$this->assertType('Varchar', $member->dbObject('Website'));
|
||||
}
|
||||
|
||||
function testDecoratorCanBeAppliedToDataObject() {
|
||||
function testExtensionCanBeAppliedToDataObject() {
|
||||
$do = new DataObject();
|
||||
$mo = new DataObjectDecoratorTest_MyObject();
|
||||
$mo = new DataExtensionTest_MyObject();
|
||||
|
||||
$this->assertTrue($do->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(
|
||||
"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(
|
||||
'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) {
|
||||
// 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.
|
||||
if($class == 'DataObjectDecoratorTest_Player') {
|
||||
if($class == 'DataExtensionTest_Player') {
|
||||
return array(
|
||||
'db' => array(
|
||||
'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() {
|
||||
return array(
|
||||
@ -205,7 +205,7 @@ class DataObjectDecoratorTest_ContactRole extends DataObjectDecorator implements
|
||||
'Phone' => 'Varchar(255)',
|
||||
),
|
||||
'has_many' => array(
|
||||
'RelatedObjects' => 'DataObjectDecoratorTest_RelatedObject'
|
||||
'RelatedObjects' => 'DataExtensionTest_RelatedObject'
|
||||
),
|
||||
'defaults' => array(
|
||||
'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(
|
||||
"FieldOne" => "Varchar",
|
||||
@ -224,21 +224,21 @@ class DataObjectDecoratorTest_RelatedObject extends DataObject implements TestOn
|
||||
);
|
||||
|
||||
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(
|
||||
'Title' => 'Varchar',
|
||||
);
|
||||
|
||||
function canOne($member = null) {
|
||||
// decorated access checks
|
||||
// extended access checks
|
||||
$results = $this->extend('canOne', $member);
|
||||
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) {
|
||||
// decorated access checks
|
||||
// extended access checks
|
||||
$results = $this->extend('canTwo', $member);
|
||||
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) {
|
||||
// decorated access checks
|
||||
// extended access checks
|
||||
$results = $this->extend('canThree', $member);
|
||||
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) {
|
||||
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) {
|
||||
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() {
|
||||
return 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() {
|
||||
return "hello world";
|
||||
}
|
||||
}
|
||||
|
||||
DataObject::add_extension('DataObjectDecoratorTest_MyObject', 'DataObjectDecoratorTest_Ext1');
|
||||
DataObject::add_extension('DataObjectDecoratorTest_MyObject', 'DataObjectDecoratorTest_Ext2');
|
||||
DataObject::add_extension('DataObjectDecoratorTest_MyObject', 'DataObjectDecoratorTest_Faves');
|
||||
DataObject::add_extension('DataExtensionTest_MyObject', 'DataExtensionTest_Ext1');
|
||||
DataObject::add_extension('DataExtensionTest_MyObject', 'DataExtensionTest_Ext2');
|
||||
DataObject::add_extension('DataExtensionTest_MyObject', 'DataExtensionTest_Faves');
|
||||
?>
|
@ -1,4 +1,4 @@
|
||||
DataObjectDecoratorTest_RelatedObject:
|
||||
DataExtensionTest_RelatedObject:
|
||||
obj1:
|
||||
FieldOne: Obj1
|
||||
obj2:
|
||||
@ -15,10 +15,10 @@ Member:
|
||||
Groups: =>Group.admingroup
|
||||
websiteuser:
|
||||
Email: websiteuser@test.com
|
||||
DataObjectDecoratorTest_Member:
|
||||
DataExtensionTest_Member:
|
||||
member1:
|
||||
Name: Sam
|
||||
Website: http://www.example.org
|
||||
DataObjectDecoratorTest_MyObject:
|
||||
DataExtensionTest_MyObject:
|
||||
object1:
|
||||
Title: Object 1
|
@ -22,11 +22,11 @@ DataObjectTest_SubTeam:
|
||||
subteam1:
|
||||
Title: Subteam 1
|
||||
SubclassDatabaseField: Subclassed 1
|
||||
DecoratedDatabaseField: Decorated 1
|
||||
ExtendedDatabaseField: Extended 1
|
||||
subteam2_with_player_relation:
|
||||
Title: Subteam 2
|
||||
SubclassDatabaseField: Subclassed 2
|
||||
DecoratedHasOneRelationship: =>DataObjectTest_Player.player1
|
||||
ExtendeHasOneRelationship: =>DataObjectTest_Player.player1
|
||||
subteam3_with_empty_fields:
|
||||
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->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('DecoratedDatabaseField'), 'hasField() finds decorated fields in instances');
|
||||
$this->assertTrue($teamInstance->hasField('DecoratedHasOneRelationshipID'), 'hasField() finds decorated foreign keys in instances');
|
||||
//$this->assertTrue($teamInstance->hasField('DecoratedDynamicField'), 'hasField() includes decorated dynamic getters in instances');
|
||||
$this->assertTrue($teamInstance->hasField('ExtendedDatabaseField'), 'hasField() finds extended fields in instances');
|
||||
$this->assertTrue($teamInstance->hasField('ExtendedHasOneRelationshipID'), 'hasField() finds extended foreign keys in instances');
|
||||
//$this->assertTrue($teamInstance->hasField('ExtendedDynamicField'), 'hasField() includes extended dynamic getters in instances');
|
||||
|
||||
/* hasField() subclass checks */
|
||||
$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('DynamicField'), 'hasField() finds dynamic getters 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('DecoratedHasOneRelationshipID'), 'hasField() finds decorated foreign keys in subclass instances');
|
||||
$this->assertTrue($subteamInstance->hasField('ExtendedDatabaseField'), 'hasField() finds extended fields in subclass instances');
|
||||
$this->assertTrue($subteamInstance->hasField('ExtendedHasOneRelationshipID'), 'hasField() finds extended foreign keys in subclass instances');
|
||||
|
||||
/* hasDatabaseField() singleton checks */
|
||||
//$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('DynamicField'), 'hasDatabaseField() doesnt dynamic getters 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('DecoratedHasOneRelationshipID'), 'hasDatabaseField() finds decorated foreign keys in instances');
|
||||
$this->assertFalse($teamInstance->hasDatabaseField('DecoratedDynamicField'), 'hasDatabaseField() doesnt include decorated dynamic getters in instances');
|
||||
$this->assertTrue($teamInstance->hasDatabaseField('ExtendedDatabaseField'), 'hasDatabaseField() finds extended fields in instances');
|
||||
$this->assertTrue($teamInstance->hasDatabaseField('ExtendedHasOneRelationshipID'), 'hasDatabaseField() finds extended foreign keys in instances');
|
||||
$this->assertFalse($teamInstance->hasDatabaseField('ExtendedDynamicField'), 'hasDatabaseField() doesnt include extended dynamic getters in instances');
|
||||
|
||||
/* hasDatabaseField() subclass checks */
|
||||
$this->assertTrue($subteamInstance->hasField('DatabaseField'), 'hasField() finds custom fields in subclass instances');
|
||||
@ -507,12 +507,12 @@ class DataObjectTest extends SapphireTest {
|
||||
//'LastEdited',
|
||||
'Title',
|
||||
'DatabaseField',
|
||||
'DecoratedDatabaseField',
|
||||
'ExtendedDatabaseField',
|
||||
'CaptainID',
|
||||
'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(
|
||||
@ -524,12 +524,12 @@ class DataObjectTest extends SapphireTest {
|
||||
'LastEdited',
|
||||
'Title',
|
||||
'DatabaseField',
|
||||
'DecoratedDatabaseField',
|
||||
'ExtendedDatabaseField',
|
||||
'CaptainID',
|
||||
'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(
|
||||
@ -542,12 +542,12 @@ class DataObjectTest extends SapphireTest {
|
||||
'SubclassDatabaseField',
|
||||
'Title',
|
||||
'DatabaseField',
|
||||
'DecoratedDatabaseField',
|
||||
'ExtendedDatabaseField',
|
||||
'CaptainID',
|
||||
'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(
|
||||
@ -803,8 +803,8 @@ class DataObjectTest extends SapphireTest {
|
||||
"hasOwnDatabaseField() doesn't detect non-existend fields"
|
||||
);
|
||||
$this->assertTrue(
|
||||
$team->hasDatabaseField('DecoratedDatabaseField'),
|
||||
"hasOwnDatabaseField() works with decorated fields"
|
||||
$team->hasDatabaseField('ExtendedDatabaseField'),
|
||||
"hasOwnDatabaseField() works with extended fields"
|
||||
);
|
||||
$this->assertFalse(
|
||||
$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() {
|
||||
return array(
|
||||
'db' => array(
|
||||
'DecoratedDatabaseField' => 'Varchar'
|
||||
'ExtendedDatabaseField' => 'Varchar'
|
||||
),
|
||||
'has_one' => array(
|
||||
'DecoratedHasOneRelationship' => 'DataObjectTest_Player'
|
||||
'ExtendedHasOneRelationship' => 'DataObjectTest_Player'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function getDecoratedDynamicField() {
|
||||
return "decorated dynamic field";
|
||||
function getExtendedDynamicField() {
|
||||
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:
|
||||
Title: Subteam 1
|
||||
SubclassDatabaseField: Subclassed 1
|
||||
DecoratedDatabaseField: Decorated 1
|
||||
ExtendedDatabaseField: Extended 1
|
||||
subteam2_with_player_relation:
|
||||
Title: Subteam 2
|
||||
SubclassDatabaseField: Subclassed 2
|
||||
DecoratedHasOneRelationship: =>DataObjectTest_Player.player1
|
||||
ExtendedHasOneRelationship: =>DataObjectTest_Player.player1
|
||||
subteam3_with_empty_fields:
|
||||
Title: Subteam 3
|
||||
|
||||
|
@ -457,7 +457,7 @@ class MemberTest extends FunctionalTest {
|
||||
$this->session()->inst_set('loggedInAs', null);
|
||||
}
|
||||
|
||||
public function testDecoratedCan() {
|
||||
public function testExtendedCan() {
|
||||
$extensions = $this->removeExtensions(Object::get_extensions('Member'));
|
||||
$member = $this->objFromFixture('Member', 'test');
|
||||
|
||||
@ -466,7 +466,7 @@ class MemberTest extends FunctionalTest {
|
||||
$this->assertFalse($member->canDelete());
|
||||
$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');
|
||||
$member2 = $this->objFromFixture('Member', 'staffmember');
|
||||
|
||||
@ -474,7 +474,7 @@ class MemberTest extends FunctionalTest {
|
||||
$this->assertFalse($member2->canDelete());
|
||||
$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::add_extension('Member', 'MemberTest_ViewingDeniedExtension');
|
||||
$member3 = $this->objFromFixture('Member', 'managementmember');
|
||||
@ -483,7 +483,7 @@ class MemberTest extends FunctionalTest {
|
||||
$this->assertFalse($member3->canDelete());
|
||||
$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::add_extension('Member', 'MemberTest_EditingAllowedDeletingDeniedExtension');
|
||||
$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() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
class MemberTest_ViewingDeniedExtension extends DataObjectDecorator implements TestOnly {
|
||||
class MemberTest_ViewingDeniedExtension extends DataExtension implements TestOnly {
|
||||
|
||||
public function canView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
class MemberTest_EditingAllowedDeletingDeniedExtension extends DataObjectDecorator implements TestOnly {
|
||||
class MemberTest_EditingAllowedDeletingDeniedExtension extends DataExtension implements TestOnly {
|
||||
|
||||
public function canView() {
|
||||
return true;
|
||||
|
@ -2924,7 +2924,7 @@ class SSTemplateParser extends Parser {
|
||||
* '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
|
||||
* 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).
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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).
|
||||
*
|
||||
* 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