From 560f8a2796e7fda2bd6c52583639b25714d4fb98 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Fri, 12 Jan 2024 00:30:21 +0000 Subject: [PATCH] continue implementations --- Autoloader.php | 12 ----- DataStorage/Database/GrammarAbstract.php | 3 ++ .../Database/Mapper/DataMapperFactory.php | 8 ---- DataStorage/Database/Mapper/ReadMapper.php | 46 +++++++++++-------- DataStorage/Database/Mapper/WriteMapper.php | 10 ++-- DataStorage/Database/Query/Builder.php | 2 + DataStorage/Database/Query/ColumnName.php | 33 +++++++++++++ .../Database/Query/Grammar/Grammar.php | 4 +- Localization/RegionEnum.php | 4 ++ Math/Parser/Evaluator.php | 4 +- 10 files changed, 79 insertions(+), 47 deletions(-) create mode 100644 DataStorage/Database/Query/ColumnName.php diff --git a/Autoloader.php b/Autoloader.php index ac9707707..2cc707fdc 100755 --- a/Autoloader.php +++ b/Autoloader.php @@ -183,18 +183,6 @@ final class Autoloader return; } - - /* - if (!isset($valid[$subclass])) { - foreach (self::$classmap as $map => $path) { - if (\str_starts_with($class, $map)) { - include_once $path . $class . '.php'; - - return; - } - } - } - */ } foreach (self::$paths as $path) { diff --git a/DataStorage/Database/GrammarAbstract.php b/DataStorage/Database/GrammarAbstract.php index ddc46920c..2ae41d70d 100755 --- a/DataStorage/Database/GrammarAbstract.php +++ b/DataStorage/Database/GrammarAbstract.php @@ -16,6 +16,7 @@ namespace phpOMS\DataStorage\Database; use phpOMS\Contract\SerializableInterface; use phpOMS\DataStorage\Database\Query\Column; +use phpOMS\DataStorage\Database\Query\ColumnName; use phpOMS\DataStorage\Database\Query\Parameter; /** @@ -299,6 +300,8 @@ abstract class GrammarAbstract return \rtrim(\rtrim(\number_format($value, 5, '.', ''), '0'), '.'); } elseif ($value instanceof Column) { return '(' . \rtrim($this->compileColumnQuery($value), ';') . ')'; + } elseif ($value instanceof ColumnName) { + return $this->compileSystem($value->name); } elseif ($value instanceof BuilderAbstract) { return '(' . \rtrim($value->toSql(), ';') . ')'; } elseif ($value instanceof \JsonSerializable) { diff --git a/DataStorage/Database/Mapper/DataMapperFactory.php b/DataStorage/Database/Mapper/DataMapperFactory.php index 47db33bbf..c32dc686a 100755 --- a/DataStorage/Database/Mapper/DataMapperFactory.php +++ b/DataStorage/Database/Mapper/DataMapperFactory.php @@ -108,14 +108,6 @@ class DataMapperFactory */ public const TABLE = ''; - /** - * Parent column. - * - * @var class-string - * @since 1.0.0 - */ - public const PARENT = ''; - /** * Model to use by the mapper. * diff --git a/DataStorage/Database/Mapper/ReadMapper.php b/DataStorage/Database/Mapper/ReadMapper.php index 9fc5488da..4c7e54e8a 100755 --- a/DataStorage/Database/Mapper/ReadMapper.php +++ b/DataStorage/Database/Mapper/ReadMapper.php @@ -282,7 +282,6 @@ final class ReadMapper extends DataMapperAbstract $value = $row[$this->mapper::PRIMARYFIELD . '_d' . $this->depth]; $obj[$value] = $this->mapper::createBaseModel($row); - $obj[$value] = $this->populateAbstract($row, $obj[$value]); $ids[] = $value; @@ -293,14 +292,16 @@ final class ReadMapper extends DataMapperAbstract // BUT the relation data is not available in the object itself meaning after retrieving the object // it cannot get assigned to the correct parent object. // Other relation types are easy because either the parent or child object contain the relation info. - $this->loadHasManyRelations($obj[$value]); + // One solution could be to always pass an array + if (!empty($this->with)) { + $this->loadHasManyRelations($obj[$value]); + } } - $countResulsts = \count($obj); - - if ($countResulsts === 0) { + $countResults = \count($obj); + if ($countResults === 0) { return $this->mapper::createNullModel(); - } elseif ($countResulsts === 1) { + } elseif ($countResults === 1) { return \reset($obj); } @@ -329,7 +330,10 @@ final class ReadMapper extends DataMapperAbstract foreach ($this->executeGetRawYield($query) as $row) { $obj = $this->mapper::createBaseModel($row); $obj = $this->populateAbstract($row, $obj); - $this->loadHasManyRelations($obj); + + if (!empty($this->with)) { + $this->loadHasManyRelations($obj); + } yield $obj; } @@ -565,7 +569,7 @@ final class ReadMapper extends DataMapperAbstract $query->fromAs($this->mapper::TABLE, $this->mapper::TABLE . '_d' . $this->depth); } - // Join tables manually without using "with()" (NOT has many/owns one etc.) + // Join tables manually without using "with()" (NOT hasMany/owns one etc.) // This is necessary for special cases, e.g. when joining in the other direction // Example: Show all profiles who have written a news article. // "with()" only allows to go from articles to accounts but we want to go the other way @@ -577,7 +581,7 @@ final class ReadMapper extends DataMapperAbstract /* variable in model */ // @todo join handling is extremely ugly, needs to be refactored foreach ($values as $join) { - // @todo the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails + // @todo the hasMany, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails if ($join['child'] !== '') { continue; } @@ -649,12 +653,12 @@ final class ReadMapper extends DataMapperAbstract /* variable in model */ $previous = null; foreach ($values as $where) { - // @todo the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails + // @todo the hasMany, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails if ($where['child'] !== '') { continue; } - $comparison = \is_array($where['value']) && \count($where['value']) > 1 ? 'in' : $where['logic']; + $comparison = \is_array($where['value']) && \count($where['value']) > 1 ? 'IN' : $where['logic']; if ($where['comparison'] === 'ALT') { // This uses an alternative value if the previous value(s) in the where clause don't exist (e.g. for localized results where you allow a user language, alternatively a primary language, and then alternatively any language if the first two don't exist). @@ -759,6 +763,7 @@ final class ReadMapper extends DataMapperAbstract $query->orderBy($this->mapper::TABLE . '_d' . $this->depth . '.' . $column, $sort['order']); break; // there is only one root element (one element with child === '') + // @todo Is this true? sort can have multiple sort components!!! } } @@ -846,7 +851,7 @@ final class ReadMapper extends DataMapperAbstract $value = $this->populateOwnsOne($def['internal'], $result, $default); - // loads has many relations. other relations are loaded in the populateOwnsOne + // loads hasMany relations. other relations are loaded in the populateOwnsOne if (\is_object($value) && isset($this->mapper::OWNS_ONE[$def['internal']]['mapper'])) { $this->mapper::OWNS_ONE[$def['internal']]['mapper']::reader(db: $this->db)->loadHasManyRelations($value); } @@ -865,7 +870,7 @@ final class ReadMapper extends DataMapperAbstract $value = $this->populateBelongsTo($def['internal'], $result, $default); - // loads has many relations. other relations are loaded in the populateBelongsTo + // loads hasMany relations. other relations are loaded in the populateBelongsTo if (\is_object($value) && isset($this->mapper::BELONGS_TO[$def['internal']]['mapper'])) { $this->mapper::BELONGS_TO[$def['internal']]['mapper']::reader(db: $this->db)->loadHasManyRelations($value); } @@ -916,7 +921,7 @@ final class ReadMapper extends DataMapperAbstract } } - // @todo How is this allowed? at the bottom we set $obj->hasMany = value. A has many should be always an array?! + // @todo How is this allowed? at the bottom we set $obj->hasMany = value. A hasMany should be always an array?! foreach ($this->mapper::HAS_MANY as $member => $def) { if (!isset($this->with[$member]) || !isset($def['column']) // @todo is this required? The code below indicates that this might be stupid @@ -1063,7 +1068,7 @@ final class ReadMapper extends DataMapperAbstract * @return mixed * * @todo in the future we could pass not only the $id ref but all of the data as a join!!! and save an additional select!!! - * @todo only the belongs to model gets populated the children of the belongsto model are always null models. either this function needs to call the get for the children, it should call get for the belongs to right away like the has many, or i find a way to recursevily load the data for all sub models and then populate that somehow recursively, probably too complex. + * @todo only the belongs to model gets populated the children of the belongsto model are always null models. either this function needs to call the get for the children, it should call get for the belongs to right away like the hasMany, or i find a way to recursevily load the data for all sub models and then populate that somehow recursively, probably too complex. * * @since 1.0.0 */ @@ -1129,6 +1134,9 @@ final class ReadMapper extends DataMapperAbstract return; } + // @todo only accept array and then perform this work on the array here + // this allows us to better load data for all objects at the same time! + $primaryKey = $this->mapper::getObjectId($obj); if (empty($primaryKey)) { return; @@ -1137,7 +1145,7 @@ final class ReadMapper extends DataMapperAbstract $refClass = null; // @todo check if there are more cases where the relation is already loaded with joins etc. - // there can be pseudo has many elements like localizations. They are has manies but these are already loaded with joins! + // there can be pseudo hasMany elements like localizations. They are hasMany but these are already loaded with joins! foreach ($this->with as $member => $withData) { if (isset($this->mapper::HAS_MANY[$member])) { $many = $this->mapper::HAS_MANY[$member]; @@ -1174,12 +1182,12 @@ final class ReadMapper extends DataMapperAbstract $refProp = $refClass->getProperty($member); $refProp->setValue($obj, !\is_array($objects) && ($many['conditional'] ?? false) === false ? [$many['mapper']::getObjectId($objects) => $objects] - : $objects // if conditional === true the obj will be assigned (e.g. has many localizations but only one is loaded for the model) + : $objects // if conditional === true the obj will be assigned (e.g. hasMany localizations but only one is loaded for the model) ); } else { $obj->{$member} = !\is_array($objects) && ($many['conditional'] ?? false) === false ? [$many['mapper']::getObjectId($objects) => $objects] - : $objects; // if conditional === true the obj will be assigned (e.g. has many localizations but only one is loaded for the model) + : $objects; // if conditional === true the obj will be assigned (e.g. hasMany localizations but only one is loaded for the model) } continue; @@ -1235,7 +1243,7 @@ final class ReadMapper extends DataMapperAbstract $refClass = null; // @todo check if there are more cases where the relation is already loaded with joins etc. - // there can be pseudo has many elements like localizations. They are has manies but these are already loaded with joins! + // there can be pseudo hasMany elements like localizations. They are has manies but these are already loaded with joins! foreach ($this->with as $member => $withData) { if (isset($this->mapper::HAS_MANY[$member])) { $many = $this->mapper::HAS_MANY[$member]; diff --git a/DataStorage/Database/Mapper/WriteMapper.php b/DataStorage/Database/Mapper/WriteMapper.php index 17b47aae3..24c38c968 100755 --- a/DataStorage/Database/Mapper/WriteMapper.php +++ b/DataStorage/Database/Mapper/WriteMapper.php @@ -286,12 +286,10 @@ final class WriteMapper extends DataMapperAbstract /** @var class-string $mapper */ $mapper = $this->mapper::HAS_MANY[$propertyName]['mapper']; - $internalName = isset($mapper::COLUMNS[$this->mapper::HAS_MANY[$propertyName]['self']]) - ? $mapper::COLUMNS[$this->mapper::HAS_MANY[$propertyName]['self']]['internal'] - : 'ERROR'; + $internalName = $mapper::COLUMNS[$this->mapper::HAS_MANY[$propertyName]['self']]['internal'] ?? 'ERROR-BAD-SELF'; // @todo this or $isRelPrivate is wrong, don't know which one. - $isInternalPrivate =$mapper::COLUMNS[$this->mapper::HAS_MANY[$propertyName]['self']]['private'] ?? false; + $isInternalPrivate = $mapper::COLUMNS[$this->mapper::HAS_MANY[$propertyName]['self']]['private'] ?? false; if (\is_object($values)) { // conditionals @@ -306,7 +304,9 @@ final class WriteMapper extends DataMapperAbstract $mapper::create(db: $this->db)->execute($values); continue; - } elseif (!\is_array($values)) { + } + + if (!\is_array($values)) { // @todo conditionals??? continue; } diff --git a/DataStorage/Database/Query/Builder.php b/DataStorage/Database/Query/Builder.php index 2c7988753..e4100081f 100755 --- a/DataStorage/Database/Query/Builder.php +++ b/DataStorage/Database/Query/Builder.php @@ -231,6 +231,8 @@ class Builder extends BuilderAbstract 'similar to', 'not similar to', 'in', + 'exists', + 'not exists', ]; /** diff --git a/DataStorage/Database/Query/ColumnName.php b/DataStorage/Database/Query/ColumnName.php new file mode 100644 index 000000000..afe50c59e --- /dev/null +++ b/DataStorage/Database/Query/ColumnName.php @@ -0,0 +1,33 @@ +name = $name; + } +} diff --git a/DataStorage/Database/Query/Grammar/Grammar.php b/DataStorage/Database/Query/Grammar/Grammar.php index 589741664..1fb68e702 100755 --- a/DataStorage/Database/Query/Grammar/Grammar.php +++ b/DataStorage/Database/Query/Grammar/Grammar.php @@ -17,6 +17,7 @@ namespace phpOMS\DataStorage\Database\Query\Grammar; use phpOMS\DataStorage\Database\BuilderAbstract; use phpOMS\DataStorage\Database\GrammarAbstract; use phpOMS\DataStorage\Database\Query\Builder; +use phpOMS\DataStorage\Database\Query\ColumnName; use phpOMS\DataStorage\Database\Query\From; use phpOMS\DataStorage\Database\Query\QueryType; use phpOMS\DataStorage\Database\Query\Where; @@ -273,7 +274,7 @@ class Grammar extends GrammarAbstract * * @param array $element Element data * @param Builder $query Query builder - * @param bool $first Is first element (usefull for nesting) + * @param bool $first Is first element (useful for nesting) * * @return string * @@ -459,6 +460,7 @@ class Grammar extends GrammarAbstract } // @todo on doesn't allow string values as value (only table column names). This is bad and needs to be fixed! + // Solution could be to use ColumnName as internal object and then pass it to compileValue in all cases // Other types such as int etc. are kind of possible if (isset($element['value'])) { $expression .= ' ' . \strtoupper($element['operator']) . ' ' diff --git a/Localization/RegionEnum.php b/Localization/RegionEnum.php index 24b6e4001..64df63c8c 100644 --- a/Localization/RegionEnum.php +++ b/Localization/RegionEnum.php @@ -89,4 +89,8 @@ class RegionEnum extends Enum public const ANTARCTICA = 'Antarctica'; public const CONTINENTS = 'Continents'; + + public const DOMESTIC = 'Domestic'; + + public const EXPORT = 'Export'; } diff --git a/Math/Parser/Evaluator.php b/Math/Parser/Evaluator.php index 459980ac7..e2e6b16c6 100755 --- a/Math/Parser/Evaluator.php +++ b/Math/Parser/Evaluator.php @@ -128,7 +128,7 @@ final class Evaluator return $n !== ''; }); - foreach ($equation as $i => $token) { + foreach ($equation as $token) { if (\is_numeric($token)) { $output[] = $token; } elseif (\strpbrk($token, '^*/+-') !== false) { @@ -140,7 +140,7 @@ final class Evaluator /*|| ($operators[$o1]['order'] === 1 && $operators[$o1]['precedence'] < $operators[$o2]['precedence'])*/) ) { // The commented part above is always FALSE because this equation always compares 4 < 2|3|4. - // Only uncomment if the opperators array changes. + // Only uncomment if the operators array changes. $output[] = \array_pop($stack); $o2 = \end($stack); }