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

View File

@ -73,7 +73,7 @@ class ViewableData implements IteratorAggregate
/**
* 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)
{
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)) {
return $this->$field;
}
return $this->data[$field];
return $this->getDynamicData($field);
}
/**
@ -236,10 +236,25 @@ class ViewableData implements IteratorAggregate
if ($this->isAccessibleProperty($field)) {
$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;
}
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.
* 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\DataObject;
use SilverStripe\Dev\SapphireTest;
use InvalidArgumentException;
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('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']);
$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);
}
}