From 9e200a052fd7485b4e2309a156890e9cd8a97260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Sun, 12 Jan 2025 10:55:18 +0100 Subject: [PATCH] Fix HasOneSql::addField() implicit caption (#1239) --- src/Persistence/Static_.php | 8 ++--- src/Reference/HasOneSql.php | 23 +++++++++++-- tests/ReferenceSqlTest.php | 66 ++++++++++++++++++++++++++++++++++--- 3 files changed, 86 insertions(+), 11 deletions(-) diff --git a/src/Persistence/Static_.php b/src/Persistence/Static_.php index de165d7cc..dba6c8fe3 100644 --- a/src/Persistence/Static_.php +++ b/src/Persistence/Static_.php @@ -17,10 +17,10 @@ class Static_ extends Array_ { /** @var string This will be the title field for the model. */ - public $titleFieldForModel; + public ?string $titleFieldForModel = null; /** @var array> Populate the following fields for the model. */ - public $fieldsForModel = []; + public array $fieldsForModel; /** * @param array $data @@ -88,7 +88,7 @@ public function __construct(array $data = []) } // if title is not set, use first key - if (!$this->titleFieldForModel) { + if ($this->titleFieldForModel === null) { if (is_int($k)) { $keyOverride[$k] = 'name'; $this->titleFieldForModel = 'name'; @@ -162,7 +162,7 @@ public function add(Model $model, array $defaults = []): void */ protected function addMissingFieldsToModel(Model $model): void { - if ($this->titleFieldForModel) { + if ($this->titleFieldForModel !== null) { $model->titleField = $this->titleFieldForModel; } diff --git a/src/Reference/HasOneSql.php b/src/Reference/HasOneSql.php index 0a3fed511..fe9ea46e9 100644 --- a/src/Reference/HasOneSql.php +++ b/src/Reference/HasOneSql.php @@ -64,6 +64,22 @@ private function _addField(string $fieldName, bool $theirFieldIsTitle, ?string $ return $fieldExpression; } + private function getLinkNameWithoutReferenceSuffix(Model $theirModel): string + { + $ourModel = $this->getOurModel(); + $theirFieldName = $this->getTheirFieldName($theirModel); + + return preg_replace('~_(' . preg_quote($theirFieldName, '~') . '|' . preg_quote($ourModel->idField, '~') . '|id)$~', '', $this->link); + } + + private function getOurFieldCaptionWithoutReferenceSuffix(Model $theirModel): string + { + $ourModel = $this->getOurModel(); + $theirField = $theirModel->getField($this->getTheirFieldName($theirModel)); + + return preg_replace('~ (' . preg_quote($theirField->getCaption(), '~') . '|' . preg_quote($ourModel->getIdField()->getCaption(), '~') . '|ID)$~i', '', $this->getOurField()->getCaption()); + } + /** * Creates expression which sub-selects a field inside related model. * @@ -76,14 +92,14 @@ public function addField(string $fieldName, ?string $theirFieldName = null, arra } $ourModel = $this->getOurModel(); + $analysingTheirModel = $ourModel->getReference($this->link)->createAnalysingTheirModel(); // if caption/type is not defined in $defaults then infer it from their field - $analysingTheirModel = $ourModel->getReference($this->link)->createAnalysingTheirModel(); $analysingTheirField = $analysingTheirModel->getField($theirFieldName); $defaults['type'] ??= $analysingTheirField->type; $defaults['enum'] ??= $analysingTheirField->enum; $defaults['values'] ??= $analysingTheirField->values; - $defaults['caption'] ??= $analysingTheirField->caption; + $defaults['caption'] ??= $this->getOurFieldCaptionWithoutReferenceSuffix($analysingTheirModel) . ' ' . $analysingTheirField->getCaption(); $defaults['ui'] = array_merge($defaults['ui'] ?? $analysingTheirField->ui, ['editable' => false]); $fieldExpression = $this->_addField($fieldName, false, $theirFieldName, $defaults); @@ -168,8 +184,9 @@ public function refLink(array $defaults = []): Model public function addTitle(array $defaults = []): SqlExpressionField { $ourModel = $this->getOurModel(); + $analysingTheirModel = $ourModel->getReference($this->link)->createAnalysingTheirModel(); - $fieldName = $defaults['field'] ?? preg_replace('~_(' . preg_quote($ourModel->idField, '~') . '|id)$~', '', $this->link); + $fieldName = $defaults['field'] ?? $this->getLinkNameWithoutReferenceSuffix($analysingTheirModel); $defaults['ui'] = array_merge(['visible' => true], $defaults['ui'] ?? [], ['editable' => false]); diff --git a/tests/ReferenceSqlTest.php b/tests/ReferenceSqlTest.php index 0a03f589d..f40b2f402 100644 --- a/tests/ReferenceSqlTest.php +++ b/tests/ReferenceSqlTest.php @@ -769,6 +769,31 @@ public function testAddTitle(): void self::assertSame($o->getField('user_id')->isVisible(), true); } + public function testHasOneTitleWholeIdField(): void + { + $this->setDb([ + 'user' => [ + 1 => ['user_id' => 1, 'name' => 'John'], + ], + 'order' => [ + ['amount' => '20', 'user_id' => 1], + ['amount' => '15', 'user_id' => 2], + ], + ]); + + $u = new Model($this->db, ['table' => 'user', 'idField' => 'user_id']); + $u->addField('name'); + + $o = new Model($this->db, ['table' => 'order']); + $o->addField('amount'); + + $o->hasOne('user_id', ['model' => $u]); + $referencedTitleField = $o->getReference('user_id')->addTitle(); + + self::assertSame('user', $referencedTitleField->shortName); + self::assertSame('User', $referencedTitleField->getCaption()); + } + /** * Tests that if we change hasOne->addTitle() field value then it will also update * link field value when saved. @@ -928,11 +953,44 @@ public function testHasOneReferenceCaption(): void $orderUserRef->addField('user_last_name', 'last_name'); $referencedCaption = $o->getField('user_last_name')->getCaption(); + self::assertSame('User Surname', $referencedCaption); + } + + public function testHasOneReferenceCaptionNonIdField(): void + { + $this->setDb([ + 'user' => [ + 1 => ['id' => 1, 'name' => 'John', 'last_name' => 'Doe'], + ['id' => 2, 'name' => 'Peter', 'last_name' => 'Foo'], + ['id' => 3, 'name' => 'Goofy', 'last_name' => 'Goo'], + ], + 'order' => [ + 1 => ['id' => 1, 'user_name' => 'John'], + ['id' => 2, 'user_name' => 'Peter'], + ['id' => 3, 'user_name' => 'John'], + ], + ]); + + $u = new Model($this->db, ['table' => 'user']); + $u->addField('name'); + $u->addField('last_name', ['caption' => 'Surname']); + + $o = (new Model($this->db, ['table' => 'order'])); + $orderUserRef = $o->hasOne('my_user', ['model' => $u, 'ourField' => 'user_name', 'theirField' => 'name']); + $orderUserRef->addField('user_last_name', 'last_name'); + + $referencedCaption = $o->getField('user_last_name')->getCaption(); + self::assertSame('User Surname', $referencedCaption); + + $referencedTitleField = $orderUserRef->addTitle(); + self::assertSame('my_user', $referencedTitleField->shortName); + self::assertSame('My User', $referencedTitleField->getCaption()); + + $orderUserRef2 = $o->hasOne('my_user2_name', ['model' => $u, 'ourField' => 'user_name', 'theirField' => 'name']); + $referenced2TitleField = $orderUserRef2->addTitle(); - // $field->caption for the field 'last_name' is defined in referenced model (User) - // When Order add field from Referenced model User - // caption will be passed to Order field user_last_name - self::assertSame('Surname', $referencedCaption); + self::assertSame('my_user2', $referenced2TitleField->shortName); + self::assertSame('My User 2', $referenced2TitleField->getCaption()); } /**