From e72fc9e3d0f35a1d43f55f83f9919f67d72fb7cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sam=20Minn=C3=A9e?= Date: Thu, 25 Oct 2018 11:42:45 +1300 Subject: [PATCH 1/2] FIX DataObject singleton creation (#8516) Ensure DataObject instances are aware they are singletons so functions like populateDefaults() can be skipped. (fixes #4878) Correctly applies https://github.com/silverstripe/silverstripe-framework/pull/7850 to the 4.x line This has already been fixed in 3.x --- src/Core/Injector/Injector.php | 9 +++++++ tests/php/ORM/DataObjectTest.php | 45 ++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) 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/tests/php/ORM/DataObjectTest.php b/tests/php/ORM/DataObjectTest.php index 55c2ea659..3a2158c4c 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(); From 46e4c19070688df74757bd9a44dc2f0b2fdcd6a9 Mon Sep 17 00:00:00 2001 From: Maxime Rainville Date: Thu, 1 Nov 2018 22:38:26 +1300 Subject: [PATCH 2/2] MINOR Add a reference to SS_Object in .upgrade.yml to allow upgrade from SS3.7 --- .upgrade.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.upgrade.yml b/.upgrade.yml index e4e2c392a..33d42e81e 100644 --- a/.upgrade.yml +++ b/.upgrade.yml @@ -958,6 +958,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'