NEW Access dynamic data inside ViewableData

This commit is contained in:
Steve Boyd 2023-02-22 09:40:27 +13:00
parent bddad3ab39
commit 0075bf6e49
4 changed files with 47 additions and 8 deletions

View File

@ -2,6 +2,7 @@
namespace SilverStripe\ORM\FieldType; namespace SilverStripe\ORM\FieldType;
use InvalidArgumentException;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DB; use SilverStripe\ORM\DB;
@ -270,11 +271,11 @@ abstract class DBComposite extends DBField
{ {
$this->objCacheClear(); $this->objCacheClear();
// Non-db fields get assigned as normal properties
if (!$this->hasField($field)) { if (!$this->hasField($field)) {
parent::setField($field, $value); throw new InvalidArgumentException(implode(' ', [
"Field $field does not exist.",
return $this; 'If this was accessed via a dynamic property then call setDynamicData() instead.'
]));
} }
// Set changed // Set changed

View File

@ -73,7 +73,7 @@ class ViewableData implements IteratorAggregate
/** /**
* Acts as a PHP 8.2+ compliant replacement for dynamic properties * Acts as a PHP 8.2+ compliant replacement for dynamic properties
*/ */
private array $data = []; private array $dynamicData = [];
// ----------------------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------------------
@ -203,7 +203,7 @@ class ViewableData implements IteratorAggregate
*/ */
public function hasField($field) public function hasField($field)
{ {
return property_exists($this, $field) || isset($this->data[$field]); return property_exists($this, $field) || $this->hasDynamicData($field);
} }
/** /**
@ -217,7 +217,7 @@ class ViewableData implements IteratorAggregate
if ($this->isAccessibleProperty($field)) { if ($this->isAccessibleProperty($field)) {
return $this->$field; return $this->$field;
} }
return $this->data[$field]; return $this->getDynamicData($field);
} }
/** /**
@ -236,10 +236,25 @@ class ViewableData implements IteratorAggregate
if ($this->isAccessibleProperty($field)) { if ($this->isAccessibleProperty($field)) {
$this->$field = $value; $this->$field = $value;
} }
$this->data[$field] = $value; return $this->setDynamicData($field, $value);
}
public function getDynamicData(string $field): mixed
{
return $this->hasDynamicData($field) ? $this->dynamicData[$field] : null;
}
public function setDynamicData(string $field, mixed $value): static
{
$this->dynamicData[$field] = $value;
return $this; return $this;
} }
public function hasDynamicData(string $field): bool
{
return array_key_exists($field, $this->dynamicData);
}
/** /**
* Returns true if a method exists for the current class which isn't private. * Returns true if a method exists for the current class which isn't private.
* Also returns true for private methods if $this is ViewableData (not a subclass) * Also returns true for private methods if $this is ViewableData (not a subclass)

View File

@ -5,6 +5,7 @@ namespace SilverStripe\ORM\Tests;
use SilverStripe\ORM\FieldType\DBMoney; use SilverStripe\ORM\FieldType\DBMoney;
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
use SilverStripe\Dev\SapphireTest; use SilverStripe\Dev\SapphireTest;
use InvalidArgumentException;
class DBCompositeTest extends SapphireTest class DBCompositeTest extends SapphireTest
{ {
@ -108,4 +109,15 @@ class DBCompositeTest extends SapphireTest
$this->assertEquals('DBCompositeTest_SubclassedDBFieldObject', $object2->dbObject('OtherMoney')->getTable()); $this->assertEquals('DBCompositeTest_SubclassedDBFieldObject', $object2->dbObject('OtherMoney')->getTable());
$this->assertEquals('DBCompositeTest_SubclassedDBFieldObject', $object2->dbObject('OverriddenMoney')->getTable()); $this->assertEquals('DBCompositeTest_SubclassedDBFieldObject', $object2->dbObject('OverriddenMoney')->getTable());
} }
public function testSetFieldDynamicPropertyException()
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage(implode(' ', [
'Field abc does not exist.',
'If this was accessed via a dynamic property then call setDynamicData() instead.'
]));
$object = new DBCompositeTest\TestObject();
$object->MyMoney->abc = 'def';
}
} }

View File

@ -267,4 +267,15 @@ class ViewableDataTest extends SapphireTest
$output = $reflectionMethod->invokeArgs(new ViewableData(), ['objCache']); $output = $reflectionMethod->invokeArgs(new ViewableData(), ['objCache']);
$this->assertTrue($output, 'Property should be accessible'); $this->assertTrue($output, 'Property should be accessible');
} }
public function testDynamicData()
{
$obj = (object) ['SomeField' => [1, 2, 3]];
$viewableData = new ViewableData();
$this->assertFalse($viewableData->hasDynamicData('abc'));
$viewableData->setDynamicData('abc', $obj);
$this->assertTrue($viewableData->hasDynamicData('abc'));
$this->assertSame($obj, $viewableData->getDynamicData('abc'));
$this->assertSame($obj, $viewableData->abc);
}
} }