diff --git a/.upgrade.yml b/.upgrade.yml index 3b9616a95..8e06b802c 100644 --- a/.upgrade.yml +++ b/.upgrade.yml @@ -959,6 +959,9 @@ warnings: 'Object': message: 'Replaced with traits' url: 'https://docs.silverstripe.org/en/4/changelogs/4.0.0#object-replace' + 'SS_Object': + message: 'Replaced with traits' + url: 'https://docs.silverstripe.org/en/4/changelogs/4.0.0#object-replace' 'SS_Log': message: 'Replaced with a PSR-3 logger' url: 'https://docs.silverstripe.org/en/4/changelogs/4.0.0#psr3-logging' diff --git a/src/Core/Injector/Injector.php b/src/Core/Injector/Injector.php index 6b0885132..6cf980cbf 100644 --- a/src/Core/Injector/Injector.php +++ b/src/Core/Injector/Injector.php @@ -13,6 +13,7 @@ use SilverStripe\Core\ClassInfo; use SilverStripe\Core\Config\Config; use SilverStripe\Core\Environment; use SilverStripe\Dev\Deprecation; +use SilverStripe\ORM\DataObject; /** * A simple injection manager that manages creating objects and injecting @@ -581,6 +582,14 @@ class Injector implements ContainerInterface $constructorParams = $spec['constructor']; } + // If we're dealing with a DataObject singleton without specific constructor params, pass through Singleton + // flag as second argument + if ((!$type || $type !== self::PROTOTYPE) + && empty($constructorParams) + && is_subclass_of($class, DataObject::class)) { + $constructorParams = array(null, true); + } + $factory = isset($spec['factory']) ? $this->get($spec['factory']) : $this->getObjectCreator(); $object = $factory->create($class, $constructorParams); diff --git a/src/Forms/GridField/GridField_FormAction.php b/src/Forms/GridField/GridField_FormAction.php index 627ef8b87..10dc772bc 100644 --- a/src/Forms/GridField/GridField_FormAction.php +++ b/src/Forms/GridField/GridField_FormAction.php @@ -101,6 +101,7 @@ class GridField_FormAction extends FormAction // will strip it from the requests 'name' => 'action_gridFieldAlterAction' . '?' . http_build_query($actionData), 'data-url' => $this->gridField->Link(), + 'type' => "button", ) ); } diff --git a/tests/php/ORM/DataObjectTest.php b/tests/php/ORM/DataObjectTest.php index c0d81c15f..8d2a1dec3 100644 --- a/tests/php/ORM/DataObjectTest.php +++ b/tests/php/ORM/DataObjectTest.php @@ -66,6 +66,51 @@ class DataObjectTest extends SapphireTest ); } + /** + * @dataProvider provideSingletons + */ + public function testSingleton($inst, $defaultValue, $altDefaultValue) + { + $inst = $inst(); + // Test that populateDefaults() isn't called on singletons + // which can lead to SQL errors during build, and endless loops + if ($defaultValue) { + $this->assertEquals($defaultValue, $inst->MyFieldWithDefault); + } else { + $this->assertEmpty($inst->MyFieldWithDefault); + } + + if ($altDefaultValue) { + $this->assertEquals($altDefaultValue, $inst->MyFieldWithAltDefault); + } else { + $this->assertEmpty($inst->MyFieldWithAltDefault); + } + } + + public function provideSingletons() + { + // because PHPUnit evalutes test providers *before* setUp methods + // any extensions added in the setUp methods won't be available + // we must return closures to generate the arguments at run time + return array( + 'create() static method' => array(function () { + return DataObjectTest\Fixture::create(); + }, 'Default Value', 'Default Value'), + 'New object creation' => array(function () { + return new DataObjectTest\Fixture(); + }, 'Default Value', 'Default Value'), + 'singleton() function' => array(function () { + return singleton(DataObjectTest\Fixture::class); + }, null, null), + 'singleton() static method' => array(function () { + return DataObjectTest\Fixture::singleton(); + }, null, null), + 'Manual constructor args' => array(function () { + return new DataObjectTest\Fixture(null, true); + }, null, null), + ); + } + public function testDb() { $schema = DataObject::getSchema();