FIX Ensure getters and setters are respected (#10708)

This commit is contained in:
Guy Sartorelli 2023-03-01 15:19:07 +13:00 committed by GitHub
parent 981e20e298
commit e3a94b9d10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 203 additions and 7 deletions

View File

@ -46,7 +46,11 @@ class DBBoolean extends DBField
{
$fieldName = $this->name;
if ($fieldName) {
$dataObject->setField($fieldName, $this->value ? 1 : 0);
if ($this->value instanceof DBField) {
$this->value->saveInto($dataObject);
} else {
$dataObject->__set($fieldName, $this->value ? 1 : 0);
}
} else {
$class = static::class;
throw new \RuntimeException("DBField::saveInto() Called on a nameless '$class' object");

View File

@ -221,8 +221,12 @@ abstract class DBComposite extends DBField
{
foreach ($this->compositeDatabaseFields() as $field => $spec) {
// Save into record
$key = $this->getName() . $field;
$dataObject->setField($key, $this->getField($field));
if ($this->value instanceof DBField) {
$this->value->saveInto($dataObject);
} else {
$key = $this->getName() . $field;
$dataObject->__set($key, $this->getField($field));
}
}
}

View File

@ -88,8 +88,12 @@ class DBDecimal extends DBField
$fieldName = $this->name;
if ($fieldName) {
$value = (float) preg_replace('/[^0-9.\-\+]/', '', $this->value ?? '');
$dataObject->setField($fieldName, $value);
if ($this->value instanceof DBField) {
$this->value->saveInto($dataObject);
} else {
$value = (float) preg_replace('/[^0-9.\-\+]/', '', $this->value ?? '');
$dataObject->__set($fieldName, $value);
}
} else {
throw new \UnexpectedValueException(
"DBField::saveInto() Called on a nameless '" . static::class . "' object"

View File

@ -542,7 +542,11 @@ abstract class DBField extends ViewableData implements DBIndexable
"DBField::saveInto() Called on a nameless '" . static::class . "' object"
);
}
$dataObject->setField($fieldName, $this->value);
if ($this->value instanceof self) {
$this->value->saveInto($dataObject);
} else {
$dataObject->__set($fieldName, $this->value);
}
}
/**

View File

@ -45,7 +45,7 @@ class DBPercentage extends DBDecimal
$fieldName = $this->name;
if ($fieldName && $dataObject->$fieldName > 1.0) {
$dataObject->setField($fieldName, 1.0);
$dataObject->__set($fieldName, 1.0);
}
}
}

View File

@ -27,6 +27,7 @@ use SilverStripe\ORM\FieldType\DBTime;
use SilverStripe\ORM\FieldType\DBVarchar;
use SilverStripe\ORM\FieldType\DBText;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\FieldType\DBYear;
/**
@ -34,6 +35,9 @@ use SilverStripe\ORM\FieldType\DBYear;
*/
class DBFieldTest extends SapphireTest
{
protected static $extra_dataobjects = [
DBFieldTest\TestDataObject::class,
];
/**
* Test the nullValue() method on DBField.
@ -322,4 +326,73 @@ class DBFieldTest extends SapphireTest
$this->assertEquals('<P>ÅÄÖ</P>', DBHTMLText::create_field('HTMLFragment', '<p>åäö</p>')->UpperCase());
$this->assertEquals('<p>åäö</p>', DBHTMLText::create_field('HTMLFragment', '<p>ÅÄÖ</p>')->LowerCase());
}
public function testSaveInto()
{
$obj = new DBFieldTest\TestDataObject();
/** @var DBField $field */
$field = $obj->dbObject('Title');
$field->setValue('New Value');
$field->saveInto($obj);
$this->assertEquals('New Value', $obj->getField('Title'));
$this->assertEquals(1, $field->saveIntoCalledCount);
$this->assertEquals(1, $obj->setFieldCalledCount);
}
public function testSaveIntoNoRecursion()
{
$obj = new DBFieldTest\TestDataObject();
/** @var DBField $field */
$field = $obj->dbObject('Title');
$value = new DBFieldTest\TestDbField('Title');
$value->setValue('New Value');
$field->setValue($value);
$field->saveInto($obj);
$this->assertEquals('New Value', $obj->getField('Title'));
$this->assertEquals(1, $field->saveIntoCalledCount);
$this->assertEquals(1, $obj->setFieldCalledCount);
}
public function testSaveIntoAsProperty()
{
$obj = new DBFieldTest\TestDataObject();
/** @var DBField $field */
$field = $obj->dbObject('Title');
$field->setValue('New Value');
$obj->Title = $field;
$this->assertEquals('New Value', $obj->getField('Title'));
$this->assertEquals(1, $field->saveIntoCalledCount);
// Called twice because $obj->setField($field) => $field->saveInto() => $obj->setField('New Value')
$this->assertEquals(2, $obj->setFieldCalledCount);
}
public function testSaveIntoNoRecursionAsProperty()
{
$obj = new DBFieldTest\TestDataObject();
/** @var DBField $field */
$field = $obj->dbObject('Title');
$value = new DBFieldTest\TestDbField('Title');
$value->setValue('New Value');
$field->setValue($value);
$obj->Title = $field;
$this->assertEquals('New Value', $obj->getField('Title'));
$this->assertEquals(1, $field->saveIntoCalledCount);
// Called twice because $obj->setField($field) => $field->saveInto() => $obj->setField('New Value')
$this->assertEquals(2, $obj->setFieldCalledCount);
}
public function testSaveIntoRespectsSetters()
{
$obj = new DBFieldTest\TestDataObject();
/** @var DBField $field */
$field = $obj->dbObject('MyTestField');
$field->setValue('New Value');
$obj->MyTestField = $field;
$this->assertEquals('new value', $obj->getField('MyTestField'));
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace SilverStripe\ORM\Tests\DBFieldTest;
use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\DataObject;
class TestDataObject extends DataObject implements TestOnly
{
private static $table_name = 'DBFieldTest_TestDataObject';
private static $db = [
'Title' => TestDbField::class,
'MyTestField' => TestDbField::class,
];
public $setFieldCalledCount = 0;
public function setField($fieldName, $val)
{
$this->setFieldCalledCount++;
return parent::setField($fieldName, $val);
}
public function setMyTestField($val)
{
return $this->setField('MyTestField', strtolower($val));
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace SilverStripe\ORM\Tests\DBFieldTest;
use SilverStripe\Core\Config\Config;
use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\DB;
use SilverStripe\ORM\FieldType\DBField;
class TestDbField extends DBField implements TestOnly
{
public function requireField()
{
// Basically the same as DBVarchar but we don't want to test with DBVarchar in case something
// changes in that class eventually.
$charset = Config::inst()->get(MySQLDatabase::class, 'charset');
$collation = Config::inst()->get(MySQLDatabase::class, 'collation');
$parts = [
'datatype' => 'varchar',
'precision' => 255,
'character set' => $charset,
'collate' => $collation,
'arrayValue' => $this->arrayValue
];
$values = [
'type' => 'varchar',
'parts' => $parts
];
DB::require_field($this->tableName, $this->name, $values);
}
public $saveIntoCalledCount = 0;
public function saveInto($dataObject)
{
$this->saveIntoCalledCount++;
return parent::saveInto($dataObject);
}
}

View File

@ -66,6 +66,7 @@ class DataObjectTest extends SapphireTest
DataObjectTest\TreeNode::class,
DataObjectTest\OverriddenDataObject::class,
DataObjectTest\InjectedDataObject::class,
DataObjectTest\SettersAndGetters::class,
];
protected function setUp(): void
@ -2667,4 +2668,14 @@ class DataObjectTest extends SapphireTest
$vals = ['25.25', '50.00', '75.00', '100.50'];
$this->assertSame(array_combine($vals ?? [], $vals ?? []), $obj->dbObject('MyEnumWithDots')->enumValues());
}
public function testSettersAndGettersAreRespected()
{
$obj = new DataObjectTest\SettersAndGetters();
$obj->MyTestField = 'Some Value';
// Setter overrides it with all lower case
$this->assertSame('some value', $obj->getField('MyTestField'));
// Getter overrides it with all upper case
$this->assertSame('SOME VALUE', $obj->MyTestField);
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace SilverStripe\ORM\Tests\DataObjectTest;
use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\DataObject;
class SettersAndGetters extends DataObject implements TestOnly
{
private static $table_name = 'DataObjectTest_SettersAndGetters';
private static $db = [
'MyTestField' => 'Varchar(255)',
];
public function setMyTestField($val)
{
$this->setField('MyTestField', strtolower($val));
}
public function getMyTestField()
{
return strtoupper($this->getField('MyTestField'));
}
}