Skip to content

Commit

Permalink
Simplify field value typecast and drop Boolean Field class
Browse files Browse the repository at this point in the history
  • Loading branch information
mvorisek committed Oct 2, 2021
1 parent b06c578 commit 276f116
Show file tree
Hide file tree
Showing 14 changed files with 160 additions and 405 deletions.
2 changes: 1 addition & 1 deletion bootstrap-types.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform): ?str
return (string) round((float) $value, 4);
}

public function convertToPHPValue($value, AbstractPlatform $platform): float
public function convertToPHPValue($value, AbstractPlatform $platform): ?float
{
$v = $this->convertToDatabaseValue($value, $platform);

Expand Down
8 changes: 0 additions & 8 deletions docs/field_boolean.rst

This file was deleted.

9 changes: 1 addition & 8 deletions docs/model.rst
Original file line number Diff line number Diff line change
Expand Up @@ -230,16 +230,9 @@ Second argument to addField() will contain a seed for the Field class::

$this->addField('surname', ['default' => 'Smith']);

Additionally, `type` property can be used to determine the best `Field` class to handle
the type::

$field = $this->addField('is_married', ['type' => 'boolean']);

// $field class now will be Field\Boolean

You may also specify your own Field implementation::

$field = $this->addField('amount_and_currency', new MyAmountCurrencyField());
$field = $this->addField('amount_and_currency', [MyAmountCurrencyField::class]);

Read more about :php:class:`Field`

Expand Down
4 changes: 2 additions & 2 deletions docs/persistence.rst
Original file line number Diff line number Diff line change
Expand Up @@ -325,12 +325,12 @@ Type Matrix
| | | | | 4 | |
+----+----+----------------------------------------------------------+------+----+-----+
| bo | bo | true / false type value. Optionally specify | true | 1 | tru |
| ol | ol | 'enum' => ['N','Y'] to store true as 'Y' and false as 'N'. | | | e |
| ol | ol | 'enum' => ['N', 'Y'] to store true as Y and false as N. | | | e |
| | ea | By default uses [0,1]. | | | |
| | n | | | | |
+----+----+----------------------------------------------------------+------+----+-----+
| ar | | Optionally pass 'fmt' option, which is 'json' by | [2 => | {2 | sto |
| ra | | default. Will json\_encode and json\_decode(..., true) | "bar | :" | red |
| ra | | default. Will json_encode and json_decode(..., true) | "bar | :" | red |
| y | | the value if database does not support array storage. | "] | ba | as- |
| | | | | r" | is |
| | | | | } | |
Expand Down
16 changes: 1 addition & 15 deletions docs/types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ Supported Types
ATK Data prior to 1.5 supports the following types:

- string
- boolean ([':php:class:`Boolean`'])
- boolean
- integer ([':php:class:`Number`', 'precision' => 0])
- money ([':php:class:`Number`', 'prefix' => '€', 'precision' => 2])
- float ([':php:class:`Number`', 'type' => 'float'])
Expand Down Expand Up @@ -118,17 +118,3 @@ All measurements are implemented with :php:class:`Units` and can be further exte
echo $model->getField('speed')->format(); // 30km/s
echo $model->getField('speed')->format('m'); // 30000m/s


List of Field Classes
=====================

.. toctree::
:maxdepth: 1

field_boolean
field_text
field_number
field_datetime
field_units


133 changes: 81 additions & 52 deletions src/Field.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,75 +93,115 @@ public function normalize($value)
return $value;
}

if ($value === null) {
if ($this->required/* known bug, see https://github.com/atk4/data/issues/575, fix in https://github.com/atk4/data/issues/576 || $this->mandatory*/) {
throw new ValidationException([$this->name => 'Must not be null'], $this->getOwner());
if (is_string($value)) {
switch ($this->type) {
case null:
case 'string':
$value = trim(str_replace(["\r", "\n"], '', $value)); // remove all line-ends and trim

break;
case 'text':
$value = trim(str_replace(["\r\n", "\r"], "\n", $value)); // normalize line-ends to LF and trim

break;
case 'boolean':
case 'integer':
$value = preg_replace('/\s+|[,`\']/', '', $value);

break;
case 'float':
case 'atk4_money':
$value = preg_replace('/\s+|[,`\'](?=.*\.)/', '', $value);

break;
}

return null;
switch ($this->type) {
case 'boolean':
case 'integer':
case 'float':
case 'atk4_money':
if ($value === '') {
$value = null;
} elseif (!is_numeric($value)) {
throw new ValidationException([$this->name => 'Must be numeric'], $this->getOwner());
}

break;
}
} elseif ($value !== null) {
switch ($this->type) {
case null:
case 'string':
case 'text':
case 'integer':
case 'float':
case 'atk4_money':
if (is_bool($value)) {
if ($this->type === 'boolean') {
$value = $value ? '1' : '0';
} else {
throw new ValidationException([$this->name => 'Must not be boolean type'], $this->getOwner());
}
} elseif (is_scalar($value)) {
$value = (string) $value;
} else {
throw new ValidationException([$this->name => 'Must be scalar'], $this->getOwner());
}

break;
}
}

// normalize using persistence typecasting
$persistence = $this->getOwner()->persistence
?? new class() extends Persistence {
public function __construct()
{
}
};
try {
$value = $persistence->typecastSaveField($this, $value);
$value = $persistence->typecastLoadField($this, $value);
} catch (\Exception $e) {
throw new ValidationException([$this->name => $e->getMessage()], $this->getOwner());
}

// only string type fields can use empty string as legit value, for all
// other field types empty value is the same as no-value, nothing or null
if ($this->type && $this->type !== 'string' && $value === '') {
if ($this->required && empty($value)) {
throw new ValidationException([$this->name => 'Must not be empty'], $this->getOwner());
if ($value === null) {
if ($this->required/* known bug, see https://github.com/atk4/data/issues/575, fix in https://github.com/atk4/data/issues/576 || $this->mandatory*/) {
throw new ValidationException([$this->name => 'Must not be null'], $this->getOwner());
}

return null;
}

// validate scalar values
if (in_array($this->type, [null, 'string', 'text', 'integer', 'float', 'atk4_money'], true)) {
if (!is_scalar($value)) {
throw new ValidationException([$this->name => 'Must use scalar value'], $this->getOwner());
}

$value = (string) $value;
if ($value === '' && $this->required) {
throw new ValidationException([$this->name => 'Must not be empty'], $this->getOwner());
}

// normalize
switch ($this->type) {
case null:
case 'string':
$value = trim(str_replace(["\r", "\n"], '', $value)); // remove all line-ends and trim
if ($this->required && empty($value)) {
throw new ValidationException([$this->name => 'Must not be empty'], $this->getOwner());
}

break;
case 'text':
$value = trim(str_replace(["\r\n", "\r"], "\n", $value)); // normalize line-ends to LF and trim
if ($this->required && empty($value)) {
throw new ValidationException([$this->name => 'Must not be empty'], $this->getOwner());
}

break;
case 'integer':
$value = preg_replace('/\s+|[,`\']/', '', $value);
if (!is_numeric($value)) {
throw new ValidationException([$this->name => 'Must be numeric'], $this->getOwner());
}
$value = (int) $value;
case 'boolean':
if ($this->required && empty($value)) {
throw new ValidationException([$this->name => 'Must not be a zero'], $this->getOwner());
throw new ValidationException([$this->name => 'Must be true'], $this->getOwner());
}

break;
case 'integer':
case 'float':
case 'atk4_money':
$value = preg_replace('/\s+|[,`\'](?=.*\.)/', '', $value);
if (!is_numeric($value)) {
throw new ValidationException([$this->name => 'Must be numeric'], $this->getOwner());
}
$value = $this->getTypeObject()->convertToPHPValue($value, new Persistence\GenericPlatform());
if ($this->required && empty($value)) {
throw new ValidationException([$this->name => 'Must not be a zero'], $this->getOwner());
}

break;
case 'boolean':
throw new Exception('Use Field\Boolean for type=boolean');
case 'date':
case 'datetime':
case 'time':
Expand All @@ -184,20 +224,6 @@ public function normalize($value)
break;
}

// normalize using DBAL type
$persistence = $this->getOwner()->persistence
?? new class() extends Persistence {
public function __construct()
{
}
};
try {
$value = $persistence->typecastSaveField($this, $value);
$value = $persistence->typecastLoadField($this, $value);
} catch (\Exception $e) {
throw new ValidationException([$this->name => 'Invalid value: ' . $e->getMessage()], $this->getOwner());
}

return $value;
} catch (Exception $e) {
$e->addMoreInfo('field', $this);
Expand All @@ -214,6 +240,9 @@ public function __construct()
public function toString($value = null): string
{
$value = ($value === null /* why not func_num_args() === 1 */ ? $this->get() : $this->normalize($value));
if (is_bool($value)) {
$value = $value ? '1' : '0';
}

return (string) $this->typecastSaveField($value, true);
}
Expand Down
107 changes: 0 additions & 107 deletions src/Field/Boolean.php

This file was deleted.

Loading

0 comments on commit 276f116

Please sign in to comment.