Merge pull request #6927 from open-sausages/pulls/4.0/remove-object

API Remove Object class
This commit is contained in:
Chris Joe 2017-05-23 15:15:01 +12:00 committed by GitHub
commit 44981de560
124 changed files with 993 additions and 980 deletions

View File

@ -56,6 +56,9 @@ before_script:
- phpenv config-rm xdebug.ini - phpenv config-rm xdebug.ini
- echo 'memory_limit = 2048M' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini - echo 'memory_limit = 2048M' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
# Temporarily update to 1.5.x-dev of composer
- composer self-update --snapshot
# Install composer dependencies # Install composer dependencies
- composer validate - composer validate
- composer install --prefer-dist - composer install --prefer-dist

View File

@ -30,6 +30,7 @@ guide developers in preparing existing 3.x code for compatibility with 4.0
arrangement of templates, as well as other references to classes via string literals or configuration. arrangement of templates, as well as other references to classes via string literals or configuration.
Automatic upgrading tools have been developed to cope with the bulk of these changes (see Automatic upgrading tools have been developed to cope with the bulk of these changes (see
[upgrading notes](#upgrading)). [upgrading notes](#upgrading)).
* Object class has been removed.
* Asset storage has been abstracted, and a new concept of `DBFile` references via database column references * Asset storage has been abstracted, and a new concept of `DBFile` references via database column references
now exists in addition to references via the existing `File` dataobject. File security and protected files now exists in addition to references via the existing `File` dataobject. File security and protected files
are now a core feature. are now a core feature.
@ -161,6 +162,90 @@ Note also that `$_FILE_TO_URL_MAPPING` has been removed and replaced with `SS_BA
See [Environment Management docs](/getting-started/environment_management/) for full details. See [Environment Management docs](/getting-started/environment_management/) for full details.
#### Replace usages of Object class
Object has been superseded by a trio of traits which replace components of this legacy class:
- Injectable: Provides `MyClass::create()` and `MyClass::singleton()`
- Configurable: Provides `MyClass::config()`
- Extensible: Provides all methods related to extensions (E.g. add_extension()). Note:
All classes which use this trait MUST invoke `constructExtensions()` in its constructor.
In particular specific Object class usages should be replaced as below:
Upgrade subclasses
:::php
// old
class MyClass extends Object {}
// new
class MyClass {
use Extensible;
use Injectable;
use Configurable;
public function __construct() {
// Only needed if using Extensible trait
$this->constructExtensions();
}
}
References to $this->class
:::php
// old
$obj->class
$this->class;
// new
get_class($obj);
static::class;
Upgrade parse_class_spec()
:::php
// old
$spec = Object::parse_class_spec($spec);
// new
$spec = ClassInfo::parse_class_spec($spec);
Upgrade create_from_string()
:::php
// old
$obj = Object::create_from_string('Varchar(100)');
// new
$obj = Injector::inst()->create('Varchar(100)');
Extensions
:::php
// old
Object::add_extension('File', 'Versioned');
$has = Object::has_extension('File', 'Versioned');
$extensions = Object::get_extensions('File');
// new
File::add_extension(Versioned::class);
$has = File::has_extension(Versioned::class)
$extensions = File::get_extensions();
// new (alternate form)
// Note: The class the extension method is called on MUST be a parent class
// of the first argument.
DataObject::add_extension(File::class, Versioned::class); // alternate
$has = DataObject::has_extension(File::class, Versioned::class); // alternate
$extensions = DataObject::get_extensions(File::class);
#### Compatibility with the new front-end building tools #### Compatibility with the new front-end building tools
If you are using Requirements from 3.x then your scripts should continue to work as they did before. If you are using Requirements from 3.x then your scripts should continue to work as they did before.
@ -1203,6 +1288,10 @@ After (`mysite/_config/config.yml`):
* Introduced new ModuleLoader manifest, which allows modules to be found via composer name. * Introduced new ModuleLoader manifest, which allows modules to be found via composer name.
E.g. `$cms = ModuleLoader::inst()->getManifest()->getModule('silverstripe/cms')` E.g. `$cms = ModuleLoader::inst()->getManifest()->getModule('silverstripe/cms')`
* `ClassManifest::getOwnerModule()` now returns a `Module` object instance. * `ClassManifest::getOwnerModule()` now returns a `Module` object instance.
* `Object` class has been removed.
* `parse_class_spec` moved to `ClassInfo`
* `create_from_spec` functionality removed, but now supportede by `Injector` natively.
* `Injectable`, `Extensible` and `Configurable` traits added to support other methods.
* Certain methods have been moved from `Controller` to `RequestHandler`: * Certain methods have been moved from `Controller` to `RequestHandler`:
* `Link` * `Link`
* `redirect` * `redirect`

View File

@ -32,7 +32,7 @@ abstract class CliController extends Controller
public function index() public function index()
{ {
foreach (ClassInfo::subclassesFor($this->class) as $subclass) { foreach (ClassInfo::subclassesFor(static::class) as $subclass) {
echo $subclass . "\n"; echo $subclass . "\n";
/** @var CliController $task */ /** @var CliController $task */
$task = Injector::inst()->create($subclass); $task = Injector::inst()->create($subclass);

View File

@ -3,7 +3,8 @@
namespace SilverStripe\Control; namespace SilverStripe\Control;
use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Object; use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Injector\Injectable;
/** /**
* The content negotiator performs "text/html" or "application/xhtml+xml" switching. It does this through * The content negotiator performs "text/html" or "application/xhtml+xml" switching. It does this through
@ -31,8 +32,10 @@ use SilverStripe\Core\Object;
* Some developers might know what they're doing and don't want ContentNegotiator messing with their * Some developers might know what they're doing and don't want ContentNegotiator messing with their
* HTML4 doctypes, but still find it useful to have self-closing tags removed. * HTML4 doctypes, but still find it useful to have self-closing tags removed.
*/ */
class ContentNegotiator extends Object class ContentNegotiator
{ {
use Injectable;
use Configurable;
/** /**
* @config * @config

View File

@ -3,7 +3,6 @@
namespace SilverStripe\Control; namespace SilverStripe\Control;
use SilverStripe\Core\ClassInfo; use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Object;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\Debug; use SilverStripe\Dev\Debug;
use SilverStripe\ORM\DataModel; use SilverStripe\ORM\DataModel;
@ -122,8 +121,9 @@ class Controller extends RequestHandler implements TemplateGlobalProvider
$this->baseInitCalled = false; $this->baseInitCalled = false;
$this->init(); $this->init();
if (!$this->baseInitCalled) { if (!$this->baseInitCalled) {
$class = static::class;
user_error( user_error(
"init() method on class '$this->class' doesn't call Controller::init()." "init() method on class '{$class}' doesn't call Controller::init()."
. "Make sure that you have parent::init() included.", . "Make sure that you have parent::init() included.",
E_USER_WARNING E_USER_WARNING
); );
@ -231,18 +231,22 @@ class Controller extends RequestHandler implements TemplateGlobalProvider
{ {
if ($response instanceof HTTPResponse) { if ($response instanceof HTTPResponse) {
if (isset($_REQUEST['debug_request'])) { if (isset($_REQUEST['debug_request'])) {
$class = static::class;
Debug::message( Debug::message(
"Request handler returned HTTPResponse object to $this->class controller;" "Request handler returned HTTPResponse object to {$class} controller;"
. "returning it without modification." . "returning it without modification."
); );
} }
$this->setResponse($response); $this->setResponse($response);
} else { } else {
if ($response instanceof Object && $response->hasMethod('getViewer')) { // Could be Controller, or ViewableData_Customised controller wrapper
if (ClassInfo::hasMethod($response, 'getViewer')) {
if (isset($_REQUEST['debug_request'])) { if (isset($_REQUEST['debug_request'])) {
$class = static::class;
$responseClass = get_class($response);
Debug::message( Debug::message(
"Request handler $response->class object to $this->class controller;" "Request handler {$responseClass} object to {$class} controller;"
. "rendering with template returned by $response->class::getViewer()" . "rendering with template returned by {$responseClass}::getViewer()"
); );
} }
$response = $response->getViewer($this->getAction())->process($response); $response = $response->getViewer($this->getAction())->process($response);
@ -396,26 +400,22 @@ class Controller extends RequestHandler implements TemplateGlobalProvider
} elseif ($this->template) { } elseif ($this->template) {
$templates = $this->template; $templates = $this->template;
} else { } else {
// Add action-specific templates for inheritance chain // Build templates based on class hierarchy
$templates = array(); $actionTemplates = [];
$classTemplates = [];
$parentClass = static::class;
while ($parentClass !== parent::class) {
// _action templates have higher priority
if ($action && $action != 'index') { if ($action && $action != 'index') {
$parentClass = $this->class; $actionTemplates[] = strtok($parentClass, '_') . '_' . $action;
while ($parentClass != __CLASS__) { }
$templates[] = strtok($parentClass, '_') . '_' . $action; // class templates have lower priority
$classTemplates[] = strtok($parentClass, '_');
$parentClass = get_parent_class($parentClass); $parentClass = get_parent_class($parentClass);
} }
}
// Add controller templates for inheritance chain // Add controller templates for inheritance chain
$parentClass = $this->class; $templates = array_unique(array_merge($actionTemplates, $classTemplates));
while ($parentClass != __CLASS__) {
$templates[] = strtok($parentClass, '_');
$parentClass = get_parent_class($parentClass);
}
$templates[] = __CLASS__;
// remove duplicates
$templates = array_unique($templates);
} }
return new SSViewer($templates); return new SSViewer($templates);
@ -469,7 +469,7 @@ class Controller extends RequestHandler implements TemplateGlobalProvider
return $definingClass; return $definingClass;
} }
$class = get_class($this); $class = static::class;
while ($class != 'SilverStripe\\Control\\RequestHandler') { while ($class != 'SilverStripe\\Control\\RequestHandler') {
$templateName = strtok($class, '_') . '_' . $action; $templateName = strtok($class, '_') . '_' . $action;
if (SSViewer::hasTemplate($templateName)) { if (SSViewer::hasTemplate($templateName)) {
@ -496,7 +496,7 @@ class Controller extends RequestHandler implements TemplateGlobalProvider
return true; return true;
} }
$parentClass = $this->class; $parentClass = static::class;
$templates = array(); $templates = array();
while ($parentClass != __CLASS__) { while ($parentClass != __CLASS__) {
@ -614,8 +614,9 @@ class Controller extends RequestHandler implements TemplateGlobalProvider
if ($this === self::$controller_stack[0]) { if ($this === self::$controller_stack[0]) {
array_shift(self::$controller_stack); array_shift(self::$controller_stack);
} else { } else {
$class = static::class;
user_error( user_error(
"popCurrent called on $this->class controller, but it wasn't at the top of the stack", "popCurrent called on {$class} controller, but it wasn't at the top of the stack",
E_USER_WARNING E_USER_WARNING
); );
} }

View File

@ -573,7 +573,8 @@ class Email extends ViewableData
{ {
$this->render(); $this->render();
return "<h2>Email template {$this->class}:</h2>\n" . '<pre>' . $this->getSwiftMessage()->toString() . '</pre>'; $class = static::class;
return "<h2>Email template {$class}:</h2>\n" . '<pre>' . $this->getSwiftMessage()->toString() . '</pre>';
} }
/** /**

View File

@ -272,7 +272,7 @@ class RSSFeed extends ViewableData
*/ */
public function getTemplates() public function getTemplates()
{ {
$templates = SSViewer::get_templates_by_class(get_class($this), '', __CLASS__); $templates = SSViewer::get_templates_by_class(static::class, '', __CLASS__);
// Prefer any custom template // Prefer any custom template
if ($this->getTemplate()) { if ($this->getTemplate()) {
array_unshift($templates, $this->getTemplate()); array_unshift($templates, $this->getTemplate());

View File

@ -130,7 +130,7 @@ class RSSFeed_Entry extends ViewableData
} }
throw new BadMethodCallException( throw new BadMethodCallException(
$this->failover->class . get_class($this->failover) .
" object has neither an AbsoluteLink nor a Link method." . " object has neither an AbsoluteLink nor a Link method." .
" Can't put a link in the RSS feed", " Can't put a link in the RSS feed",
E_USER_WARNING E_USER_WARNING

View File

@ -5,7 +5,6 @@ namespace SilverStripe\Control;
use InvalidArgumentException; use InvalidArgumentException;
use SilverStripe\Core\ClassInfo; use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Object;
use SilverStripe\Dev\Debug; use SilverStripe\Dev\Debug;
use SilverStripe\ORM\DataModel; use SilverStripe\ORM\DataModel;
use SilverStripe\Security\Security; use SilverStripe\Security\Security;
@ -164,7 +163,7 @@ class RequestHandler extends ViewableData
{ {
// $handlerClass is used to step up the class hierarchy to implement url_handlers inheritance // $handlerClass is used to step up the class hierarchy to implement url_handlers inheritance
if ($this->brokenOnConstruct) { if ($this->brokenOnConstruct) {
$handlerClass = get_class($this); $handlerClass = static::class;
throw new BadMethodCallException( throw new BadMethodCallException(
"parent::__construct() needs to be called on {$handlerClass}::__construct()" "parent::__construct() needs to be called on {$handlerClass}::__construct()"
); );
@ -205,7 +204,7 @@ class RequestHandler extends ViewableData
user_error("Non-string method name: " . var_export($action, true), E_USER_ERROR); user_error("Non-string method name: " . var_export($action, true), E_USER_ERROR);
} }
$classMessage = Director::isLive() ? 'on this handler' : 'on class '.get_class($this); $classMessage = Director::isLive() ? 'on this handler' : 'on class '.static::class;
try { try {
if (!$this->hasAction($action)) { if (!$this->hasAction($action)) {
@ -263,7 +262,7 @@ class RequestHandler extends ViewableData
*/ */
protected function findAction($request) protected function findAction($request)
{ {
$handlerClass = ($this->class) ? $this->class : get_class($this); $handlerClass = static::class;
// We stop after RequestHandler; in other words, at ViewableData // We stop after RequestHandler; in other words, at ViewableData
while ($handlerClass && $handlerClass != ViewableData::class) { while ($handlerClass && $handlerClass != ViewableData::class) {
@ -272,14 +271,18 @@ class RequestHandler extends ViewableData
if ($urlHandlers) { if ($urlHandlers) {
foreach ($urlHandlers as $rule => $action) { foreach ($urlHandlers as $rule => $action) {
if (isset($_REQUEST['debug_request'])) { if (isset($_REQUEST['debug_request'])) {
Debug::message("Testing '$rule' with '" . $request->remaining() . "' on $this->class"); $class = static::class;
$remaining = $request->remaining();
Debug::message("Testing '{$rule}' with '{$remaining}' on {$class}");
} }
if ($request->match($rule, true)) { if ($request->match($rule, true)) {
if (isset($_REQUEST['debug_request'])) { if (isset($_REQUEST['debug_request'])) {
$class = static::class;
$latestParams = var_export($request->latestParams(), true);
Debug::message( Debug::message(
"Rule '$rule' matched to action '$action' on $this->class. ". "Rule '{$rule}' matched to action '{$action}' on {$class}. ".
"Latest request params: " . var_export($request->latestParams(), true) "Latest request params: {$latestParams}"
); );
} }
@ -304,7 +307,7 @@ class RequestHandler extends ViewableData
*/ */
protected function handleAction($request, $action) protected function handleAction($request, $action)
{ {
$classMessage = Director::isLive() ? 'on this handler' : 'on class '.get_class($this); $classMessage = Director::isLive() ? 'on this handler' : 'on class '.static::class;
if (!$this->hasMethod($action)) { if (!$this->hasMethod($action)) {
return new HTTPResponse("Action '$action' isn't available $classMessage.", 404); return new HTTPResponse("Action '$action' isn't available $classMessage.", 404);
@ -469,7 +472,7 @@ class RequestHandler extends ViewableData
$isAllowed = true; $isAllowed = true;
} elseif (substr($test, 0, 2) == '->') { } elseif (substr($test, 0, 2) == '->') {
// Determined by custom method with "->" prefix // Determined by custom method with "->" prefix
list($method, $arguments) = Object::parse_class_spec(substr($test, 2)); list($method, $arguments) = ClassInfo::parse_class_spec(substr($test, 2));
$isAllowed = call_user_func_array(array($this, $method), $arguments); $isAllowed = call_user_func_array(array($this, $method), $arguments);
} else { } else {
// Value is a permission code to check the current member against // Value is a permission code to check the current member against
@ -564,7 +567,7 @@ class RequestHandler extends ViewableData
// no link defined by default // no link defined by default
trigger_error( trigger_error(
'Request handler '.get_class($this). ' does not have a url_segment defined. '. 'Request handler '.static::class. ' does not have a url_segment defined. '.
'Relying on this link may be an application error', 'Relying on this link may be an application error',
E_USER_WARNING E_USER_WARNING
); );

View File

@ -2,6 +2,7 @@
namespace SilverStripe\Core; namespace SilverStripe\Core;
use Exception;
use SilverStripe\Control\Director; use SilverStripe\Control\Director;
use SilverStripe\Core\Manifest\ClassLoader; use SilverStripe\Core\Manifest\ClassLoader;
use SilverStripe\Dev\Deprecation; use SilverStripe\Dev\Deprecation;
@ -43,14 +44,26 @@ class ClassInfo
/** /**
* Cache for {@link hasTable()} * Cache for {@link hasTable()}
*
* @internal
* @var array
*/ */
private static $_cache_all_tables = array(); private static $_cache_all_tables = array();
/** /**
* @internal
* @var array Cache for {@link ancestry()}. * @var array Cache for {@link ancestry()}.
*/ */
private static $_cache_ancestry = array(); private static $_cache_ancestry = array();
/**
* Cache for parse_class_spec
*
* @internal
* @var array
*/
private static $_cache_parse = [];
/** /**
* @todo Move this to SS_Database or DB * @todo Move this to SS_Database or DB
* *
@ -358,4 +371,148 @@ class ClassInfo
} }
return method_exists($object, 'hasMethod') && $object->hasMethod($method); return method_exists($object, 'hasMethod') && $object->hasMethod($method);
} }
/**
* Parses a class-spec, such as "Versioned('Stage','Live')", as passed to create_from_string().
* Returns a 2-element array, with classname and arguments
*
* @param string $classSpec
* @return array
* @throws Exception
*/
public static function parse_class_spec($classSpec)
{
if (isset(static::$_cache_parse[$classSpec])) {
return static::$_cache_parse[$classSpec];
}
$tokens = token_get_all("<?php $classSpec");
$class = null;
$args = array();
// Keep track of the current bucket that we're putting data into
$bucket = &$args;
$bucketStack = array();
$hadNamespace = false;
$currentKey = null;
foreach ($tokens as $token) {
// $forceResult used to allow null result to be detected
$result = $forceResult = null;
$tokenName = is_array($token) ? $token[0] : $token;
// Get the class name
if ($class === null && is_array($token) && $token[0] === T_STRING) {
$class = $token[1];
} elseif (is_array($token) && $token[0] === T_NS_SEPARATOR) {
$class .= $token[1];
$hadNamespace = true;
} elseif ($hadNamespace && is_array($token) && $token[0] === T_STRING) {
$class .= $token[1];
$hadNamespace = false;
// Get arguments
} elseif (is_array($token)) {
switch ($token[0]) {
case T_CONSTANT_ENCAPSED_STRING:
$argString = $token[1];
switch ($argString[0]) {
case '"':
$result = stripcslashes(substr($argString, 1, -1));
break;
case "'":
$result = str_replace(array("\\\\", "\\'"), array("\\", "'"), substr($argString, 1, -1));
break;
default:
throw new Exception("Bad T_CONSTANT_ENCAPSED_STRING arg $argString");
}
break;
case T_DNUMBER:
$result = (double)$token[1];
break;
case T_LNUMBER:
$result = (int)$token[1];
break;
case T_DOUBLE_ARROW:
// We've encountered an associative array (the array itself has already been
// added to the bucket), so the previous item added to the bucket is the key
end($bucket);
$currentKey = current($bucket);
array_pop($bucket);
break;
case T_STRING:
switch ($token[1]) {
case 'true':
$result = true;
break;
case 'false':
$result = false;
break;
case 'null':
$result = null;
$forceResult = true;
break;
default:
throw new Exception("Bad T_STRING arg '{$token[1]}'");
}
break;
case T_ARRAY:
$result = array();
break;
}
} else {
if ($tokenName === '[') {
$result = array();
} elseif (($tokenName === ')' || $tokenName === ']') && ! empty($bucketStack)) {
// Store the bucket we're currently working on
$oldBucket = $bucket;
// Fetch the key for the bucket at the top of the stack
end($bucketStack);
$key = key($bucketStack);
reset($bucketStack);
// Re-instate the bucket from the top of the stack
$bucket = &$bucketStack[$key];
// Add our saved, "nested" bucket to the bucket we just popped off the stack
$bucket[$key] = $oldBucket;
// Remove the bucket we just popped off the stack
array_pop($bucketStack);
}
}
// If we've got something to add to the bucket, add it
if ($result !== null || $forceResult) {
if ($currentKey) {
$bucket[$currentKey] = $result;
$currentKey = null;
} else {
$bucket[] = $result;
}
// If we've just pushed an array, that becomes our new bucket
if ($result === array()) {
// Fetch the key that the array was pushed to
end($bucket);
$key = key($bucket);
reset($bucket);
// Store reference to "old" bucket in the stack
$bucketStack[$key] = &$bucket;
// Set the active bucket to be our newly-pushed, empty array
$bucket = &$bucket[$key];
}
}
}
$result = [$class, $args];
static::$_cache_parse[$classSpec] = $result;
return $result;
}
} }

View File

@ -8,7 +8,6 @@ use SilverStripe\Config\MergeStrategy\Priority;
use SilverStripe\Config\Middleware\Middleware; use SilverStripe\Config\Middleware\Middleware;
use SilverStripe\Core\ClassInfo; use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Object;
class ExtensionMiddleware implements Middleware class ExtensionMiddleware implements Middleware
{ {
@ -52,7 +51,7 @@ class ExtensionMiddleware implements Middleware
$extensions = $classConfig['extensions']; $extensions = $classConfig['extensions'];
foreach ($extensions as $extension) { foreach ($extensions as $extension) {
list($extensionClass, $extensionArgs) = Object::parse_class_spec($extension); list($extensionClass, $extensionArgs) = ClassInfo::parse_class_spec($extension);
if (!class_exists($extensionClass)) { if (!class_exists($extensionClass)) {
throw new InvalidArgumentException("$class references nonexistent $extensionClass in 'extensions'"); throw new InvalidArgumentException("$class references nonexistent $extensionClass in 'extensions'");
} }

View File

@ -47,7 +47,7 @@ trait CustomMethods
{ {
// If the method cache was cleared by an an Object::add_extension() / Object::remove_extension() // If the method cache was cleared by an an Object::add_extension() / Object::remove_extension()
// call, then we should rebuild it. // call, then we should rebuild it.
$class = get_class($this); $class = static::class;
if (!array_key_exists($class, self::$extra_methods)) { if (!array_key_exists($class, self::$extra_methods)) {
$this->defineMethods(); $this->defineMethods();
} }
@ -151,12 +151,12 @@ trait CustomMethods
/** /**
* Get meta-data details on a named method * Get meta-data details on a named method
* *
* @param array $method * @param string $method
* @return array List of custom method details, if defined for this method * @return array List of custom method details, if defined for this method
*/ */
protected function getExtraMethodConfig($method) protected function getExtraMethodConfig($method)
{ {
$class = get_class($this); $class = static::class;
if (isset(self::$extra_methods[$class][strtolower($method)])) { if (isset(self::$extra_methods[$class][strtolower($method)])) {
return self::$extra_methods[$class][strtolower($method)]; return self::$extra_methods[$class][strtolower($method)];
} }
@ -171,7 +171,7 @@ trait CustomMethods
*/ */
public function allMethodNames($custom = false) public function allMethodNames($custom = false)
{ {
$class = get_class($this); $class = static::class;
if (!isset(self::$built_in_methods[$class])) { if (!isset(self::$built_in_methods[$class])) {
self::$built_in_methods[$class] = array_map('strtolower', get_class_methods($this)); self::$built_in_methods[$class] = array_map('strtolower', get_class_methods($this));
} }
@ -198,10 +198,11 @@ trait CustomMethods
$extension->clearOwner(); $extension->clearOwner();
} }
} else { } else {
if (!isset(self::$built_in_methods[$extension->class])) { $class = get_class($extension);
self::$built_in_methods[$extension->class] = array_map('strtolower', get_class_methods($extension)); if (!isset(self::$built_in_methods[$class])) {
self::$built_in_methods[$class] = array_map('strtolower', get_class_methods($extension));
} }
$methods = self::$built_in_methods[$extension->class]; $methods = self::$built_in_methods[$class];
} }
return $methods; return $methods;
@ -216,7 +217,7 @@ trait CustomMethods
*/ */
protected function addMethodsFrom($property, $index = null) protected function addMethodsFrom($property, $index = null)
{ {
$class = get_class($this); $class = static::class;
$extension = ($index !== null) ? $this->{$property}[$index] : $this->$property; $extension = ($index !== null) ? $this->{$property}[$index] : $this->$property;
if (!$extension) { if (!$extension) {
@ -253,7 +254,7 @@ trait CustomMethods
protected function removeMethodsFrom($property, $index = null) protected function removeMethodsFrom($property, $index = null)
{ {
$extension = ($index !== null) ? $this->{$property}[$index] : $this->$property; $extension = ($index !== null) ? $this->{$property}[$index] : $this->$property;
$class = get_class($this); $class = static::class;
if (!$extension) { if (!$extension) {
throw new InvalidArgumentException( throw new InvalidArgumentException(
@ -286,7 +287,7 @@ trait CustomMethods
*/ */
protected function addWrapperMethod($method, $wrap) protected function addWrapperMethod($method, $wrap)
{ {
$class = get_class($this); $class = static::class;
self::$extra_methods[$class][strtolower($method)] = array ( self::$extra_methods[$class][strtolower($method)] = array (
'wrap' => $wrap, 'wrap' => $wrap,
'method' => $method 'method' => $method

View File

@ -3,8 +3,10 @@
namespace SilverStripe\Core; namespace SilverStripe\Core;
use InvalidArgumentException; use InvalidArgumentException;
use SilverStripe\Control\RequestHandler;
use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use SilverStripe\View\ViewableData;
/** /**
* Allows an object to have extensions applied to it. * Allows an object to have extensions applied to it.
@ -46,9 +48,8 @@ trait Extensible
* @var array * @var array
*/ */
private static $unextendable_classes = array( private static $unextendable_classes = array(
'SilverStripe\\Core\\Object', ViewableData::class,
'SilverStripe\\View\\ViewableData', RequestHandler::class,
'SilverStripe\\Control\\RequestHandler'
); );
/** /**
@ -110,7 +111,7 @@ trait Extensible
protected function constructExtensions() protected function constructExtensions()
{ {
$class = get_class($this); $class = static::class;
// Register this trait as a method source // Register this trait as a method source
$this->registerExtraMethodCallback('defineExtensionMethods', function () { $this->registerExtraMethodCallback('defineExtensionMethods', function () {
@ -126,9 +127,9 @@ trait Extensible
if ($extensions) { if ($extensions) {
foreach ($extensions as $extension) { foreach ($extensions as $extension) {
$instance = Object::create_from_string($extension); $instance = Injector::inst()->create($extension);
$instance->setOwner(null, $class); $instance->setOwner(null, $class);
$this->extension_instances[$instance->class] = $instance; $this->extension_instances[get_class($instance)] = $instance;
} }
} }
} }
@ -177,7 +178,7 @@ trait Extensible
*/ */
public static function add_extension($classOrExtension, $extension = null) public static function add_extension($classOrExtension, $extension = null)
{ {
if (func_num_args() > 1) { if ($extension) {
$class = $classOrExtension; $class = $classOrExtension;
} else { } else {
$class = get_called_class(); $class = get_called_class();
@ -285,14 +286,18 @@ trait Extensible
} }
/** /**
* @param string $class * @param string $class If omitted, will get extensions for the current 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 DataExtension} class names, * @return array Numeric array of either {@link DataExtension} class names,
* or eval'ed class name strings with constructor arguments. * or eval'ed class name strings with constructor arguments.
*/ */
public static function get_extensions($class, $includeArgumentString = false) public static function get_extensions($class = null, $includeArgumentString = false)
{ {
if (!$class) {
$class = get_called_class();
}
$extensions = Config::forClass($class)->get('extensions', Config::EXCLUDE_EXTRA_SOURCES); $extensions = Config::forClass($class)->get('extensions', Config::EXCLUDE_EXTRA_SOURCES);
if (empty($extensions)) { if (empty($extensions)) {
return array(); return array();
@ -315,9 +320,15 @@ trait Extensible
} }
/**
* Get extra config sources for this class
*
* @param string $class Name of class. If left null will return for the current class
* @return array|null
*/
public static function get_extra_config_sources($class = null) public static function get_extra_config_sources($class = null)
{ {
if ($class === null) { if (!$class) {
$class = get_called_class(); $class = get_called_class();
} }
@ -340,7 +351,7 @@ trait Extensible
$sources = array(); $sources = array();
foreach ($extensions as $extension) { foreach ($extensions as $extension) {
list($extensionClass, $extensionArgs) = Object::parse_class_spec($extension); list($extensionClass, $extensionArgs) = ClassInfo::parse_class_spec($extension);
$sources[] = $extensionClass; $sources[] = $extensionClass;
if (!class_exists($extensionClass)) { if (!class_exists($extensionClass)) {
@ -367,16 +378,16 @@ trait Extensible
* Return TRUE if a class has a specified extension. * Return TRUE if a class has a specified extension.
* This supports backwards-compatible format (static Object::has_extension($requiredExtension)) * This supports backwards-compatible format (static Object::has_extension($requiredExtension))
* and new format ($object->has_extension($class, $requiredExtension)) * and new format ($object->has_extension($class, $requiredExtension))
* @param string $classOrExtension if 1 argument supplied, the class name of the extension to * @param string $classOrExtension Class to check extension for, or the extension name to check
* check for; if 2 supplied, the class name to test * if the second argument is null.
* @param string $requiredExtension used only if 2 arguments supplied * @param string $requiredExtension If the first argument is the parent class, this is the extension to check.
* If left null, the first parameter will be treated as the extension.
* @param boolean $strict if the extension has to match the required extension and not be a subclass * @param boolean $strict if the extension has to match the required extension and not be a subclass
* @return bool Flag if the extension exists * @return bool Flag if the extension exists
*/ */
public static function has_extension($classOrExtension, $requiredExtension = null, $strict = false) public static function has_extension($classOrExtension, $requiredExtension = null, $strict = false)
{ {
//BC support if ($requiredExtension) {
if (func_num_args() > 1) {
$class = $classOrExtension; $class = $classOrExtension;
} else { } else {
$class = get_called_class(); $class = get_called_class();
@ -500,6 +511,7 @@ trait Extensible
if ($this->hasExtension($extension)) { if ($this->hasExtension($extension)) {
return $this->extension_instances[$extension]; return $this->extension_instances[$extension];
} }
return null;
} }
/** /**

View File

@ -16,7 +16,6 @@ use SilverStripe\ORM\DataObject;
*/ */
abstract class Extension abstract class Extension
{ {
/** /**
* This is used by extensions designed to be applied to controllers. * This is used by extensions designed to be applied to controllers.
* It works the same way as {@link Controller::$allowed_actions}. * It works the same way as {@link Controller::$allowed_actions}.
@ -45,13 +44,6 @@ abstract class Extension
*/ */
private $ownerStack = []; private $ownerStack = [];
public $class;
public function __construct()
{
$this->class = get_class($this);
}
/** /**
* Called when this extension is added to a particular class * Called when this extension is added to a particular class
* *
@ -67,7 +59,7 @@ abstract class Extension
/** /**
* Set the owner of this extension. * 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,
* and then a Page object was instantiated, $owner would be a Page object, but $ownerBaseClass * and then a Page object was instantiated, $owner would be a Page object, but $ownerBaseClass

View File

@ -20,22 +20,13 @@ trait Injectable
* $list = DataList::create('SiteTree'); * $list = DataList::create('SiteTree');
* $list = SiteTree::get(); * $list = SiteTree::get();
* *
* @param string $classOrArgument The first argument, or class name (if called directly * @param array $args
* on Object).
* @param mixed $argument,... arguments to pass to the constructor
* @return static * @return static
*/ */
public static function create($classOrArgument = null, $argument = null) public static function create(...$args)
{ {
$args = func_get_args(); // Class to create should be the calling class
// Class to create should be the calling class if not Object,
// otherwise the first parameter
$class = get_called_class(); $class = get_called_class();
if ($class == 'SilverStripe\\Core\\Object') {
$class = array_shift($args);
}
return Injector::inst()->createWithArgs($class, $args); return Injector::inst()->createWithArgs($class, $args);
} }

View File

@ -3,6 +3,7 @@
namespace SilverStripe\Core\Injector; namespace SilverStripe\Core\Injector;
use Psr\Container\NotFoundExceptionInterface; use Psr\Container\NotFoundExceptionInterface;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Config;
use ReflectionProperty; use ReflectionProperty;
use ArrayObject; use ArrayObject;
@ -902,7 +903,7 @@ class Injector implements ContainerInterface
* if this object is to be created from scratch (with $asSingleton = false) * if this object is to be created from scratch (with $asSingleton = false)
* @return mixed Instance of the specified object * @return mixed Instance of the specified object
*/ */
public function get($name, $asSingleton = true, $constructorArgs = null) public function get($name, $asSingleton = true, $constructorArgs = [])
{ {
$object = $this->getNamedService($name, $asSingleton, $constructorArgs); $object = $this->getNamedService($name, $asSingleton, $constructorArgs);
@ -921,8 +922,11 @@ class Injector implements ContainerInterface
* @param array $constructorArgs * @param array $constructorArgs
* @return mixed|null Instance of the specified object (if it exists) * @return mixed|null Instance of the specified object (if it exists)
*/ */
protected function getNamedService($name, $asSingleton = true, $constructorArgs = null) protected function getNamedService($name, $asSingleton = true, $constructorArgs = [])
{ {
// Normalise service / args
list($name, $constructorArgs) = $this->normaliseArguments($name, $constructorArgs);
// reassign the name as it might actually be a compound name // reassign the name as it might actually be a compound name
if ($serviceName = $this->getServiceName($name)) { if ($serviceName = $this->getServiceName($name)) {
// check to see what the type of bean is. If it's a prototype, // check to see what the type of bean is. If it's a prototype,
@ -974,6 +978,28 @@ class Injector implements ContainerInterface
return $this->instantiate($spec); return $this->instantiate($spec);
} }
/**
* Detect service references with constructor arguments included.
* These will be split out of the service name reference and appended
* to the $args
*
* @param string $name
* @param array $args
* @return array Two items with name and new args
*/
protected function normaliseArguments($name, $args = [])
{
if (strstr($name, '(')) {
list($name, $extraArgs) = ClassInfo::parse_class_spec($name);
if ($args) {
$args = array_merge($args, $extraArgs);
} else {
$args = $extraArgs;
}
}
return [ $name, $args ];
}
/** /**
* Magic method to return an item directly * Magic method to return an item directly
* *
@ -999,7 +1025,7 @@ class Injector implements ContainerInterface
{ {
$constructorArgs = func_get_args(); $constructorArgs = func_get_args();
array_shift($constructorArgs); array_shift($constructorArgs);
return $this->get($name, false, count($constructorArgs) ? $constructorArgs : null); return $this->createWithArgs($name, $constructorArgs);
} }
/** /**

View File

@ -1,324 +0,0 @@
<?php
namespace SilverStripe\Core;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Core\Config\Configurable;
use Exception;
use ReflectionClass;
/**
* A base class for all SilverStripe objects to inherit from.
*
* This class provides a number of pattern implementations, as well as methods and fixes to add extra psuedo-static
* and method functionality to PHP.
*
* See {@link Extension} on how to implement a custom multiple
* inheritance for object instances based on PHP5 method call overloading.
*
* @todo Create instance-specific removeExtension() which removes an extension from $extension_instances,
* but not from static $extensions, and clears everything added through defineMethods(), mainly $extra_methods.
*/
abstract class Object
{
use Extensible;
use Injectable;
use Configurable;
/**
* @var string the class name
*/
public $class;
private static $_cache_inst_args = array();
/**
* Create an object from a string representation. It treats it as a PHP constructor without the
* 'new' keyword. It also manages to construct the object without the use of eval().
*
* Construction itself is done with Object::create(), so that Object::useCustomClass() calls
* are respected.
*
* `Object::create_from_string("Versioned('Stage','Live')")` will return the result of
* `Versioned::create('Stage', 'Live);`
*
* It is designed for simple, cloneable objects. The first time this method is called for a given
* string it is cached, and clones of that object are returned.
*
* If you pass the $firstArg argument, this will be prepended to the constructor arguments. It's
* impossible to pass null as the firstArg argument.
*
* `Object::create_from_string("Varchar(50)", "MyField")` will return the result of
* `Varchar::create('MyField', '50');`
*
* Arguments are always strings, although this is a quirk of the current implementation rather
* than something that can be relied upon.
*
* @param string $classSpec
* @param mixed $firstArg
* @return object
*/
public static function create_from_string($classSpec, $firstArg = null)
{
if (!isset(self::$_cache_inst_args[$classSpec.$firstArg])) {
// an $extension value can contain parameters as a string,
// e.g. "Versioned('Stage','Live')"
if (strpos($classSpec, '(') === false) {
if ($firstArg === null) {
self::$_cache_inst_args[$classSpec.$firstArg] = Object::create($classSpec);
} else {
self::$_cache_inst_args[$classSpec.$firstArg] = Object::create($classSpec, $firstArg);
}
} else {
list($class, $args) = self::parse_class_spec($classSpec);
if ($firstArg !== null) {
array_unshift($args, $firstArg);
}
array_unshift($args, $class);
self::$_cache_inst_args[$classSpec.$firstArg] = call_user_func_array(array('SilverStripe\\Core\\Object','create'), $args);
}
}
return clone self::$_cache_inst_args[$classSpec.$firstArg];
}
/**
* Parses a class-spec, such as "Versioned('Stage','Live')", as passed to create_from_string().
* Returns a 2-element array, with classname and arguments
*
* @param string $classSpec
* @return array
* @throws Exception
*/
public static function parse_class_spec($classSpec)
{
$tokens = token_get_all("<?php $classSpec");
$class = null;
$args = array();
// Keep track of the current bucket that we're putting data into
$bucket = &$args;
$bucketStack = array();
$hadNamespace = false;
$currentKey = null;
foreach ($tokens as $token) {
// $forceResult used to allow null result to be detected
$result = $forceResult = null;
$tokenName = is_array($token) ? $token[0] : $token;
// Get the class name
if ($class === null && is_array($token) && $token[0] === T_STRING) {
$class = $token[1];
} elseif (is_array($token) && $token[0] === T_NS_SEPARATOR) {
$class .= $token[1];
$hadNamespace = true;
} elseif ($hadNamespace && is_array($token) && $token[0] === T_STRING) {
$class .= $token[1];
$hadNamespace = false;
// Get arguments
} elseif (is_array($token)) {
switch ($token[0]) {
case T_CONSTANT_ENCAPSED_STRING:
$argString = $token[1];
switch ($argString[0]) {
case '"':
$result = stripcslashes(substr($argString, 1, -1));
break;
case "'":
$result = str_replace(array("\\\\", "\\'"), array("\\", "'"), substr($argString, 1, -1));
break;
default:
throw new Exception("Bad T_CONSTANT_ENCAPSED_STRING arg $argString");
}
break;
case T_DNUMBER:
$result = (double)$token[1];
break;
case T_LNUMBER:
$result = (int)$token[1];
break;
case T_DOUBLE_ARROW:
// We've encountered an associative array (the array itself has already been
// added to the bucket), so the previous item added to the bucket is the key
end($bucket);
$currentKey = current($bucket);
array_pop($bucket);
break;
case T_STRING:
switch ($token[1]) {
case 'true':
$result = true;
break;
case 'false':
$result = false;
break;
case 'null':
$result = null;
$forceResult = true;
break;
default:
throw new Exception("Bad T_STRING arg '{$token[1]}'");
}
break;
case T_ARRAY:
$result = array();
break;
}
} else {
if ($tokenName === '[') {
$result = array();
} elseif (($tokenName === ')' || $tokenName === ']') && ! empty($bucketStack)) {
// Store the bucket we're currently working on
$oldBucket = $bucket;
// Fetch the key for the bucket at the top of the stack
end($bucketStack);
$key = key($bucketStack);
reset($bucketStack);
// Re-instate the bucket from the top of the stack
$bucket = &$bucketStack[$key];
// Add our saved, "nested" bucket to the bucket we just popped off the stack
$bucket[$key] = $oldBucket;
// Remove the bucket we just popped off the stack
array_pop($bucketStack);
}
}
// If we've got something to add to the bucket, add it
if ($result !== null || $forceResult) {
if ($currentKey) {
$bucket[$currentKey] = $result;
$currentKey = null;
} else {
$bucket[] = $result;
}
// If we've just pushed an array, that becomes our new bucket
if ($result === array()) {
// Fetch the key that the array was pushed to
end($bucket);
$key = key($bucket);
reset($bucket);
// Store reference to "old" bucket in the stack
$bucketStack[$key] = &$bucket;
// Set the active bucket to be our newly-pushed, empty array
$bucket = &$bucket[$key];
}
}
}
return array($class, $args);
}
/**
* Get the value of a static property of a class, even in that property is declared protected (but not private),
* without any inheritance, merging or parent lookup if it doesn't exist on the given class.
*
* @param string $class The class to get the static from
* @param string $name The property to get from the class
* @param mixed $default The value to return if property doesn't exist on class
* @return mixed The value of the static property $name on class $class,
* or $default if that property is not defined
*/
public static function static_lookup($class, $name, $default = null)
{
if (is_subclass_of($class, 'SilverStripe\\Core\\Object')) {
if (isset($class::$$name)) {
$parent = get_parent_class($class);
if (!$parent || !isset($parent::$$name) || $parent::$$name !== $class::$$name) {
return $class::$$name;
}
}
return $default;
} else {
// TODO: This gets set once, then not updated, so any changes to statics after this is called the first
// time for any class won't be exposed
static $static_properties = array();
if (!isset($static_properties[$class])) {
$reflection = new ReflectionClass($class);
$static_properties[$class] = $reflection->getStaticProperties();
}
if (isset($static_properties[$class][$name])) {
$value = $static_properties[$class][$name];
$parent = get_parent_class($class);
if (!$parent) {
return $value;
}
if (!isset($static_properties[$parent])) {
$reflection = new ReflectionClass($parent);
$static_properties[$parent] = $reflection->getStaticProperties();
}
if (!isset($static_properties[$parent][$name]) || $static_properties[$parent][$name] !== $value) {
return $value;
}
}
}
return $default;
}
public function __construct()
{
$this->class = get_class($this);
$this->constructExtensions();
}
// --------------------------------------------------------------------------------------------------------------
/**
* Return true if this object "exists" i.e. has a sensible value
*
* This method should be overriden in subclasses to provide more context about the classes state. For example, a
* {@link DataObject} class could return false when it is deleted from the database
*
* @return bool
*/
public function exists()
{
return true;
}
/**
* @return string this classes parent class
*/
public function parentClass()
{
return get_parent_class($this);
}
/**
* Check if this class is an instance of a specific class, or has that class as one of its parents
*
* @param string $class
* @return bool
*/
public function is_a($class)
{
return $this instanceof $class;
}
/**
* @return string the class name
*/
public function __toString()
{
return $this->class;
}
}

View File

@ -3,7 +3,9 @@
namespace SilverStripe\Dev; namespace SilverStripe\Dev;
use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPRequest;
use SilverStripe\Core\Object; use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Extensible;
use SilverStripe\Core\Injector\Injectable;
/** /**
* Interface for a generic build task. Does not support dependencies. This will simply * Interface for a generic build task. Does not support dependencies. This will simply
@ -12,8 +14,16 @@ use SilverStripe\Core\Object;
* To disable the task (in the case of potentially destructive updates or deletes), declare * To disable the task (in the case of potentially destructive updates or deletes), declare
* the $Disabled property on the subclass. * the $Disabled property on the subclass.
*/ */
abstract class BuildTask extends Object abstract class BuildTask
{ {
use Injectable;
use Configurable;
use Extensible;
public function __construct()
{
$this->constructExtensions();
}
/** /**
* Set a custom url segment (to follow dev/tasks/) * Set a custom url segment (to follow dev/tasks/)
@ -63,7 +73,7 @@ abstract class BuildTask extends Object
*/ */
public function getTitle() public function getTitle()
{ {
return ($this->title) ? $this->title : $this->class; return $this->title ?: static::class;
} }
/** /**

View File

@ -200,7 +200,8 @@ abstract class BulkLoader extends ViewableData
*/ */
public function Title() public function Title()
{ {
return ($title = $this->stat('title')) ? $title : $this->class; $title = $this->stat('title');
return $title ?: static::class;
} }
/** /**

View File

@ -2,7 +2,7 @@
namespace SilverStripe\Dev; namespace SilverStripe\Dev;
use SilverStripe\Core\Object; use SilverStripe\Core\Injector\Injectable;
use SilverStripe\ORM\ArrayList; use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
use SilverStripe\View\ArrayData; use SilverStripe\View\ArrayData;
@ -15,8 +15,9 @@ use SilverStripe\View\ArrayData;
* *
* @author Ingo Schommer, Silverstripe Ltd. (<firstname>@silverstripe.com) * @author Ingo Schommer, Silverstripe Ltd. (<firstname>@silverstripe.com)
*/ */
class BulkLoader_Result extends Object class BulkLoader_Result
{ {
use Injectable;
/** /**
* Stores a map of ID and ClassNames * Stores a map of ID and ClassNames
@ -139,7 +140,7 @@ class BulkLoader_Result extends Object
{ {
$this->created[] = $this->lastChange = array( $this->created[] = $this->lastChange = array(
'ID' => $obj->ID, 'ID' => $obj->ID,
'ClassName' => $obj->class, 'ClassName' => get_class($obj),
'Message' => $message 'Message' => $message
); );
$this->lastChange['ChangeType'] = 'created'; $this->lastChange['ChangeType'] = 'created';
@ -153,7 +154,7 @@ class BulkLoader_Result extends Object
{ {
$this->updated[] = $this->lastChange = array( $this->updated[] = $this->lastChange = array(
'ID' => $obj->ID, 'ID' => $obj->ID,
'ClassName' => $obj->class, 'ClassName' => get_class($obj),
'Message' => $message 'Message' => $message
); );
$this->lastChange['ChangeType'] = 'updated'; $this->lastChange['ChangeType'] = 'updated';

View File

@ -2,13 +2,11 @@
namespace SilverStripe\Dev; namespace SilverStripe\Dev;
use SilverStripe\Core\Object;
/** /**
* Class to facilitate command-line output. * Class to facilitate command-line output.
* Support less-trivial output stuff such as colours (on xterm-color) * Support less-trivial output stuff such as colours (on xterm-color)
*/ */
class CLI extends Object class CLI
{ {
/** /**
* Returns true if the current STDOUT supports the use of colour control codes. * Returns true if the current STDOUT supports the use of colour control codes.

View File

@ -2,7 +2,7 @@
namespace SilverStripe\Dev; namespace SilverStripe\Dev;
use SilverStripe\Core\Object; use SilverStripe\Core\Injector\Injectable;
use SimpleXMLElement; use SimpleXMLElement;
use tidy; use tidy;
use Exception; use Exception;
@ -22,8 +22,10 @@ use Exception;
* Caution: Doesn't fully support HTML elements like <header> * Caution: Doesn't fully support HTML elements like <header>
* due to them being declared illegal by the "tidy" preprocessing step. * due to them being declared illegal by the "tidy" preprocessing step.
*/ */
class CSSContentParser extends Object class CSSContentParser
{ {
use Injectable;
protected $simpleXML = null; protected $simpleXML = null;
public function __construct($content) public function __construct($content)
@ -59,8 +61,6 @@ class CSSContentParser extends Object
throw new Exception('CSSContentParser::__construct(): Could not parse content.' throw new Exception('CSSContentParser::__construct(): Could not parse content.'
. ' Please check the PHP extension tidy is installed.'); . ' Please check the PHP extension tidy is installed.');
} }
parent::__construct();
} }
/** /**

View File

@ -2,7 +2,7 @@
namespace SilverStripe\Dev; namespace SilverStripe\Dev;
use SilverStripe\Core\Object; use SilverStripe\Core\Injector\Injectable;
use Iterator; use Iterator;
use SilverStripe\Control\Director; use SilverStripe\Control\Director;
@ -31,8 +31,9 @@ use SilverStripe\Control\Director;
* } * }
* </code> * </code>
*/ */
class CSVParser extends Object implements Iterator class CSVParser implements Iterator
{ {
use Injectable;
/** /**
* @var string $filename * @var string $filename
@ -117,8 +118,6 @@ class CSVParser extends Object implements Iterator
$this->filename = $filename; $this->filename = $filename;
$this->delimiter = $delimiter; $this->delimiter = $delimiter;
$this->enclosure = $enclosure; $this->enclosure = $enclosure;
parent::__construct();
} }
/** /**

View File

@ -180,7 +180,7 @@ class CsvBulkLoader extends BulkLoader
*/ */
protected function processChunk($filepath, $preview = false) protected function processChunk($filepath, $preview = false)
{ {
$results = new BulkLoader_Result(); $results = BulkLoader_Result::create();
$csv = new CSVParser( $csv = new CSVParser(
$filepath, $filepath,

View File

@ -5,15 +5,18 @@ namespace SilverStripe\Dev;
use SilverStripe\Control\Controller; use SilverStripe\Control\Controller;
use SilverStripe\Control\Director; use SilverStripe\Control\Director;
use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPRequest;
use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\Core\Object; use SilverStripe\Core\Injector\Injectable;
/** /**
* A basic HTML wrapper for stylish rendering of a developement info view. * A basic HTML wrapper for stylish rendering of a developement info view.
* Used to output error messages, and test results. * Used to output error messages, and test results.
*/ */
class DebugView extends Object class DebugView
{ {
use Configurable;
use Injectable;
/** /**
* Column size to wrap long strings to * Column size to wrap long strings to

View File

@ -2,6 +2,7 @@
namespace SilverStripe\Dev; namespace SilverStripe\Dev;
use SilverStripe\Assets\File;
use SilverStripe\ORM\DataModel; use SilverStripe\ORM\DataModel;
use SilverStripe\ORM\DB; use SilverStripe\ORM\DB;
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
@ -85,8 +86,8 @@ class FixtureBlueprint
// which they are imported doesnt guarantee valid relations until after the import is complete. // which they are imported doesnt guarantee valid relations until after the import is complete.
// Also disable filesystem manipulations // Also disable filesystem manipulations
Config::nest(); Config::nest();
Config::inst()->update('SilverStripe\\ORM\\DataObject', 'validation_enabled', false); Config::modify()->set(DataObject::class, 'validation_enabled', false);
Config::inst()->update('SilverStripe\\Assets\\File', 'update_filesystem', false); Config::modify()->set(File::class, 'update_filesystem', false);
$this->invokeCallbacks('beforeCreate', array($identifier, &$data, &$fixtures)); $this->invokeCallbacks('beforeCreate', array($identifier, &$data, &$fixtures));

View File

@ -83,8 +83,8 @@ class FunctionalTest extends SapphireTest
protected function setUp() protected function setUp()
{ {
// Skip calling FunctionalTest directly. // Skip calling FunctionalTest directly.
if (get_class($this) == __CLASS__) { if (static::class == __CLASS__) {
$this->markTestSkipped(sprintf('Skipping %s ', get_class($this))); $this->markTestSkipped(sprintf('Skipping %s ', static::class));
} }
parent::setUp(); parent::setUp();

View File

@ -111,13 +111,14 @@ class SapphireTest extends PHPUnit_Framework_TestCase
*/ */
protected $requireDefaultRecordsFrom = array(); protected $requireDefaultRecordsFrom = array();
/** /**
* A list of extensions that can't be applied during the execution of this run. If they are * A list of extensions that can't be applied during the execution of this run. If they are
* applied, they will be temporarily removed and a database migration called. * applied, they will be temporarily removed and a database migration called.
* *
* The keys of the are the classes that the extensions can't be applied the extensions to, and * The keys of the are the classes that the extensions can't be applied the extensions to, and
* the values are an array of illegal extensions on that class. * the values are an array of illegal extensions on that class.
*
* Set a class to `*` to remove all extensions (unadvised)
*/ */
protected static $illegal_extensions = []; protected static $illegal_extensions = [];
@ -242,8 +243,8 @@ class SapphireTest extends PHPUnit_Framework_TestCase
} }
// We cannot run the tests on this abstract class. // We cannot run the tests on this abstract class.
if (get_class($this) == __CLASS__) { if (static::class == __CLASS__) {
$this->markTestSkipped(sprintf('Skipping %s ', get_class($this))); $this->markTestSkipped(sprintf('Skipping %s ', static::class));
return; return;
} }
@ -357,6 +358,9 @@ class SapphireTest extends PHPUnit_Framework_TestCase
if (!class_exists($class)) { if (!class_exists($class)) {
continue; continue;
} }
if ($extensions === '*') {
$extensions = $class::get_extensions();
}
foreach ($extensions as $extension) { foreach ($extensions as $extension) {
if (!class_exists($extension) || !$class::has_extension($extension)) { if (!class_exists($extension) || !$class::has_extension($extension)) {
continue; continue;
@ -559,9 +563,9 @@ class SapphireTest extends PHPUnit_Framework_TestCase
*/ */
protected function getCurrentAbsolutePath() protected function getCurrentAbsolutePath()
{ {
$filename = self::$test_class_manifest->getItemPath(get_class($this)); $filename = self::$test_class_manifest->getItemPath(static::class);
if (!$filename) { if (!$filename) {
throw new LogicException("getItemPath returned null for " . get_class($this)); throw new LogicException("getItemPath returned null for " . static::class);
} }
return dirname($filename); return dirname($filename);
} }

View File

@ -4,7 +4,7 @@ namespace SilverStripe\Dev;
use SilverStripe\Control\Director; use SilverStripe\Control\Director;
use SilverStripe\Core\ClassInfo; use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Object; use SilverStripe\Core\Injector\Injectable;
use Symfony\Component\Yaml\Parser; use Symfony\Component\Yaml\Parser;
use InvalidArgumentException; use InvalidArgumentException;
@ -68,8 +68,9 @@ use InvalidArgumentException;
* ErrorCode: 404 * ErrorCode: 404
* </code> * </code>
*/ */
class YamlFixture extends Object class YamlFixture
{ {
use Injectable;
/** /**
* Absolute path to the .yml fixture file * Absolute path to the .yml fixture file
@ -104,8 +105,6 @@ class YamlFixture extends Object
$this->fixtureFile = $fixture; $this->fixtureFile = $fixture;
} }
parent::__construct();
} }
/** /**

View File

@ -246,9 +246,14 @@ class CompositeField extends FormField
if ($name) { if ($name) {
$formName = (isset($this->form)) ? $this->form->FormName() : '(unknown form)'; $formName = (isset($this->form)) ? $this->form->FormName() : '(unknown form)';
if (isset($list[$name])) { if (isset($list[$name])) {
user_error("collateDataFields() I noticed that a field called '$name' appears twice in" $fieldClass = get_class($field);
. " your form: '{$formName}'. One is a '{$field->class}' and the other is a" $otherFieldClass = get_class($list[$name]);
. " '{$list[$name]->class}'", E_USER_ERROR); user_error(
"collateDataFields() I noticed that a field called '$name' appears twice in"
. " your form: '{$formName}'. One is a '{$fieldClass}' and the other is a"
. " '{$otherFieldClass}'",
E_USER_ERROR
);
} }
$list[$name] = $field; $list[$name] = $field;
} }
@ -509,7 +514,8 @@ class CompositeField extends FormField
public function debug() public function debug()
{ {
$result = "$this->class ($this->name) <ul>"; $class = static::class;
$result = "$class ($this->name) <ul>";
foreach ($this->children as $child) { foreach ($this->children as $child) {
$result .= "<li>" . Debug::text($child) . "&nbsp;</li>"; $result .= "<li>" . Debug::text($child) . "&nbsp;</li>";
} }

View File

@ -347,8 +347,12 @@ class FieldList extends ArrayList
$withName = $parentPointer instanceof FormField $withName = $parentPointer instanceof FormField
? " named '{$parentPointer->getName()}'" ? " named '{$parentPointer->getName()}'"
: null; : null;
user_error("FieldList::addFieldToTab() Tried to add a tab to object" $parentPointerClass = get_class($parentPointer);
. " '{$parentPointer->class}'{$withName} - '$part' didn't exist.", E_USER_ERROR); user_error(
"FieldList::addFieldToTab() Tried to add a tab to object"
. " '{$parentPointerClass}'{$withName} - '{$part}' didn't exist.",
E_USER_ERROR
);
} }
} }
} }
@ -379,8 +383,9 @@ class FieldList extends ArrayList
if ($child instanceof CompositeField) { if ($child instanceof CompositeField) {
return $child->fieldByName($remainder); return $child->fieldByName($remainder);
} else { } else {
$childClass = get_class($child);
user_error( user_error(
"Trying to get field '$remainder' from non-composite field $child->class.$name", "Trying to get field '{$remainder}' from non-composite field {$childClass}.{$name}",
E_USER_WARNING E_USER_WARNING
); );
return null; return null;

View File

@ -2,10 +2,10 @@
namespace SilverStripe\Forms; namespace SilverStripe\Forms;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DataObjectInterface; use SilverStripe\ORM\DataObjectInterface;
use SilverStripe\Assets\File; use SilverStripe\Assets\File;
use SilverStripe\Core\Object;
/** /**
* Represents a file type which can be added to a form. * Represents a file type which can be added to a form.
@ -104,15 +104,15 @@ class FileField extends FormField implements FileHandleField
$objectClass = DataObject::getSchema()->hasOneComponent(get_class($record), $this->name); $objectClass = DataObject::getSchema()->hasOneComponent(get_class($record), $this->name);
if ($objectClass === File::class || empty($objectClass)) { if ($objectClass === File::class || empty($objectClass)) {
// Create object of the appropriate file class // Create object of the appropriate file class
$file = Object::create($fileClass); $file = Injector::inst()->create($fileClass);
} else { } else {
// try to create a file matching the relation // try to create a file matching the relation
$file = Object::create($objectClass); $file = Injector::inst()->create($objectClass);
} }
} elseif ($record instanceof File) { } elseif ($record instanceof File) {
$file = $record; $file = $record;
} else { } else {
$file = Object::create($fileClass); $file = Injector::inst()->create($fileClass);
} }
$this->upload->loadIntoFile($_FILES[$this->name], $file, $this->getFolderName()); $this->upload->loadIntoFile($_FILES[$this->name], $file, $this->getFolderName());

View File

@ -6,7 +6,7 @@ use Exception;
use InvalidArgumentException; use InvalidArgumentException;
use SilverStripe\Assets\File; use SilverStripe\Assets\File;
use SilverStripe\Assets\Storage\AssetContainer; use SilverStripe\Assets\Storage\AssetContainer;
use SilverStripe\Core\Object; use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\ArrayList; use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DataObjectInterface; use SilverStripe\ORM\DataObjectInterface;
@ -308,7 +308,7 @@ trait FileUploadReceiver
); );
} }
// Create new object explicitly. Otherwise rely on Upload::load to choose the class. // Create new object explicitly. Otherwise rely on Upload::load to choose the class.
$fileObject = Object::create($relationClass); $fileObject = Injector::inst()->create($relationClass);
if (! ($fileObject instanceof DataObject) || !($fileObject instanceof AssetContainer)) { if (! ($fileObject instanceof DataObject) || !($fileObject instanceof AssetContainer)) {
throw new InvalidArgumentException("Invalid asset container $relationClass"); throw new InvalidArgumentException("Invalid asset container $relationClass");
} }

View File

@ -942,7 +942,7 @@ class Form extends ViewableData implements HasRequestHandler
*/ */
public function getTemplates() public function getTemplates()
{ {
$templates = SSViewer::get_templates_by_class(get_class($this), '', __CLASS__); $templates = SSViewer::get_templates_by_class(static::class, '', __CLASS__);
// Prefer any custom template // Prefer any custom template
if ($this->getTemplate()) { if ($this->getTemplate()) {
array_unshift($templates, $this->getTemplate()); array_unshift($templates, $this->getTemplate());
@ -1702,7 +1702,8 @@ class Form extends ViewableData implements HasRequestHandler
public function debug() public function debug()
{ {
$result = "<h3>$this->class</h3><ul>"; $class = static::class;
$result = "<h3>$class</h3><ul>";
foreach ($this->fields as $field) { foreach ($this->fields as $field) {
$result .= "<li>$field" . $field->debug() . "</li>"; $result .= "<li>$field" . $field->debug() . "</li>";
} }

View File

@ -1140,7 +1140,7 @@ class FormField extends RequestHandler
*/ */
protected function _templates($customTemplate = null, $customTemplateSuffix = null) protected function _templates($customTemplate = null, $customTemplateSuffix = null)
{ {
$templates = SSViewer::get_templates_by_class(get_class($this), $customTemplateSuffix, __CLASS__); $templates = SSViewer::get_templates_by_class(static::class, $customTemplateSuffix, __CLASS__);
// Prefer any custom template // Prefer any custom template
if ($customTemplate) { if ($customTemplate) {
// Prioritise direct template // Prioritise direct template
@ -1278,7 +1278,7 @@ class FormField extends RequestHandler
*/ */
public function performDisabledTransformation() public function performDisabledTransformation()
{ {
$disabledClassName = $this->class . '_Disabled'; $disabledClassName = static::class . '_Disabled';
if (ClassInfo::exists($disabledClassName)) { if (ClassInfo::exists($disabledClassName)) {
$clone = $this->castedCopy($disabledClassName); $clone = $this->castedCopy($disabledClassName);
@ -1310,7 +1310,7 @@ class FormField extends RequestHandler
{ {
$patten = '/' . strtolower($class) . '/i'; $patten = '/' . strtolower($class) . '/i';
$subject = strtolower($this->class . ' ' . $this->extraClass()); $subject = strtolower(static::class . ' ' . $this->extraClass());
return preg_match($patten, $subject); return preg_match($patten, $subject);
} }
@ -1377,7 +1377,7 @@ class FormField extends RequestHandler
{ {
return sprintf( return sprintf(
'%s (%s: %s : <span style="color:red;">%s</span>) = %s', '%s (%s: %s : <span style="color:red;">%s</span>) = %s',
$this->class, static::class,
$this->name, $this->name,
$this->title, $this->title,
$this->message, $this->message,
@ -1435,12 +1435,13 @@ class FormField extends RequestHandler
*/ */
public function rootFieldList() public function rootFieldList()
{ {
if (is_object($this->containerFieldList)) { if ($this->containerFieldList) {
return $this->containerFieldList->rootFieldList(); return $this->containerFieldList->rootFieldList();
} }
$class = static::class;
user_error( user_error(
"rootFieldList() called on $this->class object without a containerFieldList", "rootFieldList() called on {$class} object without a containerFieldList",
E_USER_ERROR E_USER_ERROR
); );

View File

@ -213,7 +213,7 @@ class FormRequestHandler extends RequestHandler
) { ) {
return $this->httpError( return $this->httpError(
403, 403,
sprintf('Action "%s" not allowed on form request handler (Class: "%s")', $funcName, get_class($this)) sprintf('Action "%s" not allowed on form request handler (Class: "%s")', $funcName, static::class)
); );
} }
@ -258,7 +258,7 @@ class FormRequestHandler extends RequestHandler
if ($legacyActions) { if ($legacyActions) {
throw new BadMethodCallException( throw new BadMethodCallException(
"allowed_actions are not valid on Form class " . get_class($this->form) . "allowed_actions are not valid on Form class " . get_class($this->form) .
". Implement these in subclasses of " . get_class($this) . " instead" ". Implement these in subclasses of " . static::class . " instead"
); );
} }

View File

@ -2,7 +2,8 @@
namespace SilverStripe\Forms; namespace SilverStripe\Forms;
use SilverStripe\Core\Object; use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Forms\GridField\GridField; use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor; use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor;
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
@ -11,8 +12,9 @@ use SilverStripe\ORM\DataObject;
* @uses DBField::scaffoldFormField() * @uses DBField::scaffoldFormField()
* @uses DataObject::fieldLabels() * @uses DataObject::fieldLabels()
*/ */
class FormScaffolder extends Object class FormScaffolder
{ {
use Injectable;
/** /**
* @var DataObject $obj The object defining the fields to be scaffolded * @var DataObject $obj The object defining the fields to be scaffolded
@ -58,7 +60,6 @@ class FormScaffolder extends Object
public function __construct($obj) public function __construct($obj)
{ {
$this->obj = $obj; $this->obj = $obj;
parent::__construct();
} }
/** /**
@ -151,7 +152,7 @@ class FormScaffolder extends Object
? $this->fieldClasses[$relationship] ? $this->fieldClasses[$relationship]
: 'SilverStripe\\Forms\\GridField\\GridField'; : 'SilverStripe\\Forms\\GridField\\GridField';
/** @var GridField $grid */ /** @var GridField $grid */
$grid = Object::create( $grid = Injector::inst()->create(
$fieldClass, $fieldClass,
$relationship, $relationship,
$this->obj->fieldLabel($relationship), $this->obj->fieldLabel($relationship),
@ -181,7 +182,7 @@ class FormScaffolder extends Object
: 'SilverStripe\\Forms\\GridField\\GridField'; : 'SilverStripe\\Forms\\GridField\\GridField';
/** @var GridField $grid */ /** @var GridField $grid */
$grid = Object::create( $grid = Injector::inst()->create(
$fieldClass, $fieldClass,
$relationship, $relationship,
$this->obj->fieldLabel($relationship), $this->obj->fieldLabel($relationship),

View File

@ -2,9 +2,11 @@
namespace SilverStripe\Forms; namespace SilverStripe\Forms;
use BadMethodCallException;
use SilverStripe\Core\ClassInfo; use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Object; use SilverStripe\Core\Config\Configurable;
use SilverStripe\Dev\Debug; use SilverStripe\Core\Extensible;
use SilverStripe\Core\Injector\Injectable;
/** /**
* This class represents "transformations" of a form - such as making it printable or making it readonly. * This class represents "transformations" of a form - such as making it printable or making it readonly.
@ -18,8 +20,17 @@ use SilverStripe\Dev\Debug;
* *
* To actually perform the transformation, call $form->transform(new MyTransformation()); * To actually perform the transformation, call $form->transform(new MyTransformation());
*/ */
class FormTransformation extends Object class FormTransformation
{ {
use Configurable;
use Injectable;
use Extensible;
public function __construct()
{
$this->constructExtensions();
}
public function transform(FormField $field) public function transform(FormField $field)
{ {
// Look for a performXXTransformation() method on the field itself. // Look for a performXXTransformation() method on the field itself.
@ -34,13 +45,13 @@ class FormTransformation extends Object
function ($name) { function ($name) {
return ClassInfo::shortName($name); return ClassInfo::shortName($name);
}, },
array_values(ClassInfo::ancestry($this->class)) array_values(ClassInfo::ancestry($this))
)); ));
$fieldClasses = array_reverse(array_map( $fieldClasses = array_reverse(array_map(
function ($name) { function ($name) {
return ClassInfo::shortName($name); return ClassInfo::shortName($name);
}, },
array_values(ClassInfo::ancestry($field->class)) array_values(ClassInfo::ancestry($field))
)); ));
$len = max(sizeof($transNames), sizeof($fieldClasses)); $len = max(sizeof($transNames), sizeof($fieldClasses));
@ -64,6 +75,8 @@ class FormTransformation extends Object
} }
} }
throw new \BadMethodCallException("FormTransformation:: Can't perform '$this->class' on '$field->class'"); $class = static::class;
$fieldClass = get_class($field);
throw new BadMethodCallException("FormTransformation:: Can't perform '{$class}' on '{$fieldClass}'");
} }
} }

View File

@ -2,8 +2,10 @@
namespace SilverStripe\Forms\GridField; namespace SilverStripe\Forms\GridField;
use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Extensible;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\ORM\ArrayList; use SilverStripe\ORM\ArrayList;
use SilverStripe\Core\Object;
/** /**
* Encapsulates a collection of components following the * Encapsulates a collection of components following the
@ -22,22 +24,21 @@ use SilverStripe\Core\Object;
* - {@link GridFieldConfig_RecordEditor} * - {@link GridFieldConfig_RecordEditor}
* - {@link GridFieldConfig_RelationEditor} * - {@link GridFieldConfig_RelationEditor}
*/ */
class GridFieldConfig extends Object class GridFieldConfig
{ {
use Injectable;
use Extensible;
use Configurable;
/** /**
* @var ArrayList * @var ArrayList
*/ */
protected $components = null; protected $components = null;
/**
*
*/
public function __construct() public function __construct()
{ {
parent::__construct();
$this->components = new ArrayList(); $this->components = new ArrayList();
$this->constructExtensions();
} }
/** /**

View File

@ -3,16 +3,17 @@
namespace SilverStripe\Forms\GridField; namespace SilverStripe\Forms\GridField;
use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Control\RequestHandler; use SilverStripe\Control\RequestHandler;
use SilverStripe\Core\Extensible; use SilverStripe\Core\Extensible;
use SilverStripe\ORM\DataModel; use SilverStripe\ORM\DataModel;
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
use SilverStripe\Core\Object;
use SilverStripe\Core\ClassInfo; use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use SilverStripe\Forms\Validator; use SilverStripe\Forms\Validator;
use SilverStripe\Forms\FieldList; use SilverStripe\Forms\FieldList;
use Closure; use Closure;
use SilverStripe\ORM\Filterable;
/** /**
* Provides view and edit forms at GridField-specific URLs. * Provides view and edit forms at GridField-specific URLs.
@ -91,7 +92,7 @@ class GridFieldDetailForm implements GridField_URLHandler
* *
* @param GridField $gridField * @param GridField $gridField
* @param HTTPRequest $request * @param HTTPRequest $request
* @return GridFieldDetailForm_ItemRequest * @return HTTPResponse
*/ */
public function handleItem($gridField, $request) public function handleItem($gridField, $request)
{ {
@ -102,21 +103,18 @@ class GridFieldDetailForm implements GridField_URLHandler
/** @var DataObject $record */ /** @var DataObject $record */
if (is_numeric($request->param('ID'))) { if (is_numeric($request->param('ID'))) {
$record = $gridField->getList()->byID($request->param("ID")); /** @var Filterable $dataList */
$dataList = $gridField->getList();
$record = $dataList->byID($request->param("ID"));
} else { } else {
$record = Object::create($gridField->getModelClass()); $record = Injector::inst()->create($gridField->getModelClass());
} }
$handler = $this->getItemRequestHandler($gridField, $record, $requestHandler); $handler = $this->getItemRequestHandler($gridField, $record, $requestHandler);
// if no validator has been set on the GridField and the record has a // if no validator has been set on the GridField and the record has a
// CMS validator, use that. // CMS validator, use that.
if (!$this->getValidator() if (!$this->getValidator() && ClassInfo::hasMethod($record, 'getCMSValidator')) {
&& (
method_exists($record, 'getCMSValidator')
|| $record instanceof Object && $record->hasMethod('getCMSValidator')
)
) {
$this->setValidator($record->getCMSValidator()); $this->setValidator($record->getCMSValidator());
} }
@ -236,8 +234,8 @@ class GridFieldDetailForm implements GridField_URLHandler
{ {
if ($this->itemRequestClass) { if ($this->itemRequestClass) {
return $this->itemRequestClass; return $this->itemRequestClass;
} elseif (ClassInfo::exists(get_class($this) . "_ItemRequest")) { } elseif (ClassInfo::exists(static::class . "_ItemRequest")) {
return get_class($this) . "_ItemRequest"; return static::class . "_ItemRequest";
} else { } else {
return __CLASS__ . '_ItemRequest'; return __CLASS__ . '_ItemRequest';
} }

View File

@ -65,7 +65,7 @@ class GridFieldFilterHeader implements GridField_HTMLProvider, GridField_DataMan
} else { } else {
if ($this->throwExceptionOnBadDataType) { if ($this->throwExceptionOnBadDataType) {
throw new LogicException( throw new LogicException(
get_class($this) . " expects an SS_Filterable list to be passed to the GridField." static::class . " expects an SS_Filterable list to be passed to the GridField."
); );
} }
return false; return false;

View File

@ -2,10 +2,11 @@
namespace SilverStripe\Forms\GridField; namespace SilverStripe\Forms\GridField;
use SilverStripe\Core\Object; use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Forms\FormField; use SilverStripe\Forms\FormField;
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\FieldType\DBField; use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\Hierarchy\Hierarchy;
use SilverStripe\View\ArrayData; use SilverStripe\View\ArrayData;
use SilverStripe\View\SSViewer; use SilverStripe\View\SSViewer;
@ -14,8 +15,9 @@ use SilverStripe\View\SSViewer;
* hierarchical data. Requires the managed record to have a "getParent()" * hierarchical data. Requires the managed record to have a "getParent()"
* method or has_one relationship called "Parent". * method or has_one relationship called "Parent".
*/ */
class GridFieldLevelup extends Object implements GridField_HTMLProvider class GridFieldLevelup implements GridField_HTMLProvider
{ {
use Injectable;
/** /**
* @var integer - the record id of the level up to * @var integer - the record id of the level up to
@ -40,12 +42,15 @@ class GridFieldLevelup extends Object implements GridField_HTMLProvider
*/ */
public function __construct($currentID) public function __construct($currentID)
{ {
parent::__construct();
if ($currentID && is_numeric($currentID)) { if ($currentID && is_numeric($currentID)) {
$this->currentID = $currentID; $this->currentID = $currentID;
} }
} }
/**
* @param GridField $gridField
* @return array|null
*/
public function getHTMLFragments($gridField) public function getHTMLFragments($gridField)
{ {
$modelClass = $gridField->getModelClass(); $modelClass = $gridField->getModelClass();
@ -55,6 +60,7 @@ class GridFieldLevelup extends Object implements GridField_HTMLProvider
return null; return null;
} }
/** @var DataObject|Hierarchy $modelObj */
$modelObj = DataObject::get_by_id($modelClass, $this->currentID); $modelObj = DataObject::get_by_id($modelClass, $this->currentID);
$parent = null; $parent = null;

View File

@ -51,7 +51,7 @@ class GridFieldPageCount implements GridField_HTMLProvider
if (!$paginator && GridFieldPageCount::config()->uninherited('require_paginator')) { if (!$paginator && GridFieldPageCount::config()->uninherited('require_paginator')) {
throw new LogicException( throw new LogicException(
get_class($this) . " relies on a GridFieldPaginator to be added " . static::class . " relies on a GridFieldPaginator to be added " .
"to the same GridField, but none are present." "to the same GridField, but none are present."
); );
} }

View File

@ -88,7 +88,7 @@ class GridFieldPaginator implements GridField_HTMLProvider, GridField_DataManipu
} else { } else {
if ($this->throwExceptionOnBadDataType) { if ($this->throwExceptionOnBadDataType) {
throw new LogicException( throw new LogicException(
get_class($this) . " expects an SS_Limitable list to be passed to the GridField." static::class . " expects an SS_Limitable list to be passed to the GridField."
); );
} }
return false; return false;

View File

@ -75,7 +75,7 @@ class GridFieldSortableHeader implements GridField_HTMLProvider, GridField_DataM
} else { } else {
if ($this->throwExceptionOnBadDataType) { if ($this->throwExceptionOnBadDataType) {
throw new LogicException( throw new LogicException(
get_class($this) . " expects an SS_Sortable list to be passed to the GridField." static::class . " expects an SS_Sortable list to be passed to the GridField."
); );
} }
return false; return false;

View File

@ -47,7 +47,7 @@ class HTMLEditorField_Toolbar extends RequestHandler
*/ */
public function getTemplateViewFile() public function getTemplateViewFile()
{ {
return SSViewer::get_templates_by_class(get_class($this), '_viewfile', __CLASS__); return SSViewer::get_templates_by_class(static::class, '_viewfile', __CLASS__);
} }
/** /**

View File

@ -170,7 +170,7 @@ class NullableField extends FormField
{ {
$result = sprintf( $result = sprintf(
'%s (%s: $s : <span style="color: red">%s</span>) = ', '%s (%s: $s : <span style="color: red">%s</span>) = ',
$this->class, static::class,
$this->name, $this->name,
$this->title, $this->title,
$this->message $this->message

View File

@ -2,7 +2,9 @@
namespace SilverStripe\Forms; namespace SilverStripe\Forms;
use SilverStripe\Core\Object; use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Extensible;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\ORM\ValidationResult; use SilverStripe\ORM\ValidationResult;
/** /**
@ -10,13 +12,16 @@ use SilverStripe\ORM\ValidationResult;
* fields. It relies on javascript for client-side validation, and marking fields after server-side * fields. It relies on javascript for client-side validation, and marking fields after server-side
* validation. It acts as a visitor to individual form fields. * validation. It acts as a visitor to individual form fields.
*/ */
abstract class Validator extends Object abstract class Validator
{ {
use Injectable;
use Configurable;
use Extensible;
public function __construct() public function __construct()
{ {
parent::__construct();
$this->resetResult(); $this->resetResult();
$this->constructExtensions();
} }
/** /**

View File

@ -118,7 +118,7 @@ class ArrayList extends ViewableData implements SS_List, Filterable, Sortable, L
public function debug() public function debug()
{ {
$val = "<h2>" . $this->class . "</h2><ul>"; $val = "<h2>" . static::class . "</h2><ul>";
foreach ($this->toNestedArray() as $item) { foreach ($this->toNestedArray() as $item) {
$val .= "<li style=\"list-style-type: disc; margin-left: 20px\">" . Debug::text($item) . "</li>"; $val .= "<li style=\"list-style-type: disc; margin-left: 20px\">" . Debug::text($item) . "</li>";
} }

View File

@ -73,8 +73,8 @@ abstract class DBConnector
public function isQueryMutable($sql) public function isQueryMutable($sql)
{ {
$operations = array_merge( $operations = array_merge(
Config::inst()->get(get_class($this), 'write_operations'), Config::inst()->get(static::class, 'write_operations'),
Config::inst()->get(get_class($this), 'ddl_operations') Config::inst()->get(static::class, 'ddl_operations')
); );
return $this->isQueryType($sql, $operations); return $this->isQueryType($sql, $operations);
} }
@ -87,7 +87,7 @@ abstract class DBConnector
*/ */
public function isQueryDDL($sql) public function isQueryDDL($sql)
{ {
$operations = Config::inst()->get(get_class($this), 'ddl_operations'); $operations = Config::inst()->get(static::class, 'ddl_operations');
return $this->isQueryType($sql, $operations); return $this->isQueryType($sql, $operations);
} }
@ -100,7 +100,7 @@ abstract class DBConnector
*/ */
public function isQueryWrite($sql) public function isQueryWrite($sql)
{ {
$operations = Config::inst()->get(get_class($this), 'write_operations'); $operations = Config::inst()->get(static::class, 'write_operations');
return $this->isQueryType($sql, $operations); return $this->isQueryType($sql, $operations);
} }

View File

@ -4,7 +4,7 @@ namespace SilverStripe\ORM\Connect;
use SilverStripe\Control\Director; use SilverStripe\Control\Director;
use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Object; use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\FieldType\DBPrimaryKey; use SilverStripe\ORM\FieldType\DBPrimaryKey;
use SilverStripe\ORM\FieldType\DBField; use SilverStripe\ORM\FieldType\DBField;
use Exception; use Exception;
@ -356,7 +356,7 @@ abstract class DBSchemaManager
// Check if options changed // Check if options changed
$tableOptionsChanged = false; $tableOptionsChanged = false;
// Check for DB constant on the schema class // Check for DB constant on the schema class
$dbIDName = sprintf('%s::ID', get_class($this)); $dbIDName = sprintf('%s::ID', static::class);
$dbID = defined($dbIDName) ? constant($dbIDName) : null; $dbID = defined($dbIDName) ? constant($dbIDName) : null;
if ($dbID && isset($options[$dbID])) { if ($dbID && isset($options[$dbID])) {
if (preg_match('/ENGINE=([^\s]*)/', $options[$dbID], $alteredEngineMatches)) { if (preg_match('/ENGINE=([^\s]*)/', $options[$dbID], $alteredEngineMatches)) {
@ -389,7 +389,7 @@ abstract class DBSchemaManager
} }
/** @var DBField $fieldObj */ /** @var DBField $fieldObj */
$fieldObj = Object::create_from_string($fieldSpec, $fieldName); $fieldObj = Injector::inst()->create($fieldSpec, $fieldName);
$fieldObj->setArrayValue($arrayValue); $fieldObj->setArrayValue($arrayValue);
$fieldObj->setTable($table); $fieldObj->setTable($table);

View File

@ -777,7 +777,7 @@ abstract class Database
public function selectDatabase($name, $create = false, $errorLevel = E_USER_ERROR) public function selectDatabase($name, $create = false, $errorLevel = E_USER_ERROR)
{ {
// In case our live environment is locked down, we can bypass a SHOW DATABASE check // In case our live environment is locked down, we can bypass a SHOW DATABASE check
$canConnect = Config::inst()->get(get_class($this), 'optimistic_connect') $canConnect = Config::inst()->get(static::class, 'optimistic_connect')
|| $this->schemaManager->databaseExists($name); || $this->schemaManager->databaseExists($name);
if ($canConnect) { if ($canConnect) {
return $this->connector->selectDatabase($name); return $this->connector->selectDatabase($name);

View File

@ -165,7 +165,7 @@ abstract class DataExtension extends Extension
*/ */
public function updateSummaryFields(&$fields) public function updateSummaryFields(&$fields)
{ {
$summary_fields = Config::inst()->get($this->class, 'summary_fields'); $summary_fields = Config::inst()->get(static::class, 'summary_fields');
if ($summary_fields) { if ($summary_fields) {
// if summary_fields were passed in numeric array, // if summary_fields were passed in numeric array,
// convert to an associative array // convert to an associative array
@ -188,7 +188,7 @@ abstract class DataExtension extends Extension
*/ */
public function updateFieldLabels(&$labels) public function updateFieldLabels(&$labels)
{ {
$field_labels = Config::inst()->get($this->class, 'field_labels'); $field_labels = Config::inst()->get(static::class, 'field_labels');
if ($field_labels) { if ($field_labels) {
$labels = array_merge($labels, $field_labels); $labels = array_merge($labels, $field_labels);
} }

View File

@ -750,8 +750,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
public function debug() public function debug()
{ {
$val = "<h2>" . $this->class . "</h2><ul>"; $val = "<h2>" . static::class . "</h2><ul>";
foreach ($this->toNestedArray() as $item) { foreach ($this->toNestedArray() as $item) {
$val .= "<li style=\"list-style-type: disc; margin-left: 20px\">" . Debug::text($item) . "</li>"; $val .= "<li style=\"list-style-type: disc; margin-left: 20px\">" . Debug::text($item) . "</li>";
} }
@ -1072,7 +1071,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
/** /**
* Remove every element in this DataList matching the given $filter. * Remove every element in this DataList matching the given $filter.
* *
* @param string $filter - a sql type where filter * @param string|array $filter - a sql type where filter
* @return $this * @return $this
*/ */
public function removeByFilter($filter) public function removeByFilter($filter)

View File

@ -4,7 +4,6 @@ namespace SilverStripe\ORM;
use SilverStripe\Core\ClassInfo; use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Object;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Resettable; use SilverStripe\Core\Resettable;
use SilverStripe\Dev\Deprecation; use SilverStripe\Dev\Deprecation;
@ -30,6 +29,7 @@ use LogicException;
use InvalidArgumentException; use InvalidArgumentException;
use BadMethodCallException; use BadMethodCallException;
use Exception; use Exception;
use stdClass;
/** /**
* A single database record & abstract class for the data-access-model. * A single database record & abstract class for the data-access-model.
@ -306,7 +306,11 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
); );
} }
if (!is_array($record) && !is_a($record, "stdClass")) { if ($record instanceof stdClass) {
$record = (array)$record;
}
if (!is_array($record)) {
if (is_object($record)) { if (is_object($record)) {
$passed = "an object of type '".get_class($record)."'"; $passed = "an object of type '".get_class($record)."'";
} else { } else {
@ -321,10 +325,6 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
$record = null; $record = null;
} }
if (is_a($record, "stdClass")) {
$record = (array)$record;
}
// Set $this->record to $record, but ignore NULLs // Set $this->record to $record, but ignore NULLs
$this->record = array(); $this->record = array();
foreach ($record as $k => $v) { foreach ($record as $k => $v) {
@ -517,7 +517,6 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
return $this; return $this;
} }
$this->class = $className;
$this->setField("ClassName", $className); $this->setField("ClassName", $className);
$this->setField('RecordClassName', $className); $this->setField('RecordClassName', $className);
return $this; return $this;
@ -568,20 +567,6 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
{ {
parent::defineMethods(); parent::defineMethods();
// Define the extra db fields - this is only necessary for extensions added in the
// class definition. Object::add_extension() will call this at definition time for
// those objects, which is a better mechanism. Perhaps extensions defined inside the
// class def can somehow be applied at definiton time also?
if ($this->extension_instances) {
foreach ($this->extension_instances as $i => $instance) {
if (!$instance->class) {
$class = get_class($instance);
user_error("DataObject::defineMethods(): Please ensure {$class}::__construct() calls"
. " parent::__construct()", E_USER_ERROR);
}
}
}
if (static::class === self::class) { if (static::class === self::class) {
return; return;
} }
@ -815,11 +800,12 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
*/ */
public function update($data) public function update($data)
{ {
foreach ($data as $k => $v) { foreach ($data as $key => $value) {
// Implement dot syntax for updates // Implement dot syntax for updates
if (strpos($k, '.') !== false) { if (strpos($key, '.') !== false) {
$relations = explode('.', $k); $relations = explode('.', $key);
$fieldName = array_pop($relations); $fieldName = array_pop($relations);
/** @var static $relObj */
$relObj = $this; $relObj = $this;
$relation = null; $relation = null;
foreach ($relations as $i => $relation) { foreach ($relations as $i => $relation) {
@ -829,7 +815,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
$parentObj = $relObj; $parentObj = $relObj;
$relObj = $relObj->$relation(); $relObj = $relObj->$relation();
// If the intermediate relationship objects have been created, then write them // If the intermediate relationship objects have been created, then write them
if ($i<sizeof($relation)-1 && !$relObj->ID || (!$relObj->ID && $parentObj != $this)) { if ($i<sizeof($relation)-1 && !$relObj->ID || (!$relObj->ID && $parentObj !== $this)) {
$relObj->write(); $relObj->write();
$relatedFieldName = $relation."ID"; $relatedFieldName = $relation."ID";
$parentObj->$relatedFieldName = $relObj->ID; $parentObj->$relatedFieldName = $relObj->ID;
@ -848,16 +834,17 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
} }
if ($relObj) { if ($relObj) {
$relObj->$fieldName = $v; $relObj->$fieldName = $value;
$relObj->write(); $relObj->write();
$relatedFieldName = $relation."ID"; $relatedFieldName = $relation."ID";
$this->$relatedFieldName = $relObj->ID; $this->$relatedFieldName = $relObj->ID;
$relObj->flushCache(); $relObj->flushCache();
} else { } else {
user_error("Couldn't follow dot syntax '$k' on '$this->class' object", E_USER_WARNING); $class = static::class;
user_error("Couldn't follow dot syntax '{$key}' on '{$class}' object", E_USER_WARNING);
} }
} else { } else {
$this->$k = $v; $this->$key = $value;
} }
} }
return $this; return $this;
@ -949,6 +936,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
if ($includeRelations) { if ($includeRelations) {
if ($manyMany = $this->manyMany()) { if ($manyMany = $this->manyMany()) {
foreach ($manyMany as $relationship => $class) { foreach ($manyMany as $relationship => $class) {
/** @var DataObject $leftComponents */
$leftComponents = $leftObj->getManyManyComponents($relationship); $leftComponents = $leftObj->getManyManyComponents($relationship);
$rightComponents = $rightObj->getManyManyComponents($relationship); $rightComponents = $rightObj->getManyManyComponents($relationship);
if ($rightComponents && $rightComponents->exists()) { if ($rightComponents && $rightComponents->exists()) {
@ -1110,7 +1098,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
if ($defaults && !is_array($defaults)) { if ($defaults && !is_array($defaults)) {
user_error( user_error(
"Bad '$this->class' defaults given: " . var_export($defaults, true), "Bad '" . static::class . "' defaults given: " . var_export($defaults, true),
E_USER_WARNING E_USER_WARNING
); );
$defaults = null; $defaults = null;
@ -1181,7 +1169,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
$this->brokenOnWrite = true; $this->brokenOnWrite = true;
$this->onBeforeWrite(); $this->onBeforeWrite();
if ($this->brokenOnWrite) { if ($this->brokenOnWrite) {
user_error("$this->class has a broken onBeforeWrite() function." user_error(static::class . " has a broken onBeforeWrite() function."
. " Make sure that you call parent::onBeforeWrite().", E_USER_ERROR); . " Make sure that you call parent::onBeforeWrite().", E_USER_ERROR);
} }
} }
@ -1251,7 +1239,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
= empty($this->record['Created']) = empty($this->record['Created'])
? $now ? $now
: $this->record['Created']; : $this->record['Created'];
$manipulation[$table]['fields']['ClassName'] = $this->class; $manipulation[$table]['fields']['ClassName'] = static::class;
} }
} }
@ -1434,7 +1422,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
$this->brokenOnDelete = true; $this->brokenOnDelete = true;
$this->onBeforeDelete(); $this->onBeforeDelete();
if ($this->brokenOnDelete) { if ($this->brokenOnDelete) {
user_error("$this->class has a broken onBeforeDelete() function." user_error(static::class . " has a broken onBeforeDelete() function."
. " Make sure that you call parent::onBeforeDelete().", E_USER_ERROR); . " Make sure that you call parent::onBeforeDelete().", E_USER_ERROR);
} }
@ -1447,7 +1435,10 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
// - move the details of the delete code in the DataQuery system // - move the details of the delete code in the DataQuery system
// - update the code to just delete the base table, and rely on cascading deletes in the DB to do the rest // - update the code to just delete the base table, and rely on cascading deletes in the DB to do the rest
// obviously, that means getting requireTable() to configure cascading deletes ;-) // obviously, that means getting requireTable() to configure cascading deletes ;-)
$srcQuery = DataList::create($this->class, $this->model)->where("ID = $this->ID")->dataQuery()->query(); $srcQuery = DataList::create(static::class, $this->model)
->filter('ID', $this->ID)
->dataQuery()
->query();
foreach ($srcQuery->queriedTables() as $table) { foreach ($srcQuery->queriedTables() as $table) {
$delete = new SQLDelete("\"$table\"", array('"ID"' => $this->ID)); $delete = new SQLDelete("\"$table\"", array('"ID"' => $this->ID));
$delete->execute(); $delete->execute();
@ -1538,7 +1529,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
if ($polymorphic) { if ($polymorphic) {
$filter = array( $filter = array(
"{$joinField}ID" => $joinID, "{$joinField}ID" => $joinID,
"{$joinField}Class" => $this->class "{$joinField}Class" => static::class,
); );
} else { } else {
$filter = array( $filter = array(
@ -1557,7 +1548,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
$component = $this->model->$class->newObject(); $component = $this->model->$class->newObject();
if ($polymorphic) { if ($polymorphic) {
$component->{$joinField.'ID'} = $this->ID; $component->{$joinField.'ID'} = $this->ID;
$component->{$joinField.'Class'} = $this->class; $component->{$joinField.'Class'} = static::class;
} else { } else {
$component->$joinField = $this->ID; $component->$joinField = $this->ID;
} }
@ -1588,7 +1579,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
throw new InvalidArgumentException(sprintf( throw new InvalidArgumentException(sprintf(
"DataObject::getComponents(): Unknown 1-to-many component '%s' on class '%s'", "DataObject::getComponents(): Unknown 1-to-many component '%s' on class '%s'",
$componentName, $componentName,
$this->class static::class
)); ));
} }
@ -1596,7 +1587,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
if (!$this->ID) { if (!$this->ID) {
if (!isset($this->unsavedRelations[$componentName])) { if (!isset($this->unsavedRelations[$componentName])) {
$this->unsavedRelations[$componentName] = $this->unsavedRelations[$componentName] =
new UnsavedRelationList($this->class, $componentName, $componentClass); new UnsavedRelationList(static::class, $componentName, $componentClass);
} }
return $this->unsavedRelations[$componentName]; return $this->unsavedRelations[$componentName];
} }
@ -1605,7 +1596,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
$joinField = $schema->getRemoteJoinField(static::class, $componentName, 'has_many', $polymorphic); $joinField = $schema->getRemoteJoinField(static::class, $componentName, 'has_many', $polymorphic);
/** @var HasManyList $result */ /** @var HasManyList $result */
if ($polymorphic) { if ($polymorphic) {
$result = PolymorphicHasManyList::create($componentClass, $joinField, $this->class); $result = PolymorphicHasManyList::create($componentClass, $joinField, static::class);
} else { } else {
$result = HasManyList::create($componentClass, $joinField); $result = HasManyList::create($componentClass, $joinField);
} }
@ -1630,11 +1621,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
// Parse many_many // Parse many_many
$manyManyComponent = $this->getSchema()->manyManyComponent(static::class, $relationName); $manyManyComponent = $this->getSchema()->manyManyComponent(static::class, $relationName);
if ($manyManyComponent) { if ($manyManyComponent) {
list( return $manyManyComponent['childClass'];
$relationClass, $parentClass, $componentClass,
$parentField, $childField, $tableOrClass
) = $manyManyComponent;
return $componentClass;
} }
// Go through all relationship configuration fields. // Go through all relationship configuration fields.
@ -1772,18 +1759,17 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
case 'many_many': case 'many_many':
case 'belongs_many_many': { case 'belongs_many_many': {
// Get components and extra fields from parent // Get components and extra fields from parent
list($relationClass, $componentClass, $parentClass, $componentField, $parentField, $table) $manyMany = $remote->getSchema()->manyManyComponent($remoteClass, $remoteRelation);
= $remote->getSchema()->manyManyComponent($remoteClass, $remoteRelation);
$extraFields = $schema->manyManyExtraFieldsForComponent($remoteClass, $remoteRelation) ?: array(); $extraFields = $schema->manyManyExtraFieldsForComponent($remoteClass, $remoteRelation) ?: array();
// Reverse parent and component fields and create an inverse ManyManyList // Reverse parent and component fields and create an inverse ManyManyList
/** @var RelationList $result */ /** @var RelationList $result */
$result = Injector::inst()->create( $result = Injector::inst()->create(
$relationClass, $manyMany['relationClass'],
$componentClass, $manyMany['parentClass'], // Substitute parent class for dataClass
$table, $manyMany['join'],
$componentField, $manyMany['parentField'], // Reversed parent / child field
$parentField, $manyMany['childField'], // Reversed parent / child field
$extraFields $extraFields
); );
if ($this->model) { if ($this->model) {
@ -1816,18 +1802,15 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
throw new InvalidArgumentException(sprintf( throw new InvalidArgumentException(sprintf(
"DataObject::getComponents(): Unknown many-to-many component '%s' on class '%s'", "DataObject::getComponents(): Unknown many-to-many component '%s' on class '%s'",
$componentName, $componentName,
$this->class static::class
)); ));
} }
list($relationClass, $parentClass, $componentClass, $parentField, $componentField, $tableOrClass)
= $manyManyComponent;
// If we haven't been written yet, we can't save these relations, so use a list that handles this case // If we haven't been written yet, we can't save these relations, so use a list that handles this case
if (!$this->ID) { if (!$this->ID) {
if (!isset($this->unsavedRelations[$componentName])) { if (!isset($this->unsavedRelations[$componentName])) {
$this->unsavedRelations[$componentName] = $this->unsavedRelations[$componentName] =
new UnsavedRelationList($parentClass, $componentName, $componentClass); new UnsavedRelationList($manyManyComponent['parentClass'], $componentName, $manyManyComponent['childClass']);
} }
return $this->unsavedRelations[$componentName]; return $this->unsavedRelations[$componentName];
} }
@ -1835,11 +1818,11 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
$extraFields = $schema->manyManyExtraFieldsForComponent(static::class, $componentName) ?: array(); $extraFields = $schema->manyManyExtraFieldsForComponent(static::class, $componentName) ?: array();
/** @var RelationList $result */ /** @var RelationList $result */
$result = Injector::inst()->create( $result = Injector::inst()->create(
$relationClass, $manyManyComponent['relationClass'],
$componentClass, $manyManyComponent['childClass'],
$tableOrClass, $manyManyComponent['join'],
$componentField, $manyManyComponent['childField'],
$parentField, $manyManyComponent['parentField'],
$extraFields $extraFields
); );
@ -1968,7 +1951,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
public function getDefaultSearchContext() public function getDefaultSearchContext()
{ {
return new SearchContext( return new SearchContext(
$this->class, static::class,
$this->scaffoldSearchFields(), $this->scaffoldSearchFields(),
$this->defaultSearchFilters() $this->defaultSearchFilters()
); );
@ -2069,7 +2052,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
(array)$_params (array)$_params
); );
$fs = new FormScaffolder($this); $fs = FormScaffolder::create($this);
$fs->tabbed = $params['tabbed']; $fs->tabbed = $params['tabbed'];
$fs->includeRelations = $params['includeRelations']; $fs->includeRelations = $params['includeRelations'];
$fs->restrictFields = $params['restrictFields']; $fs->restrictFields = $params['restrictFields'];
@ -2634,7 +2617,8 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
*/ */
public function debug() public function debug()
{ {
$val = "<h3>Database record: $this->class</h3>\n<ul>\n"; $class = static::class;
$val = "<h3>Database record: {$class}</h3>\n<ul>\n";
if ($this->record) { if ($this->record) {
foreach ($this->record as $fieldName => $fieldVal) { foreach ($this->record as $fieldName => $fieldVal) {
$val .= "\t<li>$fieldName: " . Debug::text($fieldVal) . "</li>\n"; $val .= "\t<li>$fieldName: " . Debug::text($fieldVal) . "</li>\n";
@ -2680,7 +2664,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
list($class, $spec) = explode('.', $helper); list($class, $spec) = explode('.', $helper);
/** @var DBField $obj */ /** @var DBField $obj */
$table = $schema->tableName($class); $table = $schema->tableName($class);
$obj = Object::create_from_string($spec, $fieldName); $obj = Injector::inst()->create($spec, $fieldName);
$obj->setTable($table); $obj->setTable($table);
$obj->setValue($value, $this, false); $obj->setValue($value, $this, false);
return $obj; return $obj;
@ -2712,6 +2696,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
if (method_exists($component, $relation)) { if (method_exists($component, $relation)) {
$component = $component->$relation(); $component = $component->$relation();
} else { } else {
/** @var DataList $component */
$component = $component->relation($relation); $component = $component->relation($relation);
} }
} else { } else {
@ -2749,6 +2734,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
$component = $component->$relation(); $component = $component->$relation();
} elseif ($component instanceof SS_List) { } elseif ($component instanceof SS_List) {
// Select adjacent relation from DataList // Select adjacent relation from DataList
/** @var DataList $component */
$component = $component->relation($relation); $component = $component->relation($relation);
} elseif ($component instanceof DataObject } elseif ($component instanceof DataObject
&& ($dbObject = $component->dbObject($relation)) && ($dbObject = $component->dbObject($relation))
@ -2914,12 +2900,12 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
*/ */
public function flushCache($persistent = true) public function flushCache($persistent = true)
{ {
if ($this->class == self::class) { if (static::class == self::class) {
self::$_cache_get_one = array(); self::$_cache_get_one = array();
return $this; return $this;
} }
$classes = ClassInfo::ancestry($this->class); $classes = ClassInfo::ancestry(static::class);
foreach ($classes as $class) { foreach ($classes as $class) {
if (isset(self::$_cache_get_one[$class])) { if (isset(self::$_cache_get_one[$class])) {
unset(self::$_cache_get_one[$class]); unset(self::$_cache_get_one[$class]);
@ -3139,10 +3125,9 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
foreach ($manyMany as $component => $spec) { foreach ($manyMany as $component => $spec) {
// Get many_many spec // Get many_many spec
$manyManyComponent = $schema->manyManyComponent(static::class, $component); $manyManyComponent = $schema->manyManyComponent(static::class, $component);
list( $parentField = $manyManyComponent['parentField'];
$relationClass, $parentClass, $componentClass, $childField = $manyManyComponent['childField'];
$parentField, $childField, $tableOrClass $tableOrClass = $manyManyComponent['join'];
) = $manyManyComponent;
// Skip if backed by actual class // Skip if backed by actual class
if (class_exists($tableOrClass)) { if (class_exists($tableOrClass)) {
@ -3184,9 +3169,9 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
$defaultRecords = $this->config()->uninherited('default_records'); $defaultRecords = $this->config()->uninherited('default_records');
if (!empty($defaultRecords)) { if (!empty($defaultRecords)) {
$hasData = DataObject::get_one($this->class); $hasData = DataObject::get_one(static::class);
if (!$hasData) { if (!$hasData) {
$className = $this->class; $className = static::class;
foreach ($defaultRecords as $record) { foreach ($defaultRecords as $record) {
$obj = $this->model->$className->newObject($record); $obj = $this->model->$className->newObject($record);
$obj->write(); $obj->write();
@ -3308,14 +3293,14 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
*/ */
public function fieldLabels($includerelations = true) public function fieldLabels($includerelations = true)
{ {
$cacheKey = $this->class . '_' . $includerelations; $cacheKey = static::class . '_' . $includerelations;
if (!isset(self::$_cache_field_labels[$cacheKey])) { if (!isset(self::$_cache_field_labels[$cacheKey])) {
$customLabels = $this->stat('field_labels'); $customLabels = $this->stat('field_labels');
$autoLabels = array(); $autoLabels = array();
// get all translated static properties as defined in i18nCollectStatics() // get all translated static properties as defined in i18nCollectStatics()
$ancestry = ClassInfo::ancestry($this->class); $ancestry = ClassInfo::ancestry(static::class);
$ancestry = array_reverse($ancestry); $ancestry = array_reverse($ancestry);
if ($ancestry) { if ($ancestry) {
foreach ($ancestry as $ancestorClass) { foreach ($ancestry as $ancestorClass) {

View File

@ -5,10 +5,10 @@ namespace SilverStripe\ORM;
use Exception; use Exception;
use SilverStripe\Core\Injector\Injectable; use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Core\Config\Configurable; use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\FieldType\DBComposite; use SilverStripe\ORM\FieldType\DBComposite;
use SilverStripe\Core\ClassInfo; use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Object;
use InvalidArgumentException; use InvalidArgumentException;
use LogicException; use LogicException;
@ -438,7 +438,7 @@ class DataObjectSchema
// Merge composite fields into DB // Merge composite fields into DB
foreach ($compositeFields as $fieldName => $fieldSpec) { foreach ($compositeFields as $fieldName => $fieldSpec) {
$fieldObj = Object::create_from_string($fieldSpec, $fieldName); $fieldObj = Injector::inst()->create($fieldSpec, $fieldName);
$fieldObj->setTable($class); $fieldObj->setTable($class);
$nestedFields = $fieldObj->compositeDatabaseFields(); $nestedFields = $fieldObj->compositeDatabaseFields();
foreach ($nestedFields as $nestedName => $nestedSpec) { foreach ($nestedFields as $nestedName => $nestedSpec) {
@ -498,7 +498,7 @@ class DataObjectSchema
} }
// Find regular field // Find regular field
while ($candidateClass) { while ($candidateClass && $candidateClass !== DataObject::class) {
$fields = $this->databaseFields($candidateClass, false); $fields = $this->databaseFields($candidateClass, false);
if (isset($fields[$fieldName])) { if (isset($fields[$fieldName])) {
return $candidateClass; return $candidateClass;
@ -533,9 +533,9 @@ class DataObjectSchema
$classes = ClassInfo::ancestry($class); $classes = ClassInfo::ancestry($class);
foreach ($classes as $parentClass) { foreach ($classes as $parentClass) {
// Check if the component is defined in many_many on this class // Check if the component is defined in many_many on this class
$manyMany = Config::inst()->get($parentClass, 'many_many', Config::UNINHERITED); $otherManyMany = Config::inst()->get($parentClass, 'many_many', Config::UNINHERITED);
if (isset($manyMany[$component])) { if (isset($otherManyMany[$component])) {
return $this->parseManyManyComponent($parentClass, $component, $manyMany[$component]); return $this->parseManyManyComponent($parentClass, $component, $otherManyMany[$component]);
} }
// Check if the component is defined in belongs_many_many on this class // Check if the component is defined in belongs_many_many on this class
@ -545,13 +545,22 @@ class DataObjectSchema
} }
// Extract class and relation name from dot-notation // Extract class and relation name from dot-notation
list($childClass, $relationName) $belongs = $this->parseBelongsManyManyComponent(
= $this->parseBelongsManyManyComponent($parentClass, $component, $belongsManyMany[$component]); $parentClass,
$component,
$belongsManyMany[$component]
);
// Build inverse relationship from other many_many, and swap parent/child // Build inverse relationship from other many_many, and swap parent/child
list($relationClass, $childClass, $parentClass, $childField, $parentField, $joinTable) $otherManyMany = $this->manyManyComponent($belongs['childClass'], $belongs['relationName']);
= $this->manyManyComponent($childClass, $relationName); return [
return [$relationClass, $parentClass, $childClass, $parentField, $childField, $joinTable]; 'relationClass' => $otherManyMany['relationClass'],
'parentClass' => $otherManyMany['childClass'],
'childClass' => $otherManyMany['parentClass'],
'parentField' => $otherManyMany['childField'],
'childField' => $otherManyMany['parentField'],
'join' => $otherManyMany['join'],
];
} }
return null; return null;
} }
@ -596,7 +605,10 @@ class DataObjectSchema
} }
// Return relatios // Return relatios
return array($childClass, $relationName); return [
'childClass' => $childClass,
'relationName' => $relationName
];
} }
/** /**
@ -619,12 +631,12 @@ class DataObjectSchema
$belongsManyMany = Config::inst()->get($class, 'belongs_many_many', Config::UNINHERITED); $belongsManyMany = Config::inst()->get($class, 'belongs_many_many', Config::UNINHERITED);
if (isset($belongsManyMany[$component])) { if (isset($belongsManyMany[$component])) {
// Reverse relationship and find extrafields from child class // Reverse relationship and find extrafields from child class
list($childClass, $relationName) = $this->parseBelongsManyManyComponent( $belongs = $this->parseBelongsManyManyComponent(
$class, $class,
$component, $component,
$belongsManyMany[$component] $belongsManyMany[$component]
); );
return $this->manyManyExtraFieldsForComponent($childClass, $relationName); return $this->manyManyExtraFieldsForComponent($belongs['childClass'], $belongs['relationName']);
} }
$class = get_parent_class($class); $class = get_parent_class($class);
} }
@ -717,12 +729,12 @@ class DataObjectSchema
$parentClass = $this->checkManyManyFieldClass($parentClass, $component, $joinClass, $specification, 'from'); $parentClass = $this->checkManyManyFieldClass($parentClass, $component, $joinClass, $specification, 'from');
$joinChildClass = $this->checkManyManyFieldClass($parentClass, $component, $joinClass, $specification, 'to'); $joinChildClass = $this->checkManyManyFieldClass($parentClass, $component, $joinClass, $specification, 'to');
return [ return [
ManyManyThroughList::class, 'relationClass' => ManyManyThroughList::class,
$parentClass, 'parentClass' => $parentClass,
$joinChildClass, 'childClass' => $joinChildClass,
$specification['from'] . 'ID', 'parentField' => $specification['from'] . 'ID',
$specification['to'] . 'ID', 'childField' => $specification['to'] . 'ID',
$joinClass, 'join' => $joinClass,
]; ];
} }
@ -740,12 +752,12 @@ class DataObjectSchema
} }
$joinTable = "{$classTable}_{$component}"; $joinTable = "{$classTable}_{$component}";
return [ return [
ManyManyList::class, 'relationClass' => ManyManyList::class,
$parentClass, 'parentClass' => $parentClass,
$specification, 'childClass' => $specification,
$parentField, 'parentField' => $parentField,
$childField, 'childField' => $childField,
$joinTable, 'join' => $joinTable,
]; ];
} }

View File

@ -4,7 +4,6 @@ namespace SilverStripe\ORM;
use SilverStripe\Core\ClassInfo; use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\Core\Object;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\Connect\Query; use SilverStripe\ORM\Connect\Query;
use SilverStripe\ORM\Queries\SQLConditionGroup; use SilverStripe\ORM\Queries\SQLConditionGroup;
@ -452,8 +451,8 @@ class DataQuery
*/ */
public function max($field) public function max($field)
{ {
$table = ClassInfo::table_for_object_field($this->dataClass, $field); $table = DataObject::getSchema()->tableForField($this->dataClass, $field);
if (!$table || $table === 'DataObject') { if (!$table) {
return $this->aggregate("MAX(\"$field\")"); return $this->aggregate("MAX(\"$field\")");
} }
return $this->aggregate("MAX(\"$table\".\"$field\")"); return $this->aggregate("MAX(\"$table\".\"$field\")");
@ -468,8 +467,8 @@ class DataQuery
*/ */
public function min($field) public function min($field)
{ {
$table = ClassInfo::table_for_object_field($this->dataClass, $field); $table = DataObject::getSchema()->tableForField($this->dataClass, $field);
if (!$table || $table === 'DataObject') { if (!$table) {
return $this->aggregate("MIN(\"$field\")"); return $this->aggregate("MIN(\"$field\")");
} }
return $this->aggregate("MIN(\"$table\".\"$field\")"); return $this->aggregate("MIN(\"$table\".\"$field\")");
@ -484,8 +483,8 @@ class DataQuery
*/ */
public function avg($field) public function avg($field)
{ {
$table = ClassInfo::table_for_object_field($this->dataClass, $field); $table = DataObject::getSchema()->tableForField($this->dataClass, $field);
if (!$table || $table === 'DataObject') { if (!$table) {
return $this->aggregate("AVG(\"$field\")"); return $this->aggregate("AVG(\"$field\")");
} }
return $this->aggregate("AVG(\"$table\".\"$field\")"); return $this->aggregate("AVG(\"$table\".\"$field\")");
@ -500,8 +499,8 @@ class DataQuery
*/ */
public function sum($field) public function sum($field)
{ {
$table = ClassInfo::table_for_object_field($this->dataClass, $field); $table = DataObject::getSchema()->tableForField($this->dataClass, $field);
if (!$table || $table === 'DataObject') { if (!$table) {
return $this->aggregate("SUM(\"$field\")"); return $this->aggregate("SUM(\"$field\")");
} }
return $this->aggregate("SUM(\"$table\".\"$field\")"); return $this->aggregate("SUM(\"$table\".\"$field\")");
@ -569,7 +568,7 @@ class DataQuery
foreach ($compositeFields as $k => $v) { foreach ($compositeFields as $k => $v) {
if ((is_null($columns) || in_array($k, $columns)) && $v) { if ((is_null($columns) || in_array($k, $columns)) && $v) {
$tableName = $schema->tableName($tableClass); $tableName = $schema->tableName($tableClass);
$dbO = Object::create_from_string($v, $k); $dbO = Injector::inst()->create($v, $k);
$dbO->setTable($tableName); $dbO->setTable($tableName);
$dbO->addToQuery($query); $dbO->addToQuery($query);
} }
@ -799,18 +798,15 @@ class DataQuery
if ($linearOnly) { if ($linearOnly) {
throw new InvalidArgumentException("$rel is not a linear relation on model $modelClass"); throw new InvalidArgumentException("$rel is not a linear relation on model $modelClass");
} }
// Join via many_many
list($relationClass, $parentClass, $componentClass, $parentField, $componentField, $relationTable)
= $component;
$this->joinManyManyRelationship( $this->joinManyManyRelationship(
$relationClass, $component['relationClass'],
$parentClass, $component['parentClass'],
$componentClass, $component['childClass'],
$parentField, $component['parentField'],
$componentField, $component['childField'],
$relationTable $component['join']
); );
$modelClass = $componentClass; $modelClass = $component['childClass'];
} else { } else {
throw new InvalidArgumentException("$rel is not a relation on model $modelClass"); throw new InvalidArgumentException("$rel is not a relation on model $modelClass");
} }
@ -1073,7 +1069,7 @@ class DataQuery
* It's expected that the $key will be namespaced, e.g, 'Versioned.stage' instead of just 'stage'. * It's expected that the $key will be namespaced, e.g, 'Versioned.stage' instead of just 'stage'.
* *
* @param string $key * @param string $key
* @param string $value * @param string|array $value
* @return $this * @return $this
*/ */
public function setQueryParam($key, $value) public function setQueryParam($key, $value)

View File

@ -49,7 +49,8 @@ class DBBoolean extends DBField
if ($fieldName) { if ($fieldName) {
$dataObject->$fieldName = ($this->value) ? 1 : 0; $dataObject->$fieldName = ($this->value) ? 1 : 0;
} else { } else {
user_error("DBField::saveInto() Called on a nameless '$this->class' object", E_USER_ERROR); $class = static::class;
user_error("DBField::saveInto() Called on a nameless '$class' object", E_USER_ERROR);
} }
} }

View File

@ -2,7 +2,7 @@
namespace SilverStripe\ORM\FieldType; namespace SilverStripe\ORM\FieldType;
use SilverStripe\Core\Object; use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DB; use SilverStripe\ORM\DB;
use SilverStripe\ORM\Queries\SQLSelect; use SilverStripe\ORM\Queries\SQLSelect;
@ -145,6 +145,7 @@ abstract class DBComposite extends DBField
* @param mixed $value * @param mixed $value
* @param mixed $record Parent object to this field, which could be a DataObject, record array, or other * @param mixed $record Parent object to this field, which could be a DataObject, record array, or other
* @param bool $markChanged * @param bool $markChanged
* @return $this
*/ */
public function setValue($value, $record = null, $markChanged = true) public function setValue($value, $record = null, $markChanged = true)
{ {
@ -172,6 +173,7 @@ abstract class DBComposite extends DBField
$this->setField($field, $record[$key]); $this->setField($field, $record[$key]);
} }
} }
return $this;
} }
/** /**
@ -277,7 +279,7 @@ abstract class DBComposite extends DBField
$key = $this->getName() . $field; $key = $this->getName() . $field;
$spec = $fields[$field]; $spec = $fields[$field];
/** @var DBField $fieldObject */ /** @var DBField $fieldObject */
$fieldObject = Object::create_from_string($spec, $key); $fieldObject = Injector::inst()->create($spec, $key);
$fieldObject->setValue($this->getField($field), null, false); $fieldObject->setValue($this->getField($field), null, false);
return $fieldObject; return $fieldObject;
} }

View File

@ -72,7 +72,7 @@ class DBDecimal extends DBField
if ($fieldName) { if ($fieldName) {
$dataObject->$fieldName = (float)preg_replace('/[^0-9.\-\+]/', '', $this->value); $dataObject->$fieldName = (float)preg_replace('/[^0-9.\-\+]/', '', $this->value);
} else { } else {
user_error("DBField::saveInto() Called on a nameless '" . get_class($this) . "' object", E_USER_ERROR); user_error("DBField::saveInto() Called on a nameless '" . static::class . "' object", E_USER_ERROR);
} }
} }

View File

@ -3,7 +3,6 @@
namespace SilverStripe\ORM\FieldType; namespace SilverStripe\ORM\FieldType;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Object;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\Forms\FormField; use SilverStripe\Forms\FormField;
use SilverStripe\Forms\TextField; use SilverStripe\Forms\TextField;
@ -132,9 +131,8 @@ abstract class DBField extends ViewableData
public static function create_field($className, $value, $name = null, $object = null) public static function create_field($className, $value, $name = null, $object = null)
{ {
/** @var DBField $dbField */ /** @var DBField $dbField */
$dbField = Object::create($className, $name, $object); $dbField = Injector::inst()->create($className, $name, $object);
$dbField->setValue($value, null, false); $dbField->setValue($value, null, false);
return $dbField; return $dbField;
} }
@ -449,7 +447,7 @@ abstract class DBField extends ViewableData
$fieldName = $this->name; $fieldName = $this->name;
if (empty($fieldName)) { if (empty($fieldName)) {
throw new \BadMethodCallException( throw new \BadMethodCallException(
"DBField::saveInto() Called on a nameless '" . get_class($this) . "' object" "DBField::saveInto() Called on a nameless '" . static::class . "' object"
); );
} }
$dataObject->$fieldName = $this->value; $dataObject->$fieldName = $this->value;

View File

@ -71,7 +71,7 @@ class DBPolymorphicForeignKey extends DBComposite
if ($value instanceof DataObject) { if ($value instanceof DataObject) {
$value = array( $value = array(
'ID' => $value->ID, 'ID' => $value->ID,
'Class' => $value->class 'Class' => get_class($value),
); );
} }

View File

@ -2,7 +2,7 @@
namespace SilverStripe\ORM\Filters; namespace SilverStripe\ORM\Filters;
use SilverStripe\Core\Object; use SilverStripe\Core\Injector\Injectable;
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DataQuery; use SilverStripe\ORM\DataQuery;
use InvalidArgumentException; use InvalidArgumentException;
@ -23,8 +23,9 @@ use SilverStripe\ORM\FieldType\DBField;
* class: EndsWithFilter * class: EndsWithFilter
* </code> * </code>
*/ */
abstract class SearchFilter extends Object abstract class SearchFilter
{ {
use Injectable;
/** /**
* @var string Classname of the inspected {@link DataObject} * @var string Classname of the inspected {@link DataObject}
@ -79,7 +80,6 @@ abstract class SearchFilter extends Object
*/ */
public function __construct($fullName = null, $value = false, array $modifiers = array()) public function __construct($fullName = null, $value = false, array $modifiers = array())
{ {
parent::__construct();
$this->fullName = $fullName; $this->fullName = $fullName;
// sets $this->name and $this->relation // sets $this->name and $this->relation
@ -178,7 +178,7 @@ abstract class SearchFilter extends Object
$unsupported = array_diff($modifiers, $allowed); $unsupported = array_diff($modifiers, $allowed);
if ($unsupported) { if ($unsupported) {
throw new InvalidArgumentException( throw new InvalidArgumentException(
get_class($this) . ' does not accept ' . implode(', ', $unsupported) . ' as modifiers' static::class . ' does not accept ' . implode(', ', $unsupported) . ' as modifiers'
); );
} }
@ -258,7 +258,7 @@ abstract class SearchFilter extends Object
// Ensure that we're dealing with a DataObject. // Ensure that we're dealing with a DataObject.
if (!is_subclass_of($this->model, DataObject::class)) { if (!is_subclass_of($this->model, DataObject::class)) {
throw new InvalidArgumentException( throw new InvalidArgumentException(
"Model supplied to " . get_class($this) . " should be an instance of DataObject." "Model supplied to " . static::class . " should be an instance of DataObject."
); );
} }
$schema = DataObject::getSchema(); $schema = DataObject::getSchema();
@ -371,7 +371,7 @@ abstract class SearchFilter extends Object
*/ */
protected function applyMany(DataQuery $query) protected function applyMany(DataQuery $query)
{ {
throw new InvalidArgumentException(get_class($this) . " can't be used to filter by a list of items."); throw new InvalidArgumentException(static::class . " can't be used to filter by a list of items.");
} }
/** /**
@ -409,7 +409,7 @@ abstract class SearchFilter extends Object
*/ */
protected function excludeMany(DataQuery $query) protected function excludeMany(DataQuery $query)
{ {
throw new InvalidArgumentException(get_class($this) . " can't be used to filter by a list of items."); throw new InvalidArgumentException(static::class . " can't be used to filter by a list of items.");
} }
/** /**

View File

@ -122,10 +122,10 @@ class Hierarchy extends DataExtension
// Hierarchy is looping. // Hierarchy is looping.
$validationResult->addError( $validationResult->addError(
_t( _t(
'SilverStripe\\ORM\\Hierarchy\\Hierarchy.InfiniteLoopNotAllowed', __CLASS__ . '.InfiniteLoopNotAllowed',
'Infinite loop found within the "{type}" hierarchy. Please change the parent to resolve this', 'Infinite loop found within the "{type}" hierarchy. Please change the parent to resolve this',
'First argument is the class that makes up the hierarchy.', 'First argument is the class that makes up the hierarchy.',
array('type' => $owner->class) array('type' => get_class($owner))
), ),
'bad', 'bad',
'INFINITE_LOOP' 'INFINITE_LOOP'

View File

@ -3,7 +3,7 @@
namespace SilverStripe\ORM; namespace SilverStripe\ORM;
use BadMethodCallException; use BadMethodCallException;
use SilverStripe\Core\Object; use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\Queries\SQLSelect; use SilverStripe\ORM\Queries\SQLSelect;
use SilverStripe\ORM\Queries\SQLDelete; use SilverStripe\ORM\Queries\SQLDelete;
use SilverStripe\ORM\FieldType\DBComposite; use SilverStripe\ORM\FieldType\DBComposite;
@ -100,7 +100,7 @@ class ManyManyList extends RelationList
$finalized = array(); $finalized = array();
foreach ($this->extraFields as $field => $spec) { foreach ($this->extraFields as $field => $spec) {
$obj = Object::create_from_string($spec); $obj = Injector::inst()->create($spec);
if ($obj instanceof DBComposite) { if ($obj instanceof DBComposite) {
$this->_compositeExtraFields[$field] = array(); $this->_compositeExtraFields[$field] = array();
@ -146,7 +146,7 @@ class ManyManyList extends RelationList
} }
} }
$obj = Object::create_from_string($this->extraFields[$fieldName], $fieldName); $obj = Injector::inst()->create($this->extraFields[$fieldName], $fieldName);
$obj->setValue($value, null, false); $obj->setValue($value, null, false);
$add[$fieldName] = $obj; $add[$fieldName] = $obj;
} }
@ -281,7 +281,7 @@ class ManyManyList extends RelationList
foreach ($this->extraFields as $fieldName => $fieldSpec) { foreach ($this->extraFields as $fieldName => $fieldSpec) {
// Skip fields without an assignment // Skip fields without an assignment
if (array_key_exists($fieldName, $extraFields)) { if (array_key_exists($fieldName, $extraFields)) {
$fieldObject = Object::create_from_string($fieldSpec, $fieldName); $fieldObject = Injector::inst()->create($fieldSpec, $fieldName);
$fieldObject->setValue($extraFields[$fieldName]); $fieldObject->setValue($extraFields[$fieldName]);
$fieldObject->writeToManipulation($manipulation[$this->joinTable]); $fieldObject->writeToManipulation($manipulation[$this->joinTable]);
} }

View File

@ -98,8 +98,6 @@ class FulltextSearchable extends DataExtension
} else { } else {
$this->searchFields = $searchFields; $this->searchFields = $searchFields;
} }
parent::__construct();
} }
public static function get_extra_config($class, $extensionClass, $args) public static function get_extra_config($class, $extensionClass, $args)

View File

@ -4,7 +4,7 @@ namespace SilverStripe\ORM\Search;
use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPRequest;
use SilverStripe\Core\ClassInfo; use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Object; use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Forms\FieldList; use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\FormField; use SilverStripe\Forms\FormField;
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
@ -34,8 +34,9 @@ use Exception;
* *
* @see http://doc.silverstripe.com/doku.php?id=searchcontext * @see http://doc.silverstripe.com/doku.php?id=searchcontext
*/ */
class SearchContext extends Object class SearchContext
{ {
use Injectable;
/** /**
* DataObject subclass to which search parameters relate to. * DataObject subclass to which search parameters relate to.
@ -85,8 +86,6 @@ class SearchContext extends Object
$this->modelClass = $modelClass; $this->modelClass = $modelClass;
$this->fields = ($fields) ? $fields : new FieldList(); $this->fields = ($fields) ? $fields : new FieldList();
$this->filters = ($filters) ? $filters : array(); $this->filters = ($filters) ? $filters : array();
parent::__construct();
} }
/** /**
@ -136,6 +135,7 @@ class SearchContext extends Object
public function getQuery($searchParams, $sort = false, $limit = false, $existingQuery = null) public function getQuery($searchParams, $sort = false, $limit = false, $existingQuery = null)
{ {
/** DataList $query */ /** DataList $query */
$query = null;
if ($existingQuery) { if ($existingQuery) {
if (!($existingQuery instanceof DataList)) { if (!($existingQuery instanceof DataList)) {
throw new InvalidArgumentException("existingQuery must be DataList"); throw new InvalidArgumentException("existingQuery must be DataList");
@ -158,6 +158,7 @@ class SearchContext extends Object
$query = $query->limit($limit); $query = $query->limit($limit);
} }
/** @var DataList $query */
$query = $query->sort($sort); $query = $query->sort($sort);
// hack to work with $searchParems when it's an Object // hack to work with $searchParems when it's an Object

View File

@ -51,7 +51,7 @@ class UnsavedRelationList extends ArrayList implements Relation
/** /**
* Create a new UnsavedRelationList * Create a new UnsavedRelationList
* *
* @param array $baseClass * @param string $baseClass
* @param string $relationName * @param string $relationName
* @param string $dataClass The DataObject class used in the relation * @param string $dataClass The DataObject class used in the relation
*/ */

View File

@ -2,9 +2,10 @@
namespace SilverStripe\Security; namespace SilverStripe\Security;
use SilverStripe\Core\Object; use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Extensible;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Control\Controller; use SilverStripe\Control\Controller;
use SilverStripe\Dev\Deprecation;
use SilverStripe\Forms\Form; use SilverStripe\Forms\Form;
/** /**
@ -15,8 +16,16 @@ use SilverStripe\Forms\Form;
* *
* @author Markus Lanthaler <markus@silverstripe.com> * @author Markus Lanthaler <markus@silverstripe.com>
*/ */
abstract class Authenticator extends Object abstract class Authenticator
{ {
use Injectable;
use Configurable;
use Extensible;
public function __construct()
{
$this->constructExtensions();
}
/** /**
* This variable holds all authenticators that should be used * This variable holds all authenticators that should be used

View File

@ -2,7 +2,8 @@
namespace SilverStripe\Security; namespace SilverStripe\Security;
use SilverStripe\Core\Object; use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\ORM\ValidationResult; use SilverStripe\ORM\ValidationResult;
/** /**
@ -17,9 +18,15 @@ use SilverStripe\ORM\ValidationResult;
* Member::set_password_validator($pwdValidator); * Member::set_password_validator($pwdValidator);
* </code> * </code>
*/ */
class PasswordValidator extends Object class PasswordValidator
{ {
use Injectable;
use Configurable;
/**
* @config
* @var array
*/
private static $character_strength_tests = array( private static $character_strength_tests = array(
'lowercase' => '/[a-z]/', 'lowercase' => '/[a-z]/',
'uppercase' => '/[A-Z]/', 'uppercase' => '/[A-Z]/',

View File

@ -879,7 +879,7 @@ class Security extends Controller implements TemplateGlobalProvider
*/ */
public function getTemplatesFor($action) public function getTemplatesFor($action)
{ {
$templates = SSViewer::get_templates_by_class(get_class($this), "_{$action}", __CLASS__); $templates = SSViewer::get_templates_by_class(static::class, "_{$action}", __CLASS__);
return array_merge( return array_merge(
$templates, $templates,
[ [

View File

@ -3,7 +3,8 @@
namespace SilverStripe\Security; namespace SilverStripe\Security;
use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPRequest;
use SilverStripe\Core\Object; use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Control\Session; use SilverStripe\Control\Session;
use SilverStripe\Control\Controller; use SilverStripe\Control\Controller;
use SilverStripe\Forms\FieldList; use SilverStripe\Forms\FieldList;
@ -34,8 +35,10 @@ use SilverStripe\View\TemplateGlobalProvider;
* *
* @todo Make token name form specific for additional forgery protection. * @todo Make token name form specific for additional forgery protection.
*/ */
class SecurityToken extends Object implements TemplateGlobalProvider class SecurityToken implements TemplateGlobalProvider
{ {
use Configurable;
use Injectable;
/** /**
* @var string * @var string
@ -63,7 +66,6 @@ class SecurityToken extends Object implements TemplateGlobalProvider
public function __construct($name = null) public function __construct($name = null)
{ {
$this->name = ($name) ? $name : self::get_default_name(); $this->name = ($name) ? $name : self::get_default_name();
parent::__construct();
} }
/** /**

View File

@ -2,13 +2,16 @@
namespace SilverStripe\View\Parsers; namespace SilverStripe\View\Parsers;
use SilverStripe\Core\Object; use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Injector\Injectable;
/** /**
* Base class for HTML cleaning implementations. * Base class for HTML cleaning implementations.
*/ */
abstract class HTMLCleaner extends Object abstract class HTMLCleaner
{ {
use Configurable;
use Injectable;
/** /**
* @var array * @var array
@ -27,7 +30,6 @@ abstract class HTMLCleaner extends Object
*/ */
public function __construct($config = null) public function __construct($config = null)
{ {
parent::__construct();
if ($config) { if ($config) {
$config = array_merge($this->defaultConfig, $config); $config = array_merge($this->defaultConfig, $config);
} else { } else {

View File

@ -2,7 +2,7 @@
namespace SilverStripe\View\Parsers; namespace SilverStripe\View\Parsers;
use SilverStripe\Core\Object; use SilverStripe\Core\Injector\Injectable;
/** /**
* Format a SQL Query for better readable output in HTML or Plaintext. * Format a SQL Query for better readable output in HTML or Plaintext.
@ -12,8 +12,9 @@ use SilverStripe\Core\Object;
* *
* @author Ingo Schommer, Silverstripe Ltd. (<firstname>@silverstripe.com) * @author Ingo Schommer, Silverstripe Ltd. (<firstname>@silverstripe.com)
*/ */
class SQLFormatter extends Object class SQLFormatter
{ {
use Injectable;
protected static $newline_before_tokens = array( protected static $newline_before_tokens = array(
'SELECT', 'SELECT',

View File

@ -3,7 +3,9 @@
namespace SilverStripe\View\Parsers; namespace SilverStripe\View\Parsers;
use DOMNodeList; use DOMNodeList;
use SilverStripe\Core\Object; use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Extensible;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use InvalidArgumentException; use InvalidArgumentException;
use DOMElement; use DOMElement;
@ -16,8 +18,16 @@ use DOMElement;
* *
* @see http://doc.silverstripe.org/framework/en/reference/shortcodes * @see http://doc.silverstripe.org/framework/en/reference/shortcodes
*/ */
class ShortcodeParser extends Object class ShortcodeParser
{ {
use Injectable;
use Configurable;
use Extensible;
public function __construct()
{
$this->constructExtensions();
}
public function img_shortcode($attrs) public function img_shortcode($attrs)
{ {

View File

@ -2,7 +2,8 @@
namespace SilverStripe\View\Parsers; namespace SilverStripe\View\Parsers;
use SilverStripe\Core\Object; use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Injector\Injectable;
/** /**
* Support class for converting unicode strings into a suitable 7-bit ASCII equivalent. * Support class for converting unicode strings into a suitable 7-bit ASCII equivalent.
@ -14,8 +15,11 @@ use SilverStripe\Core\Object;
* $ascii = $tr->toASCII($unicode); * $ascii = $tr->toASCII($unicode);
* </code> * </code>
*/ */
class Transliterator extends Object class Transliterator
{ {
use Injectable;
use Configurable;
/** /**
* @config * @config
* @var boolean Allow the use of iconv() to perform transliteration. Set to false to disable. * @var boolean Allow the use of iconv() to perform transliteration. Set to false to disable.
@ -53,11 +57,11 @@ class Transliterator extends Object
'Õ'=>'O', 'Ö'=>'Oe', 'Ø'=>'O', 'Ù'=>'U', 'Ú'=>'U', 'Û'=>'U', 'Ü'=>'Ue', 'Ý'=>'Y', 'Þ'=>'B', 'ß'=>'ss', 'Õ'=>'O', 'Ö'=>'Oe', 'Ø'=>'O', 'Ù'=>'U', 'Ú'=>'U', 'Û'=>'U', 'Ü'=>'Ue', 'Ý'=>'Y', 'Þ'=>'B', 'ß'=>'ss',
'à'=>'a', 'á'=>'a', 'â'=>'a', 'ã'=>'a', 'ä'=>'ae', 'å'=>'a', 'æ'=>'ae', 'ç'=>'c', 'è'=>'e', 'é'=>'e', 'à'=>'a', 'á'=>'a', 'â'=>'a', 'ã'=>'a', 'ä'=>'ae', 'å'=>'a', 'æ'=>'ae', 'ç'=>'c', 'è'=>'e', 'é'=>'e',
'ê'=>'e', 'ë'=>'e', 'ì'=>'i', 'í'=>'i', 'î'=>'i', 'ï'=>'i', 'ð'=>'o', 'ñ'=>'n', 'ò'=>'o', 'ó'=>'o', 'ê'=>'e', 'ë'=>'e', 'ì'=>'i', 'í'=>'i', 'î'=>'i', 'ï'=>'i', 'ð'=>'o', 'ñ'=>'n', 'ò'=>'o', 'ó'=>'o',
'ô'=>'o', 'õ'=>'o', 'ö'=>'oe', 'ø'=>'o', 'ù'=>'u', 'ú'=>'u', 'û'=>'u', 'ü'=>'ue', 'ý'=>'y', 'ý'=>'y', 'ô'=>'o', 'õ'=>'o', 'ö'=>'oe', 'ø'=>'o', 'ù'=>'u', 'ú'=>'u', 'û'=>'u', 'ü'=>'ue', 'ý'=>'y',
'þ'=>'b', 'ÿ'=>'y', 'Ŕ'=>'R', 'ŕ'=>'r', 'þ'=>'b', 'ÿ'=>'y', 'Ŕ'=>'R', 'ŕ'=>'r',
'Ā'=>'A', 'ā'=>'a', 'Ē'=>'E', 'ē'=>'e', 'Ī'=>'I', 'ī'=>'i', 'Ō'=>'O', 'ō'=>'o', 'Ū'=>'U', 'ū'=>'u', 'Ā'=>'A', 'ā'=>'a', 'Ē'=>'E', 'ē'=>'e', 'Ī'=>'I', 'ī'=>'i', 'Ō'=>'O', 'ō'=>'o', 'Ū'=>'U', 'ū'=>'u',
'œ'=>'oe', 'ß'=>'ss', 'ij'=>'ij', 'ą'=>'a','ę'=>'e', 'ė'=>'e', 'į'=>'i','=>'u','=>'u', 'Ą'=>'A', 'œ'=>'oe', 'ij'=>'ij', 'ą'=>'a','ę'=>'e', 'ė'=>'e', 'į'=>'i', '=>'u', 'Ą'=>'A',
'Ę'=>'E', 'Ė'=>'E', 'Į'=>'I','Ų'=>'U','Ū'=>'U', 'Ę'=>'E', 'Ė'=>'E', 'Į'=>'I','Ų'=>'U',
"ľ"=>"l", "Ľ"=>"L", "ť"=>"t", "Ť"=>"T", "ů"=>"u", "Ů"=>"U", "ľ"=>"l", "Ľ"=>"L", "ť"=>"t", "Ť"=>"T", "ů"=>"u", "Ů"=>"U",
'ł'=>'l', 'Ł'=>'L', 'ń'=>'n', 'Ń'=>'N', 'ś'=>'s', 'Ś'=>'S', 'ź'=>'z', 'Ź'=>'Z', 'ż'=>'z', 'Ż'=>'Z', 'ł'=>'l', 'Ł'=>'L', 'ń'=>'n', 'Ń'=>'N', 'ś'=>'s', 'Ś'=>'S', 'ź'=>'z', 'Ź'=>'Z', 'ż'=>'z', 'Ż'=>'Z',
'а'=>"a",'б'=>"b",'в'=>"v",'г'=>"g",'д'=>"d",'е'=>"e",'ё'=>"yo",'ж'=>"zh",'з'=>"z",'и'=>"i", 'а'=>"a",'б'=>"b",'в'=>"v",'г'=>"g",'д'=>"d",'е'=>"e",'ё'=>"yo",'ж'=>"zh",'з'=>"z",'и'=>"i",

View File

@ -2,7 +2,8 @@
namespace SilverStripe\View\Parsers; namespace SilverStripe\View\Parsers;
use SilverStripe\Core\Object; use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Injector\Injectable;
/** /**
* Filter certain characters from "URL segments" (also called "slugs"), for nicer (more SEO-friendly) URLs. * Filter certain characters from "URL segments" (also called "slugs"), for nicer (more SEO-friendly) URLs.
@ -14,8 +15,10 @@ use SilverStripe\Core\Object;
* *
* See {@link FileNameFilter} for similar implementation for filesystem-based URLs. * See {@link FileNameFilter} for similar implementation for filesystem-based URLs.
*/ */
class URLSegmentFilter extends Object class URLSegmentFilter
{ {
use Configurable;
use Injectable;
/** /**
* @config * @config

View File

@ -313,7 +313,7 @@ class SSViewer implements Flushable
/** /**
* Returns true if at least one of the listed templates exists. * Returns true if at least one of the listed templates exists.
* *
* @param array $templates * @param array|string $templates
* *
* @return boolean * @return boolean
*/ */

View File

@ -5,7 +5,6 @@ namespace SilverStripe\View;
use InvalidArgumentException; use InvalidArgumentException;
use SilverStripe\Core\ClassInfo; use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Object;
/** /**
* This extends SSViewer_Scope to mix in data on top of what the item provides. This can be "global" * This extends SSViewer_Scope to mix in data on top of what the item provides. This can be "global"
@ -304,7 +303,7 @@ class SSViewer_DataPresenter extends SSViewer_Scope
if ($val) { if ($val) {
$obj = $val['obj']; $obj = $val['obj'];
if ($name === 'hasValue') { if ($name === 'hasValue') {
$res = $obj instanceof Object $res = $obj instanceof ViewableData
? $obj->exists() ? $obj->exists()
: (bool)$obj; : (bool)$obj;
} else { } else {

View File

@ -2,7 +2,10 @@
namespace SilverStripe\View; namespace SilverStripe\View;
use SilverStripe\Core\Object; use Exception;
use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Extensible;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\ORM\ArrayLib; use SilverStripe\ORM\ArrayLib;
use SilverStripe\ORM\FieldType\DBField; use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\FieldType\DBHTMLText; use SilverStripe\ORM\FieldType\DBHTMLText;
@ -23,8 +26,13 @@ use ArrayIterator;
* is provided and automatically escaped by ViewableData. Any class that needs to be available to a view (controllers, * is provided and automatically escaped by ViewableData. Any class that needs to be available to a view (controllers,
* {@link DataObject}s, page controls) should inherit from this class. * {@link DataObject}s, page controls) should inherit from this class.
*/ */
class ViewableData extends Object implements IteratorAggregate class ViewableData implements IteratorAggregate
{ {
use Extensible {
defineMethods as extensibleDefineMethods;
}
use Injectable;
use Configurable;
/** /**
* An array of objects to cast certain fields to. This is set up as an array in the format: * An array of objects to cast certain fields to. This is set up as an array in the format:
@ -75,6 +83,11 @@ class ViewableData extends Object implements IteratorAggregate
*/ */
private $objCache = array(); private $objCache = array();
public function __construct()
{
$this->constructExtensions();
}
// ----------------------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------------------
// FIELD GETTERS & SETTERS ----------------------------------------------------------------------------------------- // FIELD GETTERS & SETTERS -----------------------------------------------------------------------------------------
@ -218,11 +231,12 @@ class ViewableData extends Object implements IteratorAggregate
$this->addMethodsFrom('failover'); $this->addMethodsFrom('failover');
if (isset($_REQUEST['debugfailover'])) { if (isset($_REQUEST['debugfailover'])) {
Debug::message("$this->class created with a failover class of {$this->failover->class}"); $class = static::class;
$failoverClass = get_class($this->failover);
Debug::message("$class created with a failover class of {$failoverClass}");
} }
} }
$this->extensibleDefineMethods();
parent::defineMethods();
} }
/** /**
@ -249,6 +263,27 @@ class ViewableData extends Object implements IteratorAggregate
); );
} }
/**
* Return true if this object "exists" i.e. has a sensible value
*
* This method should be overriden in subclasses to provide more context about the classes state. For example, a
* {@link DataObject} class could return false when it is deleted from the database
*
* @return bool
*/
public function exists()
{
return true;
}
/**
* @return string the class name
*/
public function __toString()
{
return static::class;
}
/** /**
* @return ViewableData * @return ViewableData
*/ */
@ -273,6 +308,7 @@ class ViewableData extends Object implements IteratorAggregate
* *
* @param string $field * @param string $field
* @return string Casting helper As a constructor pattern, and may include arguments. * @return string Casting helper As a constructor pattern, and may include arguments.
* @throws Exception
*/ */
public function castingHelper($field) public function castingHelper($field)
{ {
@ -295,7 +331,7 @@ class ViewableData extends Object implements IteratorAggregate
// Fall back to default_cast // Fall back to default_cast
$default = $this->config()->get('default_cast'); $default = $this->config()->get('default_cast');
if (empty($default)) { if (empty($default)) {
throw new \Exception("No default_cast"); throw new Exception("No default_cast");
} }
return $default; return $default;
} }
@ -448,7 +484,7 @@ class ViewableData extends Object implements IteratorAggregate
if (!is_object($value)) { if (!is_object($value)) {
// Force cast // Force cast
$castingHelper = $this->castingHelper($fieldName); $castingHelper = $this->castingHelper($fieldName);
$valueObject = Object::create_from_string($castingHelper, $fieldName); $valueObject = Injector::inst()->create($castingHelper, $fieldName);
$valueObject->setValue($value, $this); $valueObject->setValue($value, $this);
$value = $valueObject; $value = $valueObject;
} }
@ -564,7 +600,7 @@ class ViewableData extends Object implements IteratorAggregate
public function CSSClasses($stopAtClass = self::class) public function CSSClasses($stopAtClass = self::class)
{ {
$classes = array(); $classes = array();
$classAncestry = array_reverse(ClassInfo::ancestry($this->class)); $classAncestry = array_reverse(ClassInfo::ancestry(static::class));
$stopClasses = ClassInfo::ancestry($stopAtClass); $stopClasses = ClassInfo::ancestry($stopAtClass);
foreach ($classAncestry as $class) { foreach ($classAncestry as $class) {

View File

@ -42,15 +42,16 @@ class ViewableData_Debugger extends ViewableData
public function forTemplate($field = null) public function forTemplate($field = null)
{ {
// debugging info for a specific field // debugging info for a specific field
$class = get_class($this->object);
if ($field) { if ($field) {
return "<b>Debugging Information for {$this->class}->{$field}</b><br/>" . return "<b>Debugging Information for {$class}->{$field}</b><br/>" .
($this->object->hasMethod($field) ? "Has method '$field'<br/>" : null) . ($this->object->hasMethod($field) ? "Has method '$field'<br/>" : null) .
($this->object->hasField($field) ? "Has field '$field'<br/>" : null); ($this->object->hasField($field) ? "Has field '$field'<br/>" : null);
} }
// debugging information for the entire class // debugging information for the entire class
$reflector = new ReflectionObject($this->object); $reflector = new ReflectionObject($this->object);
$debug = "<b>Debugging Information: all methods available in '{$this->object->class}'</b><br/><ul>"; $debug = "<b>Debugging Information: all methods available in '{$class}'</b><br/><ul>";
foreach ($this->object->allMethodNames() as $method) { foreach ($this->object->allMethodNames() as $method) {
// check that the method is public // check that the method is public
@ -74,7 +75,7 @@ class ViewableData_Debugger extends ViewableData
$debug .= '</ul>'; $debug .= '</ul>';
if ($this->object->hasMethod('toMap')) { if ($this->object->hasMethod('toMap')) {
$debug .= "<b>Debugging Information: all fields available in '{$this->object->class}'</b><br/><ul>"; $debug .= "<b>Debugging Information: all fields available in '{$class}'</b><br/><ul>";
foreach ($this->object->toMap() as $field => $value) { foreach ($this->object->toMap() as $field => $value) {
$debug .= "<li>\$$field</li>"; $debug .= "<li>\$$field</li>";

View File

@ -2,7 +2,7 @@
namespace SilverStripe\Core\Tests; namespace SilverStripe\Core\Tests;
use SilverStripe\Core\Object; use ReflectionException;
use SilverStripe\Core\Tests\ClassInfoTest\BaseClass; use SilverStripe\Core\Tests\ClassInfoTest\BaseClass;
use SilverStripe\Core\Tests\ClassInfoTest\BaseDataClass; use SilverStripe\Core\Tests\ClassInfoTest\BaseDataClass;
use SilverStripe\Core\Tests\ClassInfoTest\ChildClass; use SilverStripe\Core\Tests\ClassInfoTest\ChildClass;
@ -39,8 +39,8 @@ class ClassInfoTest extends SapphireTest
public function testExists() public function testExists()
{ {
$this->assertTrue(ClassInfo::exists('SilverStripe\\Core\\Object')); $this->assertTrue(ClassInfo::exists(ClassInfo::class));
$this->assertTrue(ClassInfo::exists('SilverStripe\\Core\\object')); $this->assertTrue(ClassInfo::exists('SilverStripe\\Core\\classinfo'));
$this->assertTrue(ClassInfo::exists('SilverStripe\\Core\\Tests\\ClassInfoTest')); $this->assertTrue(ClassInfo::exists('SilverStripe\\Core\\Tests\\ClassInfoTest'));
$this->assertTrue(ClassInfo::exists('SilverStripe\\Core\\Tests\\CLASSINFOTEST')); $this->assertTrue(ClassInfo::exists('SilverStripe\\Core\\Tests\\CLASSINFOTEST'));
$this->assertTrue(ClassInfo::exists('stdClass')); $this->assertTrue(ClassInfo::exists('stdClass'));
@ -89,7 +89,8 @@ class ClassInfoTest extends SapphireTest
public function testNonClassName() public function testNonClassName()
{ {
$this->setExpectedException('ReflectionException', 'Class IAmAClassThatDoesNotExist does not exist'); $this->expectException(ReflectionException::class);
$this->expectExceptionMessage('Class IAmAClassThatDoesNotExist does not exist');
$this->assertEquals('IAmAClassThatDoesNotExist', ClassInfo::class_name('IAmAClassThatDoesNotExist')); $this->assertEquals('IAmAClassThatDoesNotExist', ClassInfo::class_name('IAmAClassThatDoesNotExist'));
} }
@ -117,15 +118,12 @@ class ClassInfoTest extends SapphireTest
public function testAncestry() public function testAncestry()
{ {
$ancestry = ClassInfo::ancestry(ChildClass::class); $ancestry = ClassInfo::ancestry(ChildClass::class);
$expect = ArrayLib::valuekey( $expect = ArrayLib::valuekey([
array(
Object::class,
ViewableData::class, ViewableData::class,
DataObject::class, DataObject::class,
BaseClass::class, BaseClass::class,
ChildClass::class, ChildClass::class,
) ]);
);
$this->assertEquals($expect, $ancestry); $this->assertEquals($expect, $ancestry);
ClassInfo::reset_db_cache(); ClassInfo::reset_db_cache();

View File

@ -3,7 +3,6 @@
namespace SilverStripe\Core\Tests\Config; namespace SilverStripe\Core\Tests\Config;
use SilverStripe\Config\MergeStrategy\Priority; use SilverStripe\Config\MergeStrategy\Priority;
use SilverStripe\Core\Object;
use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Config;
use SilverStripe\Dev\SapphireTest; use SilverStripe\Dev\SapphireTest;
@ -260,21 +259,6 @@ class ConfigTest extends SapphireTest
); );
} }
public function testStaticLookup()
{
$this->assertEquals(Object::static_lookup(ConfigTest\DefinesFoo::class, 'foo'), 1);
$this->assertEquals(Object::static_lookup(ConfigTest\DefinesFoo::class, 'bar'), null);
$this->assertEquals(Object::static_lookup(ConfigTest\DefinesBar::class, 'foo'), null);
$this->assertEquals(Object::static_lookup(ConfigTest\DefinesBar::class, 'bar'), 2);
$this->assertEquals(Object::static_lookup(ConfigTest\DefinesFooAndBar::class, 'foo'), 3);
$this->assertEquals(Object::static_lookup(ConfigTest\DefinesFooAndBar::class, 'bar'), 3);
$this->assertEquals(Object::static_lookup(ConfigTest\DefinesFooDoesntExtendObject::class, 'foo'), 4);
$this->assertEquals(Object::static_lookup(ConfigTest\DefinesFooDoesntExtendObject::class, 'bar'), null);
}
public function testForClass() public function testForClass()
{ {
$config = ConfigTest\DefinesFoo::config(); $config = ConfigTest\DefinesFoo::config();

View File

@ -0,0 +1,11 @@
<?php
namespace SilverStripe\Core\Tests\Config\ConfigTest;
use SilverStripe\Core\Config\Configurable;
use SilverStripe\Dev\TestOnly;
class BaseObject implements TestOnly
{
use Configurable;
}

View File

@ -2,10 +2,7 @@
namespace SilverStripe\Core\Tests\Config\ConfigTest; namespace SilverStripe\Core\Tests\Config\ConfigTest;
use SilverStripe\Core\Object; class DefinesFoo extends BaseObject
use SilverStripe\Dev\TestOnly;
class DefinesFoo extends Object implements TestOnly
{ {
protected static $foo = 1; protected static $foo = 1;

View File

@ -2,10 +2,7 @@
namespace SilverStripe\Core\Tests\Config\ConfigTest; namespace SilverStripe\Core\Tests\Config\ConfigTest;
use SilverStripe\Core\Object; class TestNest extends BaseObject
use SilverStripe\Dev\TestOnly;
class TestNest extends Object implements TestOnly
{ {
/** /**
* @config * @config

View File

@ -2,8 +2,10 @@
namespace SilverStripe\Core\Tests\Injector\InjectorTest; namespace SilverStripe\Core\Tests\Injector\InjectorTest;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Injector\InjectionCreator; use SilverStripe\Core\Injector\InjectionCreator;
use SilverStripe\Core\Object; use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\TestOnly;
/** /**
* An example object creator that uses the SilverStripe class(arguments) mechanism for * An example object creator that uses the SilverStripe class(arguments) mechanism for
@ -11,8 +13,11 @@ use SilverStripe\Core\Object;
* *
* @see https://github.com/silverstripe/sapphire * @see https://github.com/silverstripe/sapphire
*/ */
class SSObjectCreator extends InjectionCreator class SSObjectCreator extends InjectionCreator implements TestOnly
{ {
/**
* @var Injector
*/
private $injector; private $injector;
public function __construct($injector) public function __construct($injector)
@ -25,7 +30,7 @@ class SSObjectCreator extends InjectionCreator
if (strpos($class, '(') === false) { if (strpos($class, '(') === false) {
return parent::create($class, $params); return parent::create($class, $params);
} else { } else {
list($class, $params) = Object::parse_class_spec($class); list($class, $params) = ClassInfo::parse_class_spec($class);
$params = $this->injector->convertServiceProperty($params); $params = $this->injector->convertServiceProperty($params);
return parent::create($class, $params); return parent::create($class, $params);
} }

View File

@ -154,7 +154,7 @@ class ClassManifestTest extends SapphireTest
*/ */
public function testManifestWarnsAboutDuplicateClasses() public function testManifestWarnsAboutDuplicateClasses()
{ {
$this->setExpectedException(Exception::class); $this->expectException(Exception::class);
new ClassManifest(dirname(__FILE__) . '/fixtures/classmanifest_duplicates', false); new ClassManifest(dirname(__FILE__) . '/fixtures/classmanifest_duplicates', false);
} }
} }

View File

@ -12,7 +12,7 @@ use SilverStripe\Control\HTTPRequest as Request, SilverStripe\Control\HTTPRespon
/** @skipUpgrade */ /** @skipUpgrade */
use silverstripe\test\ClassA; use silverstripe\test\ClassA;
/** @skipUpgrade */ /** @skipUpgrade */
use \SilverStripe\Core\Object; use \SilverStripe\Core\ClassInfo;
/** @skipUpgrade */ /** @skipUpgrade */
class ClassI extends ModelAdmin implements P { class ClassI extends ModelAdmin implements P {

View File

@ -2,7 +2,7 @@
namespace SilverStripe\Core\Tests; namespace SilverStripe\Core\Tests;
use SilverStripe\Core\Object; use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Tests\ObjectTest\ExtendTest1; use SilverStripe\Core\Tests\ObjectTest\ExtendTest1;
use SilverStripe\Core\Tests\ObjectTest\ExtendTest2; use SilverStripe\Core\Tests\ObjectTest\ExtendTest2;
@ -52,7 +52,7 @@ class ObjectTest extends SapphireTest
foreach ($trueMethods as $method) { foreach ($trueMethods as $method) {
$methodU = strtoupper($method); $methodU = strtoupper($method);
$methodL = strtoupper($method); $methodL = strtoupper($method);
$this->assertTrue($obj->hasMethod($method), "Test that obj#$i has method $method ($obj->class)"); $this->assertTrue($obj->hasMethod($method), "Test that obj#$i has method $method");
$this->assertTrue($obj->hasMethod($methodU), "Test that obj#$i has method $methodU"); $this->assertTrue($obj->hasMethod($methodU), "Test that obj#$i has method $methodU");
$this->assertTrue($obj->hasMethod($methodL), "Test that obj#$i has method $methodL"); $this->assertTrue($obj->hasMethod($methodL), "Test that obj#$i has method $methodL");
@ -73,32 +73,21 @@ class ObjectTest extends SapphireTest
public function testSingletonCreation() public function testSingletonCreation()
{ {
$myObject = singleton(MyObject::class); $myObject = MyObject::singleton();
$this->assertEquals( $this->assertInstanceOf(
$myObject->class,
MyObject::class, MyObject::class,
$myObject,
'singletons are creating a correct class instance' 'singletons are creating a correct class instance'
); );
$this->assertEquals( $mySubObject = MySubObject::singleton();
get_class($myObject), $this->assertInstanceOf(
MyObject::class,
'singletons are creating a correct class instance'
);
$mySubObject = singleton(MySubObject::class);
$this->assertEquals(
$mySubObject->class,
MySubObject::class,
'singletons are creating a correct subclass instance'
);
$this->assertEquals(
get_class($mySubObject),
MySubObject::class, MySubObject::class,
$mySubObject,
'singletons are creating a correct subclass instance' 'singletons are creating a correct subclass instance'
); );
$myFirstObject = singleton(MyObject::class); $myFirstObject = MyObject::singleton();
$mySecondObject = singleton(MyObject::class); $mySecondObject = MyObject::singleton();
$this->assertTrue( $this->assertTrue(
$myFirstObject === $mySecondObject, $myFirstObject === $mySecondObject,
'singletons are using the same object on subsequent calls' 'singletons are using the same object on subsequent calls'
@ -182,14 +171,14 @@ class ObjectTest extends SapphireTest
'SilverStripe\\Core\\Tests\\oBjEcTTEST\\EXTENDTest1', 'SilverStripe\\Core\\Tests\\oBjEcTTEST\\EXTENDTest1',
"SilverStripe\\Core\\Tests\\ObjectTest\\ExtendTest2", "SilverStripe\\Core\\Tests\\ObjectTest\\ExtendTest2",
), ),
Object::get_extensions(ExtensionTest::class) ExtensionTest::get_extensions()
); );
$this->assertEquals( $this->assertEquals(
array( array(
'SilverStripe\\Core\\Tests\\oBjEcTTEST\\EXTENDTest1', 'SilverStripe\\Core\\Tests\\oBjEcTTEST\\EXTENDTest1',
"SilverStripe\\Core\\Tests\\ObjectTest\\ExtendTest2('FOO', 'BAR')", "SilverStripe\\Core\\Tests\\ObjectTest\\ExtendTest2('FOO', 'BAR')",
), ),
Object::get_extensions(ExtensionTest::class, true) ExtensionTest::get_extensions(null, true)
); );
$inst = new ExtensionTest(); $inst = new ExtensionTest();
$extensions = $inst->getExtensionInstances(); $extensions = $inst->getExtensionInstances();
@ -336,7 +325,7 @@ class ObjectTest extends SapphireTest
ObjectTest\ExtensionRemoveTest::remove_extension(ExtendTest2::class); ObjectTest\ExtensionRemoveTest::remove_extension(ExtendTest2::class);
$this->assertFalse( $this->assertFalse(
Object::has_extension(ExtensionRemoveTest::class, ExtendTest2::class), ExtensionRemoveTest::has_extension(ExtendTest2::class),
"Extension added through \$add_extension() are detected as removed in has_extension()" "Extension added through \$add_extension() are detected as removed in has_extension()"
); );
@ -347,14 +336,9 @@ class ObjectTest extends SapphireTest
); );
} }
public function testParentClass()
{
$this->assertEquals(ObjectTest\MyObject::create()->parentClass(), 'SilverStripe\\Core\\Object');
}
public function testIsA() public function testIsA()
{ {
$this->assertTrue(ObjectTest\MyObject::create() instanceof Object); $this->assertTrue(ObjectTest\MyObject::create() instanceof ObjectTest\BaseObject);
$this->assertTrue(ObjectTest\MyObject::create() instanceof ObjectTest\MyObject); $this->assertTrue(ObjectTest\MyObject::create() instanceof ObjectTest\MyObject);
} }
@ -369,30 +353,6 @@ class ObjectTest extends SapphireTest
$this->assertTrue($obj->getExtensionInstance(TestExtension::class) instanceof ObjectTest\TestExtension); $this->assertTrue($obj->getExtensionInstance(TestExtension::class) instanceof ObjectTest\TestExtension);
} }
public function testCacheToFile()
{
$this->markTestIncomplete();
/*
// This doesn't run properly on our build slave.
$obj = new ObjectTest_CacheTest();
$obj->clearCache('cacheMethod');
$obj->clearCache('cacheMethod', null, array(true));
$obj->clearCache('incNumber');
$this->assertEquals('noarg', $obj->cacheToFile('cacheMethod', -1));
$this->assertEquals('hasarg', $obj->cacheToFile('cacheMethod', -1, null, array(true)));
$this->assertEquals('hasarg', $obj->cacheToFile('cacheMethod', 3600, null, array(true)));
// -1 lifetime will ensure that the cache isn't read - number incremented
$this->assertEquals(1, $obj->cacheToFile('incNumber', -1));
// -1 lifetime will ensure that the cache isn't read - number incremented
$this->assertEquals(2, $obj->cacheToFile('incNumber', -1));
// Number shouldn't be incremented now because we're using the cached version
$this->assertEquals(2, $obj->cacheToFile('incNumber'));
*/
}
public function testExtend() public function testExtend()
{ {
$object = new ObjectTest\ExtendTest(); $object = new ObjectTest\ExtendTest();
@ -434,52 +394,52 @@ class ObjectTest extends SapphireTest
// Simple case // Simple case
$this->assertEquals( $this->assertEquals(
array(Versioned::class,array('Stage', 'Live')), array(Versioned::class,array('Stage', 'Live')),
Object::parse_class_spec("SilverStripe\\Versioned\\Versioned('Stage','Live')") ClassInfo::parse_class_spec("SilverStripe\\Versioned\\Versioned('Stage','Live')")
); );
// String with commas // String with commas
$this->assertEquals( $this->assertEquals(
array(Versioned::class,array('Stage,Live', 'Stage')), array(Versioned::class,array('Stage,Live', 'Stage')),
Object::parse_class_spec("SilverStripe\\Versioned\\Versioned('Stage,Live','Stage')") ClassInfo::parse_class_spec("SilverStripe\\Versioned\\Versioned('Stage,Live','Stage')")
); );
// String with quotes // String with quotes
$this->assertEquals( $this->assertEquals(
array(Versioned::class,array('Stage\'Stage,Live\'Live', 'Live')), array(Versioned::class,array('Stage\'Stage,Live\'Live', 'Live')),
Object::parse_class_spec("SilverStripe\\Versioned\\Versioned('Stage\\'Stage,Live\\'Live','Live')") ClassInfo::parse_class_spec("SilverStripe\\Versioned\\Versioned('Stage\\'Stage,Live\\'Live','Live')")
); );
// True, false and null values // True, false and null values
$this->assertEquals( $this->assertEquals(
array('ClassName', array('string', true, array('string', false))), array('ClassName', array('string', true, array('string', false))),
Object::parse_class_spec('ClassName("string", true, array("string", false))') ClassInfo::parse_class_spec('ClassName("string", true, array("string", false))')
); );
$this->assertEquals( $this->assertEquals(
array('ClassName', array(true, false, null)), array('ClassName', array(true, false, null)),
Object::parse_class_spec('ClassName(true, false, null)') ClassInfo::parse_class_spec('ClassName(true, false, null)')
); );
// Array // Array
$this->assertEquals( $this->assertEquals(
array('Enum',array(array('Accepted', 'Pending', 'Declined', 'Unsubmitted'), 'Unsubmitted')), array('Enum',array(array('Accepted', 'Pending', 'Declined', 'Unsubmitted'), 'Unsubmitted')),
Object::parse_class_spec("Enum(array('Accepted', 'Pending', 'Declined', 'Unsubmitted'), 'Unsubmitted')") ClassInfo::parse_class_spec("Enum(array('Accepted', 'Pending', 'Declined', 'Unsubmitted'), 'Unsubmitted')")
); );
// Nested array // Nested array
$this->assertEquals( $this->assertEquals(
array('Enum',array(array('Accepted', 'Pending', 'Declined', array('UnsubmittedA','UnsubmittedB')), array('Enum',array(array('Accepted', 'Pending', 'Declined', array('UnsubmittedA','UnsubmittedB')),
'Unsubmitted')), 'Unsubmitted')),
Object::parse_class_spec( ClassInfo::parse_class_spec(
"Enum(array('Accepted', 'Pending', 'Declined', array('UnsubmittedA','UnsubmittedB')), 'Unsubmitted')" "Enum(array('Accepted', 'Pending', 'Declined', array('UnsubmittedA','UnsubmittedB')), 'Unsubmitted')"
) )
); );
// 5.4 Shorthand Array // 5.4 Shorthand Array
$this->assertEquals( $this->assertEquals(
array('Enum',array(array('Accepted', 'Pending', 'Declined', 'Unsubmitted'), 'Unsubmitted')), array('Enum',array(array('Accepted', 'Pending', 'Declined', 'Unsubmitted'), 'Unsubmitted')),
Object::parse_class_spec("Enum(['Accepted', 'Pending', 'Declined', 'Unsubmitted'], 'Unsubmitted')") ClassInfo::parse_class_spec("Enum(['Accepted', 'Pending', 'Declined', 'Unsubmitted'], 'Unsubmitted')")
); );
// 5.4 Nested shorthand array // 5.4 Nested shorthand array
$this->assertEquals( $this->assertEquals(
array('Enum',array(array('Accepted', 'Pending', 'Declined', array('UnsubmittedA','UnsubmittedB')), array('Enum',array(array('Accepted', 'Pending', 'Declined', array('UnsubmittedA','UnsubmittedB')),
'Unsubmitted')), 'Unsubmitted')),
Object::parse_class_spec( ClassInfo::parse_class_spec(
"Enum(['Accepted', 'Pending', 'Declined', ['UnsubmittedA','UnsubmittedB']], 'Unsubmitted')" "Enum(['Accepted', 'Pending', 'Declined', ['UnsubmittedA','UnsubmittedB']], 'Unsubmitted')"
) )
); );
@ -487,33 +447,33 @@ class ObjectTest extends SapphireTest
// Associative array // Associative array
$this->assertEquals( $this->assertEquals(
array('Varchar', array(255, array('nullifyEmpty' => false))), array('Varchar', array(255, array('nullifyEmpty' => false))),
Object::parse_class_spec("Varchar(255, array('nullifyEmpty' => false))") ClassInfo::parse_class_spec("Varchar(255, array('nullifyEmpty' => false))")
); );
// Nested associative array // Nested associative array
$this->assertEquals( $this->assertEquals(
array('Test', array('string', array('nested' => array('foo' => 'bar')))), array('Test', array('string', array('nested' => array('foo' => 'bar')))),
Object::parse_class_spec("Test('string', array('nested' => array('foo' => 'bar')))") ClassInfo::parse_class_spec("Test('string', array('nested' => array('foo' => 'bar')))")
); );
// 5.4 shorthand associative array // 5.4 shorthand associative array
$this->assertEquals( $this->assertEquals(
array('Varchar', array(255, array('nullifyEmpty' => false))), array('Varchar', array(255, array('nullifyEmpty' => false))),
Object::parse_class_spec("Varchar(255, ['nullifyEmpty' => false])") ClassInfo::parse_class_spec("Varchar(255, ['nullifyEmpty' => false])")
); );
// 5.4 shorthand nested associative array // 5.4 shorthand nested associative array
$this->assertEquals( $this->assertEquals(
array('Test', array('string', array('nested' => array('foo' => 'bar')))), array('Test', array('string', array('nested' => array('foo' => 'bar')))),
Object::parse_class_spec("Test('string', ['nested' => ['foo' => 'bar']])") ClassInfo::parse_class_spec("Test('string', ['nested' => ['foo' => 'bar']])")
); );
// Namespaced class // Namespaced class
$this->assertEquals( $this->assertEquals(
array('Test\MyClass', array()), array('Test\MyClass', array()),
Object::parse_class_spec('Test\MyClass') ClassInfo::parse_class_spec('Test\MyClass')
); );
// Fully qualified namespaced class // Fully qualified namespaced class
$this->assertEquals( $this->assertEquals(
array('\Test\MyClass', array()), array('\Test\MyClass', array()),
Object::parse_class_spec('\Test\MyClass') ClassInfo::parse_class_spec('\Test\MyClass')
); );
} }
} }

View File

@ -0,0 +1,20 @@
<?php
namespace SilverStripe\Core\Tests\ObjectTest;
use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Extensible;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Dev\TestOnly;
class BaseObject implements TestOnly
{
use Extensible;
use Configurable;
use Injectable;
public function __construct()
{
$this->constructExtensions();
}
}

View File

@ -2,11 +2,8 @@
namespace SilverStripe\Core\Tests\ObjectTest; namespace SilverStripe\Core\Tests\ObjectTest;
use SilverStripe\Core\Object; class CacheTest extends BaseObject
class CacheTest extends Object
{ {
public $count = 0; public $count = 0;
public function cacheMethod($arg1 = null) public function cacheMethod($arg1 = null)

View File

@ -2,9 +2,7 @@
namespace SilverStripe\Core\Tests\ObjectTest; namespace SilverStripe\Core\Tests\ObjectTest;
use SilverStripe\Core\Object; class CreateTest extends BaseObject
class CreateTest extends Object
{ {
public $constructArguments; public $constructArguments;

View File

@ -2,8 +2,6 @@
namespace SilverStripe\Core\Tests\ObjectTest; namespace SilverStripe\Core\Tests\ObjectTest;
use SilverStripe\Core\Object; class CreateTest2 extends BaseObject
class CreateTest2 extends Object
{ {
} }

View File

@ -2,8 +2,6 @@
namespace SilverStripe\Core\Tests\ObjectTest; namespace SilverStripe\Core\Tests\ObjectTest;
use SilverStripe\Core\Object; class CreateTest3 extends BaseObject
class CreateTest3 extends Object
{ {
} }

View File

@ -2,9 +2,7 @@
namespace SilverStripe\Core\Tests\ObjectTest; namespace SilverStripe\Core\Tests\ObjectTest;
use SilverStripe\Core\Object; class ExtendTest extends BaseObject
class ExtendTest extends Object
{ {
private static $extensions = array( private static $extensions = array(
ExtendTest1::class, ExtendTest1::class,

View File

@ -3,8 +3,9 @@
namespace SilverStripe\Core\Tests\ObjectTest; namespace SilverStripe\Core\Tests\ObjectTest;
use SilverStripe\Core\Extension; use SilverStripe\Core\Extension;
use SilverStripe\Dev\TestOnly;
class ExtendTest1 extends Extension class ExtendTest1 extends Extension implements TestOnly
{ {
public function extendableMethod(&$argument = null) public function extendableMethod(&$argument = null)
{ {

View File

@ -3,9 +3,17 @@
namespace SilverStripe\Core\Tests\ObjectTest; namespace SilverStripe\Core\Tests\ObjectTest;
use SilverStripe\Core\Extension; use SilverStripe\Core\Extension;
use SilverStripe\Dev\TestOnly;
class ExtendTest2 extends Extension class ExtendTest2 extends Extension implements TestOnly
{ {
protected $constructorArgs = [];
public function __construct()
{
$this->constructorArgs = func_get_args();
}
public function extendableMethod($argument = null) public function extendableMethod($argument = null)
{ {
$args = implode(',', array_filter(func_get_args())); $args = implode(',', array_filter(func_get_args()));

View File

@ -3,9 +3,17 @@
namespace SilverStripe\Core\Tests\ObjectTest; namespace SilverStripe\Core\Tests\ObjectTest;
use SilverStripe\Core\Extension; use SilverStripe\Core\Extension;
use SilverStripe\Dev\TestOnly;
class ExtendTest3 extends Extension class ExtendTest3 extends Extension implements TestOnly
{ {
protected $constructorArgs = [];
public function __construct()
{
$this->constructorArgs = func_get_args();
}
public function extendableMethod($argument = null) public function extendableMethod($argument = null)
{ {
return "ExtendTest3($argument)"; return "ExtendTest3($argument)";

View File

@ -2,10 +2,7 @@
namespace SilverStripe\Core\Tests\ObjectTest; namespace SilverStripe\Core\Tests\ObjectTest;
use SilverStripe\Core\Object; class Extending extends BaseObject
use SilverStripe\Dev\TestOnly;
class Extending extends Object implements TestOnly
{ {
private static $extensions = array( private static $extensions = array(

View File

@ -2,9 +2,7 @@
namespace SilverStripe\Core\Tests\ObjectTest; namespace SilverStripe\Core\Tests\ObjectTest;
use SilverStripe\Core\Object; class ExtensionRemoveTest extends BaseObject
class ExtensionRemoveTest extends Object
{ {
private static $extensions = array( private static $extensions = array(
ExtendTest1::class, ExtendTest1::class,

View File

@ -2,9 +2,7 @@
namespace SilverStripe\Core\Tests\ObjectTest; namespace SilverStripe\Core\Tests\ObjectTest;
use SilverStripe\Core\Object; class ExtensionTest extends BaseObject
class ExtensionTest extends Object
{ {
private static $extensions = array( private static $extensions = array(
'SilverStripe\\Core\\Tests\\oBjEcTTEST\\EXTENDTest1', 'SilverStripe\\Core\\Tests\\oBjEcTTEST\\EXTENDTest1',

View File

@ -2,9 +2,7 @@
namespace SilverStripe\Core\Tests\ObjectTest; namespace SilverStripe\Core\Tests\ObjectTest;
use SilverStripe\Core\Object; class ExtensionTest2 extends BaseObject
class ExtensionTest2 extends Object
{ {
private static $extensions = [ private static $extensions = [
TestExtension::class, TestExtension::class,

View File

@ -2,8 +2,6 @@
namespace SilverStripe\Core\Tests\ObjectTest; namespace SilverStripe\Core\Tests\ObjectTest;
use SilverStripe\Core\Object; class ExtensionTest3 extends BaseObject
class ExtensionTest3 extends Object
{ {
} }

View File

@ -2,9 +2,7 @@
namespace SilverStripe\Core\Tests\ObjectTest; namespace SilverStripe\Core\Tests\ObjectTest;
use SilverStripe\Core\Object; class MyObject extends BaseObject
class MyObject extends Object
{ {
public $title = 'my object'; public $title = 'my object';
/** /**

View File

@ -2,9 +2,7 @@
namespace SilverStripe\Core\Tests\ObjectTest; namespace SilverStripe\Core\Tests\ObjectTest;
use SilverStripe\Core\Object; class T1A extends BaseObject
class T1A extends Object
{ {
public function testMethod() public function testMethod()
{ {

View File

@ -2,9 +2,7 @@
namespace SilverStripe\Core\Tests\ObjectTest; namespace SilverStripe\Core\Tests\ObjectTest;
use SilverStripe\Core\Object; class T1B extends BaseObject
class T1B extends Object
{ {
public function someMethod() public function someMethod()
{ {

View File

@ -2,9 +2,7 @@
namespace SilverStripe\Core\Tests\ObjectTest; namespace SilverStripe\Core\Tests\ObjectTest;
use SilverStripe\Core\Object; class T1C extends BaseObject
class T1C extends Object
{ {
public function t1cMethod() public function t1cMethod()
{ {

View File

@ -2,9 +2,7 @@
namespace SilverStripe\Core\Tests\ObjectTest; namespace SilverStripe\Core\Tests\ObjectTest;
use SilverStripe\Core\Object; class T2 extends BaseObject
class T2 extends Object
{ {
protected $failover; protected $failover;
protected $failoverArr = array(); protected $failoverArr = array();

View File

@ -3,7 +3,8 @@
namespace SilverStripe\Core\Tests\ObjectTest; namespace SilverStripe\Core\Tests\ObjectTest;
use SilverStripe\Core\Extension; use SilverStripe\Core\Extension;
use SilverStripe\Dev\TestOnly;
class TestExtension extends Extension class TestExtension extends Extension implements TestOnly
{ {
} }

View File

@ -37,14 +37,10 @@ class TestController extends Controller implements TestOnly
$field->getConfig()->addComponent(new GridFieldAddNewButton('toolbar-header-right')); $field->getConfig()->addComponent(new GridFieldAddNewButton('toolbar-header-right'));
$field->getConfig()->addComponent(new GridFieldViewButton()); $field->getConfig()->addComponent(new GridFieldViewButton());
$field->getConfig()->addComponent(new GridFieldEditButton()); $field->getConfig()->addComponent(new GridFieldEditButton());
/** /** @skipUpgrade */
* @skipUpgrade
*/
$field->getConfig()->addComponent($gridFieldForm = new GridFieldDetailForm($this, 'Form')); $field->getConfig()->addComponent($gridFieldForm = new GridFieldDetailForm($this, 'Form'));
$field->getConfig()->addComponent(new GridFieldEditButton()); $field->getConfig()->addComponent(new GridFieldEditButton());
/** /** @skipUpgrade */
* @skipUpgrade
*/
return new Form($this, 'Form', new FieldList($field), new FieldList()); return new Form($this, 'Form', new FieldList($field), new FieldList());
} }
} }

View File

@ -2,10 +2,11 @@
namespace SilverStripe\ORM\Tests; namespace SilverStripe\ORM\Tests;
use SilverStripe\Control\Director;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\FieldType\DBHTMLText; use SilverStripe\ORM\FieldType\DBHTMLText;
use SilverStripe\ORM\FieldType\DBField; use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\Core\Object;
use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Config;
use SilverStripe\Dev\SapphireTest; use SilverStripe\Dev\SapphireTest;
use SilverStripe\ORM\Tests\DBHTMLTextTest\TestShortcode; use SilverStripe\ORM\Tests\DBHTMLTextTest\TestShortcode;
@ -217,26 +218,24 @@ class DBHTMLTextTest extends SapphireTest
public function testCreate() public function testCreate()
{ {
/** /** @var DBHTMLText $field */
* @var DBHTMLText $field $field = Injector::inst()->create("HTMLFragment(['whitelist' => 'link'])", 'MyField');
*/
$field = Object::create_from_string("HTMLFragment(['whitelist' => 'link'])", 'MyField');
$this->assertEquals(['link'], $field->getWhitelist()); $this->assertEquals(['link'], $field->getWhitelist());
$field = Object::create_from_string("HTMLFragment(['whitelist' => 'link,a'])", 'MyField'); $field = Injector::inst()->create("HTMLFragment(['whitelist' => 'link,a'])", 'MyField');
$this->assertEquals(['link', 'a'], $field->getWhitelist()); $this->assertEquals(['link', 'a'], $field->getWhitelist());
$field = Object::create_from_string("HTMLFragment(['whitelist' => ['link', 'a']])", 'MyField'); $field = Injector::inst()->create("HTMLFragment(['whitelist' => ['link', 'a']])", 'MyField');
$this->assertEquals(['link', 'a'], $field->getWhitelist()); $this->assertEquals(['link', 'a'], $field->getWhitelist());
$field = Object::create_from_string("HTMLFragment", 'MyField'); $field = Injector::inst()->create("HTMLFragment", 'MyField');
$this->assertEmpty($field->getWhitelist()); $this->assertEmpty($field->getWhitelist());
// Test shortcodes // Test shortcodes
$field = Object::create_from_string("HTMLFragment(['shortcodes' => true])", 'MyField'); $field = Injector::inst()->create("HTMLFragment(['shortcodes' => true])", 'MyField');
$this->assertEquals(true, $field->getProcessShortcodes()); $this->assertEquals(true, $field->getProcessShortcodes());
$field = Object::create_from_string("HTMLFragment(['shortcodes' => false])", 'MyField'); $field = Injector::inst()->create("HTMLFragment(['shortcodes' => false])", 'MyField');
$this->assertEquals(false, $field->getProcessShortcodes()); $this->assertEquals(false, $field->getProcessShortcodes());
// Mix options // Mix options
$field = Object::create_from_string("HTMLFragment(['shortcodes' => true, 'whitelist' => ['a'])", 'MyField'); $field = Injector::inst()->create("HTMLFragment(['shortcodes' => true, 'whitelist' => ['a'])", 'MyField');
$this->assertEquals(true, $field->getProcessShortcodes()); $this->assertEquals(true, $field->getProcessShortcodes());
$this->assertEquals(['a'], $field->getWhitelist()); $this->assertEquals(['a'], $field->getWhitelist());
} }
@ -553,7 +552,7 @@ class DBHTMLTextTest extends SapphireTest
$field->Plain() $field->Plain()
); );
Config::nest(); Config::nest();
Config::inst()->update('SilverStripe\\Control\\Director', 'alternate_base_url', 'http://example.com/'); Director::config()->set('alternate_base_url', 'http://example.com/');
$this->assertEquals( $this->assertEquals(
'<p>Replaced short code with this. <a href="http://example.com/home">home</a></p>', '<p>Replaced short code with this. <a href="http://example.com/home">home</a></p>',
$field->AbsoluteLinks() $field->AbsoluteLinks()

View File

@ -2,7 +2,7 @@
namespace SilverStripe\ORM\Tests; namespace SilverStripe\ORM\Tests;
use SilverStripe\Core\Object; use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\FieldType\DBField; use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\FieldType\DBString; use SilverStripe\ORM\FieldType\DBString;
use SilverStripe\Dev\SapphireTest; use SilverStripe\Dev\SapphireTest;
@ -24,10 +24,8 @@ class DBStringTest extends SapphireTest
public function testDefault() public function testDefault()
{ {
/** /** @var DBString $dbField */
* @var DBString $dbField $dbField = Injector::inst()->create(
*/
$dbField = Object::create_from_string(
DBStringTest\MyStringField::class."(['default' => 'Here is my default text'])", DBStringTest\MyStringField::class."(['default' => 'Here is my default text'])",
'Myfield' 'Myfield'
); );
@ -42,9 +40,11 @@ class DBStringTest extends SapphireTest
*/ */
public function testLowerCase() public function testLowerCase()
{ {
/** @var MyStringField $field */
$field = DBField::create_field(MyStringField::class, 'This is a TEST!');
$this->assertEquals( $this->assertEquals(
'this is a test!', 'this is a test!',
DBField::create_field(MyStringField::class, 'This is a TEST!')->LowerCase() $field->LowerCase()
); );
} }
@ -53,9 +53,11 @@ class DBStringTest extends SapphireTest
*/ */
public function testUpperCase() public function testUpperCase()
{ {
/** @var MyStringField $field */
$field = DBField::create_field(MyStringField::class, 'This is a TEST!');
$this->assertEquals( $this->assertEquals(
'THIS IS A TEST!', 'THIS IS A TEST!',
DBField::create_field(MyStringField::class, 'This is a TEST!')->UpperCase() $field->UpperCase()
); );
} }

View File

@ -2,7 +2,7 @@
namespace SilverStripe\ORM\Tests; namespace SilverStripe\ORM\Tests;
use SilverStripe\Core\Object; use SilverStripe\Core\ClassInfo;
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
use SilverStripe\Dev\SapphireTest; use SilverStripe\Dev\SapphireTest;
use SilverStripe\ORM\DataObjectSchema; use SilverStripe\ORM\DataObjectSchema;
@ -139,7 +139,7 @@ class DataObjectSchemaTest extends SapphireTest
); );
$this->assertNull( $this->assertNull(
$schema->tableForField(Object::class, 'Title') $schema->tableForField(ClassInfo::class, 'Title')
); );
// Test fixed fields // Test fixed fields

View File

@ -619,17 +619,17 @@ class DataObjectTest extends SapphireTest
// Set the favourite team for fan1 // Set the favourite team for fan1
$fan1->setField('FavouriteID', $team1->ID); $fan1->setField('FavouriteID', $team1->ID);
$fan1->setField('FavouriteClass', $team1->class); $fan1->setField('FavouriteClass', get_class($team1));
$this->assertEquals($team1->ID, $fan1->Favourite()->ID, 'The team is assigned to fan 1'); $this->assertEquals($team1->ID, $fan1->Favourite()->ID, 'The team is assigned to fan 1');
$this->assertInstanceOf($team1->class, $fan1->Favourite(), 'The team is assigned to fan 1'); $this->assertInstanceOf(get_class($team1), $fan1->Favourite(), 'The team is assigned to fan 1');
$this->assertEquals( $this->assertEquals(
$team1->ID, $team1->ID,
$fan1->getComponent('Favourite')->ID, $fan1->getComponent('Favourite')->ID,
'The team exists through the component getter' 'The team exists through the component getter'
); );
$this->assertInstanceOf( $this->assertInstanceOf(
$team1->class, get_class($team1),
$fan1->getComponent('Favourite'), $fan1->getComponent('Favourite'),
'The team exists through the component getter' 'The team exists through the component getter'
); );
@ -847,10 +847,10 @@ class DataObjectTest extends SapphireTest
// Test for polymorphic has_one relations // Test for polymorphic has_one relations
$fan = $this->objFromFixture(DataObjectTest\Fan::class, 'fan1'); $fan = $this->objFromFixture(DataObjectTest\Fan::class, 'fan1');
$fan->FavouriteID = $team->ID; $fan->FavouriteID = $team->ID;
$fan->FavouriteClass = $team->class; $fan->FavouriteClass = DataObjectTest\Team::class;
$this->assertNotNull($fan->Favourite()); $this->assertNotNull($fan->Favourite());
$this->assertEquals($team->ID, $fan->Favourite()->ID); $this->assertEquals($team->ID, $fan->Favourite()->ID);
$this->assertInstanceOf($team->class, $fan->Favourite()); $this->assertInstanceOf(DataObjectTest\Team::class, $fan->Favourite());
} }
public function testFieldNamesThatMatchMethodNamesWork() public function testFieldNamesThatMatchMethodNamesWork()
@ -1434,26 +1434,25 @@ class DataObjectTest extends SapphireTest
$equipmentSuppliers = $team->EquipmentSuppliers(); $equipmentSuppliers = $team->EquipmentSuppliers();
// Check that DataObject::many_many() works as expected // Check that DataObject::many_many() works as expected
list($relationClass, $class, $targetClass, $parentField, $childField, $joinTable) $manyManyComponent = DataObject::getSchema()->manyManyComponent(DataObjectTest\Team::class, 'Sponsors');
= DataObject::getSchema()->manyManyComponent(DataObjectTest\Team::class, 'Sponsors'); $this->assertEquals(ManyManyList::class, $manyManyComponent['relationClass']);
$this->assertEquals(ManyManyList::class, $relationClass);
$this->assertEquals( $this->assertEquals(
DataObjectTest\Team::class, DataObjectTest\Team::class,
$class, $manyManyComponent['parentClass'],
'DataObject::many_many() didn\'t find the correct base class' 'DataObject::many_many() didn\'t find the correct base class'
); );
$this->assertEquals( $this->assertEquals(
DataObjectTest\EquipmentCompany::class, DataObjectTest\EquipmentCompany::class,
$targetClass, $manyManyComponent['childClass'],
'DataObject::many_many() didn\'t find the correct target class for the relation' 'DataObject::many_many() didn\'t find the correct target class for the relation'
); );
$this->assertEquals( $this->assertEquals(
'DataObjectTest_EquipmentCompany_SponsoredTeams', 'DataObjectTest_EquipmentCompany_SponsoredTeams',
$joinTable, $manyManyComponent['join'],
'DataObject::many_many() didn\'t find the correct relation table' 'DataObject::many_many() didn\'t find the correct relation table'
); );
$this->assertEquals('DataObjectTest_TeamID', $parentField); $this->assertEquals('DataObjectTest_TeamID', $manyManyComponent['parentField']);
$this->assertEquals('DataObjectTest_EquipmentCompanyID', $childField); $this->assertEquals('DataObjectTest_EquipmentCompanyID', $manyManyComponent['childField']);
// Check that ManyManyList still works // Check that ManyManyList still works
$this->assertEquals(2, $sponsors->count(), 'Rows are missing from relation'); $this->assertEquals(2, $sponsors->count(), 'Rows are missing from relation');
@ -1918,11 +1917,15 @@ class DataObjectTest extends SapphireTest
// Test belongs_to assignment // Test belongs_to assignment
$company->OwnerID = $ceo->ID; $company->OwnerID = $ceo->ID;
$company->OwnerClass = $ceo->class; $company->OwnerClass = DataObjectTest\CEO::class;
$company->write(); $company->write();
$this->assertEquals($company->ID, $ceo->CompanyOwned()->ID, 'belongs_to returns the right results.'); $this->assertEquals($company->ID, $ceo->CompanyOwned()->ID, 'belongs_to returns the right results.');
$this->assertEquals($company->class, $ceo->CompanyOwned()->class, 'belongs_to returns the right results.'); $this->assertInstanceOf(
DataObjectTest\Company::class,
$ceo->CompanyOwned(),
'belongs_to returns the right results.'
);
// Test automatic creation of class where no assigment exists // Test automatic creation of class where no assigment exists
$ceo = new DataObjectTest\CEO(); $ceo = new DataObjectTest\CEO();

View File

@ -2,11 +2,7 @@
namespace SilverStripe\ORM\Tests; namespace SilverStripe\ORM\Tests;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DataExtension;
use SilverStripe\Core\Object;
use SilverStripe\Dev\SapphireTest; use SilverStripe\Dev\SapphireTest;
use SilverStripe\Dev\TestOnly;
class ManyManyListExtensionTest extends SapphireTest class ManyManyListExtensionTest extends SapphireTest
{ {
@ -26,9 +22,10 @@ class ManyManyListExtensionTest extends SapphireTest
// This extends ManyManyListTest_Secondary with the secondary extension that adds the relationship back // This extends ManyManyListTest_Secondary with the secondary extension that adds the relationship back
// to the primary. The instance from the fixture is ManyManyListTest_SecondarySub, deliberately a sub-class of // to the primary. The instance from the fixture is ManyManyListTest_SecondarySub, deliberately a sub-class of
// the extended class. // the extended class.
Object::add_extension(ManyManyListTest\Secondary::class, ManyManyListTest\IndirectSecondaryExtension::class); ManyManyListTest\Secondary::add_extension(ManyManyListTest\IndirectSecondaryExtension::class);
// Test from the primary (not extended) to the secondary (which is extended) // Test from the primary (not extended) to the secondary (which is extended)
/** @var ManyManyListTest\IndirectPrimary $primary */
$primary = $this->objFromFixture(ManyManyListTest\IndirectPrimary::class, 'manymany_extra_primary'); $primary = $this->objFromFixture(ManyManyListTest\IndirectPrimary::class, 'manymany_extra_primary');
$secondaries = $primary->Secondary(); $secondaries = $primary->Secondary();
$extraFields = $secondaries->getExtraFields(); $extraFields = $secondaries->getExtraFields();
@ -37,6 +34,7 @@ class ManyManyListExtensionTest extends SapphireTest
$this->assertTrue(isset($extraFields['DocumentSort']), 'has DocumentSort'); $this->assertTrue(isset($extraFields['DocumentSort']), 'has DocumentSort');
// Test from the secondary (which is extended) to the primary (not extended) // Test from the secondary (which is extended) to the primary (not extended)
/** @var ManyManyListTest\SecondarySub|ManyManyListTest\IndirectSecondaryExtension $secondary */
$secondary = $this->objFromFixture(ManyManyListTest\SecondarySub::class, 'manymany_extra_secondary'); $secondary = $this->objFromFixture(ManyManyListTest\SecondarySub::class, 'manymany_extra_secondary');
$primaries = $secondary->Primary(); $primaries = $secondary->Primary();

View File

@ -4,11 +4,14 @@ namespace SilverStripe\ORM\Tests\ManyManyListTest;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\ManyManyList;
/** /**
* A data object that implements the primary side of a many_many (where the extra fields are * A data object that implements the primary side of a many_many (where the extra fields are
* defined.) The many-many refers to ManyManyListTest_Secondary rather than ManyManyListTest_SecondarySub * defined.) The many-many refers to ManyManyListTest_Secondary rather than ManyManyListTest_SecondarySub
* by design, because we're trying to test that a subclass instance picks up the extra fields of it's parent. * by design, because we're trying to test that a subclass instance picks up the extra fields of it's parent.
*
* @method ManyManyList Secondary()
*/ */
class IndirectPrimary extends DataObject implements TestOnly class IndirectPrimary extends DataObject implements TestOnly
{ {

View File

@ -4,10 +4,13 @@ namespace SilverStripe\ORM\Tests\ManyManyListTest;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\DataExtension; use SilverStripe\ORM\DataExtension;
use SilverStripe\ORM\ManyManyList;
/** /**
* An extension that is applied to ManyManyListTest_Secondary that * An extension that is applied to ManyManyListTest_Secondary that
* implements the other side of the many-many relationship. * implements the other side of the many-many relationship.
*
* @method ManyManyList Primary()
*/ */
class IndirectSecondaryExtension extends DataExtension implements TestOnly class IndirectSecondaryExtension extends DataExtension implements TestOnly
{ {

View File

@ -160,12 +160,12 @@ class ManyManyThroughListTest extends SapphireTest
// Parent components // Parent components
$this->assertEquals( $this->assertEquals(
[ [
ManyManyThroughList::class, 'relationClass' => ManyManyThroughList::class,
ManyManyThroughListTest\TestObject::class, 'parentClass' => ManyManyThroughListTest\TestObject::class,
ManyManyThroughListTest\Item::class, 'childClass' => ManyManyThroughListTest\Item::class,
'ParentID', 'parentField' => 'ParentID',
'ChildID', 'childField' => 'ChildID',
ManyManyThroughListTest\JoinObject::class 'join' => ManyManyThroughListTest\JoinObject::class
], ],
$schema->manyManyComponent(ManyManyThroughListTest\TestObject::class, 'Items') $schema->manyManyComponent(ManyManyThroughListTest\TestObject::class, 'Items')
); );
@ -173,12 +173,12 @@ class ManyManyThroughListTest extends SapphireTest
// Belongs_many_many is the same, but with parent/child substituted // Belongs_many_many is the same, but with parent/child substituted
$this->assertEquals( $this->assertEquals(
[ [
ManyManyThroughList::class, 'relationClass' => ManyManyThroughList::class,
ManyManyThroughListTest\Item::class, 'parentClass' => ManyManyThroughListTest\Item::class,
ManyManyThroughListTest\TestObject::class, 'childClass' => ManyManyThroughListTest\TestObject::class,
'ChildID', 'parentField' => 'ChildID',
'ParentID', 'childField' => 'ParentID',
ManyManyThroughListTest\JoinObject::class 'join' => ManyManyThroughListTest\JoinObject::class
], ],
$schema->manyManyComponent(ManyManyThroughListTest\Item::class, 'Objects') $schema->manyManyComponent(ManyManyThroughListTest\Item::class, 'Objects')
); );

View File

@ -3,7 +3,6 @@
namespace SilverStripe\Security\Tests; namespace SilverStripe\Security\Tests;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\Core\Object;
use SilverStripe\Dev\FunctionalTest; use SilverStripe\Dev\FunctionalTest;
use SilverStripe\Control\Cookie; use SilverStripe\Control\Cookie;
use SilverStripe\i18n\i18n; use SilverStripe\i18n\i18n;
@ -27,14 +26,9 @@ class MemberTest extends FunctionalTest
protected $orig = array(); protected $orig = array();
protected static $illegal_extensions = array( protected static $illegal_extensions = [
Member::class => array( Member::class => '*',
// TODO Coupling with modules, this should be resolved by automatically ];
// removing all applied extensions before a unit test
'ForumRole',
'OpenIDAuthenticatedRole'
)
);
public function __construct() public function __construct()
{ {
@ -537,7 +531,6 @@ class MemberTest extends FunctionalTest
*/ */
public function testCanManipulateOwnRecord() public function testCanManipulateOwnRecord()
{ {
$extensions = $this->removeExtensions(Object::get_extensions(Member::class));
$member = $this->objFromFixture(Member::class, 'test'); $member = $this->objFromFixture(Member::class, 'test');
$member2 = $this->objFromFixture(Member::class, 'staffmember'); $member2 = $this->objFromFixture(Member::class, 'staffmember');
@ -560,13 +553,11 @@ class MemberTest extends FunctionalTest
$this->assertFalse($member->canDelete()); $this->assertFalse($member->canDelete());
$this->assertFalse($member->canEdit()); $this->assertFalse($member->canEdit());
$this->addExtensions($extensions);
$this->session()->inst_set('loggedInAs', null); $this->session()->inst_set('loggedInAs', null);
} }
public function testAuthorisedMembersCanManipulateOthersRecords() public function testAuthorisedMembersCanManipulateOthersRecords()
{ {
$extensions = $this->removeExtensions(Object::get_extensions(Member::class));
$member = $this->objFromFixture(Member::class, 'test'); $member = $this->objFromFixture(Member::class, 'test');
$member2 = $this->objFromFixture(Member::class, 'staffmember'); $member2 = $this->objFromFixture(Member::class, 'staffmember');
@ -575,14 +566,10 @@ class MemberTest extends FunctionalTest
$this->assertTrue($member2->canView()); $this->assertTrue($member2->canView());
$this->assertTrue($member2->canDelete()); $this->assertTrue($member2->canDelete());
$this->assertTrue($member2->canEdit()); $this->assertTrue($member2->canEdit());
$this->addExtensions($extensions);
$this->session()->inst_set('loggedInAs', null);
} }
public function testExtendedCan() public function testExtendedCan()
{ {
$extensions = $this->removeExtensions(Object::get_extensions(Member::class));
$member = $this->objFromFixture(Member::class, 'test'); $member = $this->objFromFixture(Member::class, 'test');
/* Normal behaviour is that you can't view a member unless canView() on an extension returns true */ /* Normal behaviour is that you can't view a member unless canView() on an extension returns true */
@ -617,7 +604,6 @@ class MemberTest extends FunctionalTest
$this->assertTrue($member4->canEdit()); $this->assertTrue($member4->canEdit());
Member::remove_extension(MemberTest\EditingAllowedDeletingDeniedExtension::class); Member::remove_extension(MemberTest\EditingAllowedDeletingDeniedExtension::class);
$this->addExtensions($extensions);
} }
/** /**

View File

@ -8,7 +8,6 @@ class TestPasswordValidator extends PasswordValidator
{ {
public function __construct() public function __construct()
{ {
parent::__construct();
$this->minLength(7); $this->minLength(7);
$this->checkHistoricalPasswords(6); $this->checkHistoricalPasswords(6);
$this->characterStrength(3, array('lowercase', 'uppercase', 'digits', 'punctuation')); $this->characterStrength(3, array('lowercase', 'uppercase', 'digits', 'punctuation'));

View File

@ -1,8 +1,6 @@
<?php <?php
use SilverStripe\Core\Object; class i18nOtherModule
class i18nOtherModule extends Object
{ {
public function mymethod() public function mymethod()
{ {

View File

@ -1,7 +1,6 @@
<?php <?php
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
use SilverStripe\Core\Object;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
class i18nTestModule extends DataObject implements TestOnly class i18nTestModule extends DataObject implements TestOnly
@ -20,7 +19,7 @@ class i18nTestModule extends DataObject implements TestOnly
); );
} }
} }
class i18nTestModule_Addition extends Object class i18nTestModule_Addition
{ {
public function myAdditionalMethod() public function myAdditionalMethod()
{ {

View File

@ -1,13 +1,9 @@
<?php <?php
use SilverStripe\Core\Object; class i18nTestSubModule
class i18nTestSubModule extends Object
{ {
public function __construct() public function __construct()
{ {
_t('i18nTestModule.OTHERENTITY', 'Other Entity'); _t('i18nTestModule.OTHERENTITY', 'Other Entity');
parent::__construct();
} }
} }