Skip to content

Commit dcd11f4

Browse files
committed
dedup field value typecast
1 parent 39a2b2b commit dcd11f4

File tree

2 files changed

+38
-34
lines changed

2 files changed

+38
-34
lines changed

src/Field.php

+37-31
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,25 @@ public function setNull(): self
310310
return $this;
311311
}
312312

313+
/**
314+
* @param mixed $value
315+
*
316+
* @return mixed
317+
*/
318+
private function typecastSaveField($value, bool $allowDummyPersistence = false)
319+
{
320+
$persistence = $this->getOwner()->persistence;
321+
if ($persistence === null) {
322+
if ($allowDummyPersistence) {
323+
$persistence = (new \ReflectionClass(Persistence\Sql::class))->newInstanceWithoutConstructor();
324+
} else {
325+
$this->getOwner()->checkPersistence();
326+
}
327+
}
328+
329+
return $persistence->typecastSaveRow($this->getOwner(), [$this->short_name => $value])[$this->getPersistenceName()];
330+
}
331+
313332
/**
314333
* Compare new value of the field with existing one without retrieving.
315334
* In the trivial case it's same as ($value == $model->get($name)) but this method can be used for:
@@ -326,32 +345,17 @@ public function compare($value, $value2 = null): bool
326345
$value2 = $this->get();
327346
}
328347

329-
// TODO code below is not nice, we want to replace it, the purpose of the code is simply to
330-
// compare if typecasted values are the same using strict comparison (===) or nor
331-
$typecastFunc = function ($v) {
332-
// do not typecast null values, because that implies calling normalize() which tries to validate that value can't be null in case field value is required
333-
if ($v === null) {
334-
return $v;
335-
}
336-
337-
if ($this->getOwner()->persistence === null) {
338-
$v = $this->normalize($v);
339-
340-
// without persistence, we can not do a lot with non-scalar types, but as DateTime
341-
// is used often, fix the compare for them
342-
// TODO probably create and use a default persistence
343-
if (is_scalar($v)) {
344-
return (string) $v;
345-
} elseif ($v instanceof \DateTimeInterface) {
346-
return $v->getTimestamp() . '.' . $v->format('u');
347-
}
348-
349-
return serialize($v);
348+
$typecastFunc = function ($value): ?string {
349+
// do not typecast null values, because that implies calling normalize()
350+
// which tries to validate if value is not null in case field value is required
351+
if ($value === null) {
352+
return null;
350353
}
351354

352-
return (string) $this->getOwner()->persistence->typecastSaveRow($this->getOwner(), [$this->short_name => $v])[$this->getPersistenceName()];
355+
return (string) $this->typecastSaveField($value, true);
353356
};
354357

358+
// compare if typecasted values are the same using strict comparison
355359
return $typecastFunc($value) === $typecastFunc($value2);
356360
}
357361

@@ -388,24 +392,26 @@ public function useAlias(): bool
388392
public function getQueryArguments($operator, $value): array
389393
{
390394
$typecastField = $this;
395+
$allowArray = true;
391396
if (in_array($operator, [
392397
Scope\Condition::OPERATOR_LIKE,
393398
Scope\Condition::OPERATOR_NOT_LIKE,
394399
Scope\Condition::OPERATOR_REGEXP,
395400
Scope\Condition::OPERATOR_NOT_REGEXP,
396401
], true)) {
397402
$typecastField = new self(['type' => 'string']);
403+
$typecastField->setOwner(new Model($this->getOwner()->persistence, ['table' => false]));
404+
$typecastField->short_name = $this->short_name;
405+
$allowArray = false;
398406
}
399407

400-
if (is_array($value)) {
401-
$value = array_map(function ($option) use ($typecastField) {
402-
return $this->getOwner()->persistence->typecastSaveField($typecastField, $option);
403-
}, $value);
404-
} else {
405-
$value = $this->getOwner()->persistence->typecastSaveField($typecastField, $value);
406-
}
407-
408-
return [$this, $operator, $value];
408+
return [
409+
$this,
410+
$operator,
411+
is_array($value) && $allowArray
412+
? array_map(fn ($value) => $typecastField->typecastSaveField($value), $value)
413+
: $typecastField->typecastSaveField($value),
414+
];
409415
}
410416

411417
// }}}

src/Model.php

+1-3
Original file line numberDiff line numberDiff line change
@@ -1530,9 +1530,7 @@ public function save(array $data = [])
15301530
throw new Exception('Model::save() with 2nd param $to_persistence is no longer supported');
15311531
}
15321532

1533-
if (!$this->persistence) {
1534-
throw new Exception('Model is not associated with any persistence');
1535-
}
1533+
$this->checkPersistence();
15361534

15371535
if ($this->read_only) {
15381536
throw new Exception('Model is read-only and cannot be saved');

0 commit comments

Comments
 (0)