Skip to content

Commit

Permalink
Fix HasOneSql::addField() implicit caption (#1239)
Browse files Browse the repository at this point in the history
  • Loading branch information
mvorisek authored Jan 12, 2025
1 parent afd31ee commit 9e200a0
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 11 deletions.
8 changes: 4 additions & 4 deletions src/Persistence/Static_.php
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, array<mixed>> Populate the following fields for the model. */
public $fieldsForModel = [];
public array $fieldsForModel;

/**
* @param array<int|string, mixed> $data
Expand Down Expand Up @@ -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';
Expand Down Expand Up @@ -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;
}

Expand Down
23 changes: 20 additions & 3 deletions src/Reference/HasOneSql.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand All @@ -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);
Expand Down Expand Up @@ -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]);

Expand Down
66 changes: 62 additions & 4 deletions tests/ReferenceSqlTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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());
}

/**
Expand Down

0 comments on commit 9e200a0

Please sign in to comment.