NEW Set many_many_extraFields data via the ORM

This commit is contained in:
Guy Sartorelli 2022-07-14 17:39:08 +12:00
parent 1253ab82af
commit af3c50c9da
2 changed files with 83 additions and 2 deletions

View File

@ -433,6 +433,58 @@ class ManyManyList extends RelationList
}
}
/**
* Set the extra field data for a single row of the relationship join
* table, given the known child ID.
*
* @param int $itemID The ID of the child for the relationship
* @param array $data The data to set, with field names as keys and values as values
* @throws InvalidArgumentException if the $data array is invalid
*/
public function setExtraData(int $itemID, array $data): void
{
// Don't bother doing anything if we aren't given any data
if (empty($data)) {
return;
}
// Prepare db manipulation
$foreignID = $this->getForeignID();
$manipulation = [
$this->joinTable => [
'command' => 'update',
'fields' => [],
'where' => [
"\"{$this->joinTable}\".\"{$this->foreignKey}\"" => $foreignID,
"\"{$this->joinTable}\".\"{$this->localKey}\"" => $itemID
],
],
];
/** @var DBField[] $fieldObjects */
$fieldObjects = [];
// Write extra field to manipluation in the same way
// that DataObject::prepareManipulationTable writes fields
foreach ($data as $fieldName => $value) {
if (!array_key_exists($fieldName, $this->extraFields)) {
throw new InvalidArgumentException("Field '$fieldName' is not defined in many_many_extraFields for this relationship");
}
$fieldObject = Injector::inst()->create($this->extraFields[$fieldName], $fieldName);
// Make sure the field assignment is not an array unless the field allows non-scalar values
if (is_array($value) && $fieldObject->scalarValueOnly()) {
throw new InvalidArgumentException(
'ManyManyList::setExtraData: parameterised field assignments are disallowed'
);
}
// Set the value into the manipulation
$fieldObject->setValue($value);
$fieldObject->writeToManipulation($manipulation[$this->joinTable]);
$fieldObjects[$fieldName] = $fieldObject;
}
DB::manipulate($manipulation);
}
/**
* Find the extra field data for a single row of the relationship join
* table, given the known child ID.

View File

@ -11,7 +11,6 @@ use SilverStripe\ORM\Tests\DataObjectTest\Player;
use SilverStripe\ORM\Tests\DataObjectTest\Team;
use SilverStripe\ORM\Tests\ManyManyListTest\ExtraFieldsObject;
use SilverStripe\ORM\Tests\ManyManyListTest\Product;
use InvalidArgumentException;
class ManyManyListTest extends SapphireTest
{
@ -73,7 +72,7 @@ class ManyManyListTest extends SapphireTest
// the actual test is that this does not generate an error in the sql.
$obj->Products()->add($product, [
'Reference' => 'Foo'
'Reference' => 'Foo',
]);
$result = $obj->Products()->First();
@ -81,6 +80,36 @@ class ManyManyListTest extends SapphireTest
$this->assertEquals('Test Product', $result->Title);
}
public function testSetExtraData()
{
$obj = new ManyManyListTest\ExtraFieldsObject();
$obj->write();
$obj2 = new ManyManyListTest\ExtraFieldsObject();
$obj2->write();
$money = new DBMoney();
$money->setAmount(100);
$money->setCurrency('USD');
// Set some data on add
$obj->Clients()->add($obj2, [
'Worth' => $money,
'Reference' => 'Foo',
]);
// Change the data afterward
$money->setAmount(50);
$obj->Clients()->setExtraData($obj2->ID, [
'Worth' => $money,
'Reference' => 'Bar',
]);
$result = $obj->Clients()->First();
$this->assertEquals('Bar', $result->Reference, 'Basic scalar fields should exist');
$this->assertInstanceOf(DBMoney::class, $result->Worth, 'Composite fields should exist on the record');
$this->assertEquals(50, $result->Worth->getAmount());
}
public function testCreateList()
{
$list = ManyManyList::create(