Skip to content

Commit

Permalink
Drop entity parameter from {HasOneSql, HasMany}::refLink() method (#1182
Browse files Browse the repository at this point in the history
)
  • Loading branch information
mvorisek authored Mar 9, 2024
1 parent fe03a22 commit dd97646
Show file tree
Hide file tree
Showing 23 changed files with 184 additions and 153 deletions.
2 changes: 1 addition & 1 deletion docs/persistence.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ protected function init(): void
$this->getOwner()->hasOne(
$f . '_currency_id',
[
$this->currency_model ?? new Currency(),
'model' => $this->currency_model ?? new Currency(),
'system' => true,
]
);
Expand Down
2 changes: 1 addition & 1 deletion src/Field.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public function __construct(array $defaults = [])
{
$this->setDefaults($defaults);

if (!(new \ReflectionProperty($this, 'type'))->isInitialized($this)) {
if (($this->type ?? null) === null) {
$this->type = 'string';
}
}
Expand Down
9 changes: 7 additions & 2 deletions src/Model.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,7 @@ class Model implements \IteratorAggregate
/** @var string|null */
public $tableAlias;

/** @var Persistence|null */
private $_persistence;
private ?Persistence $_persistence = null;

/** @var array<string, mixed>|null Persistence store some custom information in here that may be useful for them. */
public ?array $persistenceData = null;
Expand Down Expand Up @@ -534,6 +533,12 @@ public function addField(string $name, $seed = []): Field
{
$this->assertIsModel();

if ($this->hasField($name)) {
throw (new Exception('Field with such name already exists'))
->addMoreInfo('name', $name)
->addMoreInfo('seed', $seed);
}

if (is_object($seed)) {
$field = $seed;
} else {
Expand Down
6 changes: 3 additions & 3 deletions src/Model/ReferencesTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -155,14 +155,14 @@ public function ref(string $link, array $defaults = []): Model
}

/**
* Traverse reference and create their model but keep condition not materialized (for subquery actions).
* Traverse reference and create their model but keep reference condition not materialized (for subquery actions).
*
* @param array<string, mixed> $defaults
*/
public function refLink(string $link, array $defaults = []): Model
{
$reference = $this->getModel(true)->getReference($link);
$reference = $this->getReference($link);

return $reference->refLink($this, $defaults);
return $reference->refLink($defaults);
}
}
14 changes: 7 additions & 7 deletions src/Model/Scope/Condition.php
Original file line number Diff line number Diff line change
Expand Up @@ -287,12 +287,14 @@ public function negate(): self
#[\Override]
public function toWords(Model $model = null): string
{
if ($model === null) {
if ($model !== null) {
$model->assertIsModel();
} else {
$model = $this->getModel();
}

if ($model === null) {
throw new Exception('Condition must be associated with Model to convert to words');
if ($model === null) {
throw new Exception('Condition must be associated with model to convert to words');
}
}

$field = $this->fieldToWords($model);
Expand Down Expand Up @@ -405,9 +407,7 @@ protected function valueToWords(Model $model, $value): string
$title = null;
if ($field instanceof Field && $field->hasReference()) {
// make sure we set the value in the Model
$entity = $model->isEntity()
? clone $model
: $model->createEntity();
$entity = $model->createEntity();
$entity->set($field->shortName, $value);

// then take the title
Expand Down
6 changes: 6 additions & 0 deletions src/Model/UserActionsTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ public function addUserAction(string $name, $seed = []): UserAction
{
$this->assertIsModel();

if ($this->hasUserAction($name)) {
throw (new Exception('User action with such name already exists'))
->addMoreInfo('name', $name)
->addMoreInfo('seed', $seed);
}

if ($seed instanceof \Closure) {
$seed = ['callback' => $seed];
}
Expand Down
24 changes: 10 additions & 14 deletions src/Reference.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,12 @@ protected function assertReferenceValueNotNull($value): void
public function getOurFieldName(): string
{
return $this->ourField
?? $this->getOurModel(null)->idField;
?? $this->getOurModel()->idField;
}

final protected function getOurField(): Field
{
return $this->getOurModel(null)->getField($this->getOurFieldName());
return $this->getOurModel()->getField($this->getOurFieldName());
}

/**
Expand All @@ -141,7 +141,7 @@ protected function onHookToOurModel(string $spot, \Closure $fx, array $args = []
{
$name = $this->shortName; // use static function to allow this object to be GCed

return $this->getOurModel(null)->onHookDynamic(
return $this->getOurModel()->onHookDynamic(
$spot,
static function (Model $modelOrEntity) use ($name): self {
/** @var self */
Expand All @@ -164,7 +164,7 @@ protected function onHookToTheirModel(Model $theirModel, string $spot, \Closure
{
$theirModel->assertIsModel();

$ourModel = $this->getOurModel(null);
$ourModel = $this->getOurModel();
$name = $this->shortName; // use static function to allow this object to be GCed

return $theirModel->onHookDynamic(
Expand Down Expand Up @@ -203,22 +203,18 @@ public function assertOurModelOrEntity(Model $ourModelOrEntity): void
->assertIsModel($ourModelOrEntity->getModel(true));
}

public function getOurModel(?Model $ourModelOrEntity): Model
public function getOurModel(): Model
{
$ourModel = $ourModelOrEntity !== null
? $ourModelOrEntity->getModel(true)
: $this->getOwner();

$this->getOwner()
->assertIsModel($ourModel);
$ourModel = $this->getOwner();
$ourModel->assertIsModel();

return $ourModel;
}

protected function initTableAlias(): void
{
if (!$this->tableAlias) {
$ourModel = $this->getOurModel(null);
$ourModel = $this->getOurModel();

$aliasFull = $this->link;
$alias = preg_replace('~_(' . preg_quote($ourModel->idField !== false ? $ourModel->idField : '', '~') . '|id)$~', '', $aliasFull);
Expand All @@ -238,7 +234,7 @@ protected function initTableAlias(): void
*/
protected function getDefaultPersistence(Model $theirModel)
{
$ourModel = $this->getOurModel(null);
$ourModel = $this->getOurModel();

// this is useful for ContainsOne/Many implementation in case when you have
// SQL_Model->containsOne()->hasOne() structure to get back to SQL persistence
Expand All @@ -261,7 +257,7 @@ protected function createTheirModelBeforeInit(array $defaults): Model

// if model is Closure, then call the closure and it should return a model
if ($this->model instanceof \Closure) {
$m = ($this->model)($this->getOurModel(null), $this, $defaults);
$m = ($this->model)($this->getOurModel(), $this, $defaults);
} else {
$m = $this->model;
}
Expand Down
4 changes: 2 additions & 2 deletions src/Reference/ContainsBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ protected function init(): void
{
parent::init();

if (!$this->ourField) {
if ($this->ourField === null) {
$this->ourField = $this->link;
}

$ourModel = $this->getOurModel(null);
$ourModel = $this->getOurModel();

$ourField = $this->getOurFieldName();
if (!$ourModel->hasField($ourField)) {
Expand Down
3 changes: 1 addition & 2 deletions src/Reference/ContainsMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ public function ref(Model $ourModelOrEntity, array $defaults = []): Model
$this->assertOurModelOrEntity($ourEntity);
$ourEntity->assertIsEntity();

/** @var Persistence\Array_ */
$persistence = $theirEntity->getModel()->getPersistence();
$persistence = Persistence\Array_::assertInstanceOf($theirEntity->getModel()->getPersistence());
$rows = $persistence->getRawDataByTable($theirEntity->getModel(), $this->tableAlias); // @phpstan-ignore-line
$ourEntity->save([$this->getOurFieldName() => $rows !== [] ? $rows : null]);
});
Expand Down
3 changes: 1 addition & 2 deletions src/Reference/ContainsOne.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ public function ref(Model $ourModelOrEntity, array $defaults = []): Model
$this->assertOurModelOrEntity($ourEntity);
$ourEntity->assertIsEntity();

/** @var Persistence\Array_ */
$persistence = $theirEntity->getModel()->getPersistence();
$persistence = Persistence\Array_::assertInstanceOf($theirEntity->getModel()->getPersistence());
$row = $persistence->getRawDataByTable($theirEntity->getModel(), $this->tableAlias); // @phpstan-ignore-line
$row = $row ? array_shift($row) : null; // get first and only one record from array persistence
$ourEntity->save([$this->getOurFieldName() => $row]);
Expand Down
28 changes: 13 additions & 15 deletions src/Reference/HasMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,17 @@ private function getModelTableString(Model $model): string
#[\Override]
public function getTheirFieldName(Model $theirModel = null): string
{
if ($this->theirField) {
if ($this->theirField !== null) {
return $this->theirField;
}

// this is pure guess, verify if such field exist, otherwise throw
// TODO probably remove completely in the future
$ourModel = $this->getOurModel(null);
$ourModel = $this->getOurModel();
$theirFieldName = preg_replace('~^.+\.~s', '', $this->getModelTableString($ourModel)) . '_' . $ourModel->idField;
if (!($theirModel ?? $this->createTheirModel())->hasField($theirFieldName)) {
throw (new Exception('Their model does not contain fallback field'))
->addMoreInfo('their_fallback_field', $theirFieldName);
throw (new Exception('Their model does not contain implicit field'))
->addMoreInfo('theirImplicitField', $theirFieldName);
}

return $theirFieldName;
Expand All @@ -50,7 +50,7 @@ protected function getOurFieldValueForRefCondition(Model $ourModelOrEntity)
$this->assertOurModelOrEntity($ourModelOrEntity);

if ($ourModelOrEntity->isEntity()) {
$res = $this->ourField
$res = $this->ourField !== null
? $ourModelOrEntity->get($this->ourField)
: $ourModelOrEntity->getId();
$this->assertReferenceValueNotNull($res);
Expand All @@ -71,7 +71,7 @@ protected function referenceOurValue(): Field
{
// TODO horrible hack to render the field with a table prefix,
// find a solution how to wrap the field inside custom Field (without owner?)
$ourModelCloned = clone $this->getOurModel(null);
$ourModelCloned = clone $this->getOurModel();
$ourModelCloned->persistenceData['use_table_prefixes'] = true;

return $ourModelCloned->getReference($this->link)->getOurField();
Expand All @@ -96,10 +96,8 @@ public function ref(Model $ourModelOrEntity, array $defaults = []): Model
*
* @param array<string, mixed> $defaults
*/
public function refLink(?Model $ourModel, array $defaults = []): Model
public function refLink(array $defaults = []): Model
{
$this->getOurModel($ourModel); // or should $this->assertOurModelOrEntity($ourModelOrEntity); be here? What is exactly the difference between ref and refLink?
$theirModelLinked = $this->createTheirModel($defaults)->addCondition(
$this->getTheirFieldName(),
$this->referenceOurValue()
Expand Down Expand Up @@ -134,7 +132,7 @@ public function addField(string $fieldName, array $defaults = []): Field

if (isset($defaults['expr'])) {
$fx = function () use ($defaults, $alias) {
$theirModelLinked = $this->refLink(null);
$theirModelLinked = $this->refLink();

return $theirModelLinked->action('field', [$theirModelLinked->expr(
$defaults['expr'],
Expand All @@ -144,15 +142,15 @@ public function addField(string $fieldName, array $defaults = []): Field
unset($defaults['args']);
} elseif (is_object($defaults['aggregate'])) {
$fx = function () use ($defaults, $alias) {
return $this->refLink(null)->action('field', [$defaults['aggregate'], 'alias' => $alias]);
return $this->refLink()->action('field', [$defaults['aggregate'], 'alias' => $alias]);
};
} elseif ($defaults['aggregate'] === 'count' && !isset($defaults['field'])) {
$fx = function () use ($alias) {
return $this->refLink(null)->action('count', ['alias' => $alias]);
return $this->refLink()->action('count', ['alias' => $alias]);
};
} elseif (in_array($defaults['aggregate'], ['sum', 'avg', 'min', 'max', 'count'], true)) {
$fx = function () use ($defaults, $field) {
return $this->refLink(null)->action('fx0', [$defaults['aggregate'], $field]);
return $this->refLink()->action('fx0', [$defaults['aggregate'], $field]);
};
} else {
$fx = function () use ($defaults, $field) {
Expand All @@ -161,11 +159,11 @@ public function addField(string $fieldName, array $defaults = []): Field
$args['concatSeparator'] = $defaults['concatSeparator'];
}

return $this->refLink(null)->action('fx', $args);
return $this->refLink()->action('fx', $args);
};
}

return $this->getOurModel(null)->addExpression($fieldName, array_merge($defaults, ['expr' => $fx]));
return $this->getOurModel()->addExpression($fieldName, array_merge($defaults, ['expr' => $fx]));
}

/**
Expand Down
10 changes: 5 additions & 5 deletions src/Reference/HasOne.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ protected function init(): void
{
parent::init();

if (!$this->ourField) {
if ($this->ourField === null) {
$this->ourField = $this->link;
}

// for references use "integer" as a default type
if (!(new \ReflectionProperty($this, 'type'))->isInitialized($this)) {
if (($this->type ?? null) === null) {
$this->type = 'integer';
}

Expand All @@ -32,7 +32,7 @@ protected function init(): void
$fieldPropsRefl = (new \ReflectionClass(Model\FieldPropertiesTrait::class))->getProperties();
$fieldPropsRefl[] = (new \ReflectionClass(Model\JoinLinkTrait::class))->getProperty('joinName');

$ourModel = $this->getOurModel(null);
$ourModel = $this->getOurModel();
if (!$ourModel->hasField($this->ourField)) {
$fieldSeed = [];
foreach ($fieldPropsRefl as $fieldPropRefl) {
Expand Down Expand Up @@ -63,7 +63,7 @@ protected function referenceOurValue(): Field
{
// TODO horrible hack to render the field with a table prefix,
// find a solution how to wrap the field inside custom Field (without owner?)
$ourModelCloned = clone $this->getOurModel(null);
$ourModelCloned = clone $this->getOurModel();
$ourModelCloned->persistenceData['use_table_prefixes'] = true;

return $ourModelCloned->getReference($this->link)->getOurField();
Expand All @@ -84,7 +84,7 @@ public function ref(Model $ourModelOrEntity, array $defaults = []): Model

if ($ourModelOrEntity->isEntity()) {
$this->onHookToTheirModel($theirModel, Model::HOOK_AFTER_SAVE, function (Model $theirEntity) use ($ourModelOrEntity) {
$theirValue = $this->theirField
$theirValue = $this->theirField !== null
? $theirEntity->get($this->theirField)
: $theirEntity->getId();

Expand Down
Loading

0 comments on commit dd97646

Please sign in to comment.