From 542d62973e8c51acceb08e0bfc7f7c6f0c750491 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Sat, 9 Sep 2017 16:24:03 +0200 Subject: [PATCH 01/76] Fix initialization --- System/File/Ftp/FtpStorage.php | 14 ++++++++++++-- System/File/Local/LocalStorage.php | 15 +++++++++++++++ System/File/StorageAbstract.php | 18 +----------------- 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/System/File/Ftp/FtpStorage.php b/System/File/Ftp/FtpStorage.php index a681391fd..a96821930 100644 --- a/System/File/Ftp/FtpStorage.php +++ b/System/File/Ftp/FtpStorage.php @@ -32,9 +32,19 @@ class FtpStorage extends StorageAbstract { private $con = null; - public function __construct(string $uri, int $port = 21, bool $mode = true, string $login = null, string $pass = null, bool $ssl = false) + private static $instance = null; + + public function __construct() { + + } + + public static function getInstance() : StorageAbstract { - $this->connect($uri, $port = 21, $mode, $login = null, $pass = null, $ssl = false); + if(!isset(self::$instance)) { + self::$instance = new self(); + } + + return self::$instance; } public function connect(string $uri, int $port = 21, bool $mode = true, string $login = null, string $pass = null, bool $ssl = false) : bool diff --git a/System/File/Local/LocalStorage.php b/System/File/Local/LocalStorage.php index 3cce69807..6604da447 100644 --- a/System/File/Local/LocalStorage.php +++ b/System/File/Local/LocalStorage.php @@ -30,6 +30,21 @@ use phpOMS\System\File\StorageAbstract; */ class LocalStorage extends StorageAbstract { + private static $instance = null; + + public function __construct() { + + } + + public static function getInstance() : StorageAbstract + { + if(!isset(self::$instance)) { + self::$instance = new self(); + } + + return self::$instance; + } + /** * {@inheritdoc} */ diff --git a/System/File/StorageAbstract.php b/System/File/StorageAbstract.php index fc6793f66..d1fb38838 100644 --- a/System/File/StorageAbstract.php +++ b/System/File/StorageAbstract.php @@ -28,14 +28,6 @@ namespace phpOMS\System\File; */ abstract class StorageAbstract implements DirectoryInterface, FileInterface { - /** - * Singleton instance. - * - * @var StorageAbstract - * @since 1.0.0 - */ - protected static $instance = null; - /** * Storage type. * @@ -60,15 +52,7 @@ abstract class StorageAbstract implements DirectoryInterface, FileInterface * * @since 1.0.0 */ - public static function getInstance() : StorageAbstract - { - if(!isset(static::$instance)) { - static::$instance = new static(); - } - - return static::$instance; - } - + abstract public static function getInstance() : StorageAbstract; /** * Get storage type. * From 1be5c3495a4acb94ec1a197da796cdf79ae7b8b0 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Sat, 9 Sep 2017 21:18:58 +0200 Subject: [PATCH 02/76] fixes #101 --- DataStorage/Database/DataMapperAbstract.php | 240 +++++++++++++++++++- 1 file changed, 230 insertions(+), 10 deletions(-) diff --git a/DataStorage/Database/DataMapperAbstract.php b/DataStorage/Database/DataMapperAbstract.php index d117baba4..3d224e724 100644 --- a/DataStorage/Database/DataMapperAbstract.php +++ b/DataStorage/Database/DataMapperAbstract.php @@ -1264,11 +1264,11 @@ class DataMapperAbstract implements DataMapperInterface * @param array[] $result Result set * @param mixed $obj Object to add the relations to * - * @return mixed + * @return void * * @since 1.0.0 */ - public static function populateManyToMany(array $result, &$obj) + public static function populateManyToMany(array $result, &$obj) /* : void */ { // todo: maybe pass reflectionClass as optional parameter for performance increase $reflectionClass = new \ReflectionClass(get_class($obj)); @@ -1298,18 +1298,45 @@ class DataMapperAbstract implements DataMapperInterface } } + /** + * Populate data. + * + * @param array[] $result Result set + * @param array $obj Object to add the relations to + * + * @return void + * + * @since 1.0.0 + */ + public static function populateManyToManyArray(array $result, array &$obj) /* : void */ + { + foreach ($result as $member => $values) { + if (!empty($values)) { + /** @var DataMapperAbstract $mapper */ + $mapper = static::$hasMany[$member]['mapper']; + $values = array_diff($values, array_keys(self::$initObjects[$mapper] ?? [])); + if(empty($values)) { + continue; + } + + $objects = $mapper::getArray($values); + $obj[$member] = $objects; + } + } + } + /** * Populate data. * * @param mixed $obj Object to add the relations to * - * @return mixed + * @return void * * @todo accept reflection class as parameter * * @since 1.0.0 */ - public static function populateHasOne(&$obj) + public static function populateHasOne(&$obj) /* : void */ { $reflectionClass = new \ReflectionClass(get_class($obj)); @@ -1343,15 +1370,42 @@ class DataMapperAbstract implements DataMapperInterface /** * Populate data. * - * @param mixed $obj Object to add the relations to + * @param array $obj Object to add the relations to * - * @return mixed + * @return void * * @todo accept reflection class as parameter * * @since 1.0.0 */ - public static function populateOwnsOne(&$obj) + public static function populateHasOneArray(array &$obj) /* : void */ + { + foreach (static::$hasOne as $member => $one) { + /** @var DataMapperAbstract $mapper */ + $mapper = static::$hasOne[$member]['mapper']; + + if(self::isInitialized($mapper, $obj['member'])) { + $value = self::$initObjects[$mapper][$id]; + } else { + $value = $mapper::getArray($obj[$member]); + } + + $obj[$member] = $value; + } + } + + /** + * Populate data. + * + * @param mixed $obj Object to add the relations to + * + * @return void + * + * @todo accept reflection class as parameter + * + * @since 1.0.0 + */ + public static function populateOwnsOne(&$obj) /* : void */ { $reflectionClass = new \ReflectionClass(get_class($obj)); @@ -1385,15 +1439,42 @@ class DataMapperAbstract implements DataMapperInterface /** * Populate data. * - * @param mixed $obj Object to add the relations to + * @param array $obj Object to add the relations to * - * @return mixed + * @return void * * @todo accept reflection class as parameter * * @since 1.0.0 */ - public static function populateBelongsTo(&$obj) + public static function populateOwnsOneArray(array &$obj) /* : void */ + { + foreach (static::$ownsOne as $member => $one) { + /** @var DataMapperAbstract $mapper */ + $mapper = static::$ownsOne[$member]['mapper']; + + if(self::isInitialized($mapper, $obj[$member])) { + $value = self::$initObjects[$mapper][$id]; + } else { + $value = $mapper::getArray($obj[$member]); + } + + $obj[$member] = $value; + } + } + + /** + * Populate data. + * + * @param mixed $obj Object to add the relations to + * + * @return void + * + * @todo accept reflection class as parameter + * + * @since 1.0.0 + */ + public static function populateBelongsTo(&$obj) /* : void */ { $reflectionClass = new \ReflectionClass(get_class($obj)); @@ -1424,6 +1505,33 @@ class DataMapperAbstract implements DataMapperInterface } } + /** + * Populate data. + * + * @param array $obj Object to add the relations to + * + * @return void + * + * @todo accept reflection class as parameter + * + * @since 1.0.0 + */ + public static function populateBelongsToArray(array &$obj) /* : void */ + { + foreach (static::$belongsTo as $member => $one) { + /** @var DataMapperAbstract $mapper */ + $mapper = static::$belongsTo[$member]['mapper']; + + if(self::isInitialized($mapper, $obj[$member])) { + $value = self::$initObjects[$mapper][$id]; + } else { + $value = $mapper::get($obj[$member]); + } + + $obj[$member] = $value; + } + } + /** * Populate data. * @@ -1471,6 +1579,41 @@ class DataMapperAbstract implements DataMapperInterface return $obj; } + /** + * Populate data. + * + * @param array $result Query result set + * + * @return array + * + * @throws \UnexpectedValueException + * + * @since 1.0.0 + */ + public static function populateAbstractArray(array $result) : array + { + $obj = []; + + foreach ($result as $column => $value) { + if (isset(static::$columns[$column]['internal'])) { + if (in_array(static::$columns[$column]['type'], ['string', 'int', 'float', 'bool'])) { + settype($value, static::$columns[$column]['type']); + $obj[static::$columns[$column]['internal']] = $value; + } elseif (static::$columns[$column]['type'] === 'DateTime') { + $obj[static::$columns[$column]['internal']] = new \DateTime($value ?? ''); + } elseif (static::$columns[$column]['type'] === 'Json') { + $obj[static::$columns[$column]['internal']] = json_decode($value, true); + } elseif (static::$columns[$column]['type'] === 'Serializable') { + $obj[static::$columns[$column]['internal']] = $value; + } else { + throw new \UnexpectedValueException('Value "' . static::$columns[$column]['type'] . '" is not supported.'); + } + } + } + + return $obj; + } + /** * Get object. * @@ -1521,6 +1664,44 @@ class DataMapperAbstract implements DataMapperInterface return count($obj) === 1 ? reset($obj) : $obj; } + /** + * Get object. + * + * @param mixed $primaryKey Key + * @param int $relations Load relations + * + * @return mixed + * + * @since 1.0.0 + */ + public static function getArray($primaryKey, int $relations = RelationType::ALL) : array + { + if(!isset(self::$parentMapper)) { + self::setUpParentMapper(); + } + + self::extend(__CLASS__); + + $primaryKey = (array) $primaryKey; + $fill = (array) $fill; + $obj = []; + + foreach ($primaryKey as $key => $value) { + if(self::isInitialized(static::class, $value)) { + continue; + } + + $obj[$value] = self::populateAbstractArray(self::getRaw($value)); + + self::addInitialized(static::class, $value); + } + + self::fillRelationsArray($obj, $relations); + self::clear(); + + return count($obj) === 1 ? reset($obj) : $obj; + } + /** * Get object. * @@ -1694,6 +1875,45 @@ class DataMapperAbstract implements DataMapperInterface } } + /** + * Fill object with relations + * + * @param mixed $obj Objects to fill + * @param int $relations Relations type + * + * @return void + * + * @since 1.0.0 + */ + public static function fillRelationsArray(array &$obj, int $relations = RelationType::ALL) /* : void */ + { + $hasMany = !empty(static::$hasMany); + $hasOne = !empty(static::$hasOne); + $ownsOne = !empty(static::$ownsOne); + $belongsTo = !empty(static::$belongsTo); + + if ($relations !== RelationType::NONE && ($hasMany || $hasOne || $ownsOne || $belongsTo)) { + foreach ($obj as $key => $value) { + /* loading relations from relations table and populating them and then adding them to the object */ + if ($hasMany) { + self::populateManyToManyArray(self::getHasManyRaw($key, $relations), $obj[$key]); + } + + if ($hasOne) { + self::populateHasOneArray($obj[$key]); + } + + if ($ownsOne) { + self::populateOwnsOneArray($obj[$key]); + } + + if ($belongsTo) { + self::populateBelongsToArray($obj[$key]); + } + } + } + } + /** * Get object. * From a154cb489236c8d6fcb5bc6cbed9032acbdb3044 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Sat, 9 Sep 2017 22:35:27 +0200 Subject: [PATCH 03/76] Add array create --- DataStorage/Database/DataMapperAbstract.php | 184 ++++++++++++++++++++ 1 file changed, 184 insertions(+) diff --git a/DataStorage/Database/DataMapperAbstract.php b/DataStorage/Database/DataMapperAbstract.php index 3d224e724..8682f48ac 100644 --- a/DataStorage/Database/DataMapperAbstract.php +++ b/DataStorage/Database/DataMapperAbstract.php @@ -363,6 +363,31 @@ class DataMapperAbstract implements DataMapperInterface return $objId; } + /** + * Create object in db. + * + * @param array $obj Object reference (gets filled with insert id) + * @param int $relations Create all relations as well + * + * @return mixed + * + * @since 1.0.0 + */ + public static function createArray(array &$obj, int $relations = RelationType::ALL) + { + self::extend(__CLASS__); + + $objId = self::createModelArray($obj); + settype($objId, static::$columns[static::$primaryField]['type']); + $obj[static::$columns[static::$primaryField]['internal']] = $objId; + + if ($relations === RelationType::ALL) { + self::createHasManyArray($obj, $objId); + } + + return $objId; + } + /** * Create base model. * @@ -422,6 +447,52 @@ class DataMapperAbstract implements DataMapperInterface return self::$db->con->lastInsertId(); } + /** + * Create base model. + * + * @param Object $obj Model to create + * + * @return mixed + * + * @since 1.0.0 + */ + private static function createModelArray($obj) + { + $query = new Builder(self::$db); + $query->prefix(self::$db->getPrefix())->into(static::$table); + + foreach ($obj as $propertyName => &$property) { + if (isset(static::$hasMany[$propertyName]) || isset(static::$hasOne[$propertyName])) { + continue; + } + + foreach (static::$columns as $key => $column) { + if (isset(static::$ownsOne[$propertyName]) && $column['internal'] === $propertyName) { + $id = self::createOwnsOneArray($propertyName, $property); + $value = self::parseValue($column['type'], $id); + + $query->insert($column['name'])->value($value, $column['type']); + break; + } elseif (isset(static::$belongsTo[$propertyName]) && $column['internal'] === $propertyName) { + $id = self::createBelongsToArray($propertyName, $property); + $value = self::parseValue($column['type'], $id); + + $query->insert($column['name'])->value($value, $column['type']); + break; + } elseif ($column['internal'] === $propertyName && $column['type'] !== static::$primaryField) { + $value = self::parseValue($column['type'], $property); + + $query->insert($column['name'])->value($value, $column['type']); + break; + } + } + } + + self::$db->con->prepare($query->toSql())->execute(); + + return self::$db->con->lastInsertId(); + } + /** * Get id of object * @@ -559,6 +630,62 @@ class DataMapperAbstract implements DataMapperInterface } } + /** + * Create has many + * + * @param array $obj Object to create + * @param mixed $objId Id to set + * + * @return void + * + * @throws InvalidMapperException + * + * @since 1.0.0 + */ + private static function createHasManyArray(array &$obj, $objId) /* : void */ + { + foreach (static::$hasMany as $propertyName => $rel) { + $values = $obj[$propertyName]; + + if (!isset(static::$hasMany[$propertyName]['mapper'])) { + throw new InvalidMapperException(); + } + + /** @var DataMapperAbstract $mapper */ + $mapper = static::$hasMany[$propertyName]['mapper']; + $objsIds = []; + + foreach ($values as $key => &$value) { + if (!is_object($value)) { + // Is scalar => already in database + $objsIds[$key] = $value; + + continue; + } + + $primaryKey = $obj[static::$columns[static::$primaryField]['internal']]; + + // already in db + if (!empty($primaryKey)) { + $objsIds[$key] = $value; + + continue; + } + + // Setting relation value (id) for relation (since the relation is not stored in an extra relation table) + /** @var string $table */ + /** @var array $columns */ + if (static::$hasMany[$propertyName]['table'] === static::$hasMany[$propertyName]['mapper']::$table) { + $value[$mapper::$columns[static::$hasMany[$propertyName]['dst']]['internal']] = $objId; + } + + $objsIds[$key] = $mapper::createArray($value); + } + + self::createRelationTable($propertyName, $objsIds, $objId); + } + } + private static function createHasOne(\ReflectionClass $reflectionClass, $obj) { throw new \Exception(); @@ -596,6 +723,34 @@ class DataMapperAbstract implements DataMapperInterface return $obj; } + /** + * Create owns one + * + * The reference is stored in the main model + * + * @param string $propertyName Property name to initialize + * @param array $obj Object to create + * + * @return mixed + * + * @since 1.0.0 + */ + private static function createOwnsOneArray(string $propertyName, array &$obj) + { + if (is_array($obj)) { + $mapper = static::$ownsOne[$propertyName]['mapper']; + $primaryKey = $obj[static::$columns[static::$primaryField]['internal']]; + + if (empty($primaryKey)) { + return $mapper::createArray($obj); + } + + return $primaryKey; + } + + return $obj; + } + /** * Create owns one * @@ -625,6 +780,35 @@ class DataMapperAbstract implements DataMapperInterface return $obj; } + /** + * Create owns one + * + * The reference is stored in the main model + * + * @param string $propertyName Property name to initialize + * @param Object $obj Object to create + * + * @return mixed + * + * @since 1.0.0 + */ + private static function createBelongsToArray(string $propertyName, array $obj) + { + if (is_array($obj)) { + /** @var DataMapperAbstract $mapper */ + $mapper = static::$belongsTo[$propertyName]['mapper']; + $primaryKey = $obj[static::$columns[static::$primaryField]['internal']]; + + if (empty($primaryKey)) { + return $mapper::createArray($obj); + } + + return $primaryKey; + } + + return $obj; + } + /** * Create relation table entry * From e193a420075eff5b9a862819b31357de0e522452 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Wed, 13 Sep 2017 13:10:07 +0200 Subject: [PATCH 04/76] Create getFor() --- DataStorage/Database/DataMapperAbstract.php | 96 +++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/DataStorage/Database/DataMapperAbstract.php b/DataStorage/Database/DataMapperAbstract.php index 8682f48ac..4913fe973 100644 --- a/DataStorage/Database/DataMapperAbstract.php +++ b/DataStorage/Database/DataMapperAbstract.php @@ -1886,6 +1886,66 @@ class DataMapperAbstract implements DataMapperInterface return count($obj) === 1 ? reset($obj) : $obj; } + /** + * Get object. + * + * @param mixed $refKey Key + * @param string $ref The field that defines the for + * @param int $relations Load relations + * @param mixed $fill Object to fill + * + * @return mixed + * + * @since 1.0.0 + */ + public static function getFor($refKey, string $ref, int $relations = RelationType::ALL, $fill = null) + { + if(!isset(self::$parentMapper)) { + self::setUpParentMapper(); + } + + self::extend(__CLASS__); + + $refKey = (array) $refKey; + $obj = []; + + foreach ($refKey as $key => $value) { + // todo: this only works for belongsTo not for many-to-many relations. Implement many-to-many + $obj[$value] = self::get(self::getPrimaryKeyBy($value, self::getColumnByMember($ref)), $relations, $fill); + } + return count($obj) === 1 ? reset($obj) : $obj; + } + + /** + * Get object. + * + * @param mixed $refKey Key + * @param string $ref The field that defines the for + * @param int $relations Load relations + * @param mixed $fill Object to fill + * + * @return mixed + * + * @since 1.0.0 + */ + public static function getForArray($refKey, string $ref, int $relations = RelationType::ALL, $fill = null) + { + if(!isset(self::$parentMapper)) { + self::setUpParentMapper(); + } + + self::extend(__CLASS__); + + $refKey = (array) $refKey; + $obj = []; + + foreach ($refKey as $key => $value) { + // todo: this only works for belongsTo not for many-to-many relations. Implement many-to-many + $obj[$value] = self::getArray(self::getPrimaryKeyBy($value, self::getColumnByMember($ref)), $relations, $fill); + } + return count($obj) === 1 ? reset($obj) : $obj; + } + /** * Get object. * @@ -2120,6 +2180,31 @@ class DataMapperAbstract implements DataMapperInterface return is_bool($results) ? [] : $results; } + /** + * Get object. + * + * @param mixed $refKey Key + * @param string $ref Ref + * + * @return mixed + * + * @since 1.0.0 + */ + public static function getPrimaryKeyBy($refKey, string $ref) : array + { + $query = self::getQuery(); + $query->select(static::$primaryField) + ->from(static::$table) + ->where(static::$table . '.' . $ref, '=', $refKey); + + $sth = self::$db->con->prepare($query->toSql()); + $sth->execute(); + + $results = array_column($sth->fetchAll(\PDO::FETCH_NUM) ?? [], 0); + + return $results; + } + /** * Get all in raw output. * @@ -2352,4 +2437,15 @@ class DataMapperAbstract implements DataMapperInterface return count($results) === 0; } + + private static function getColumnByMember(string $name) : string + { + foreach(static::$columns as $cName => $column) { + if($column['internal'] === $name) { + return $cName; + } + } + + throw \Exception(); + } } From 354ca75009a5addc01b299966d58e1cbe91a674e Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Wed, 13 Sep 2017 13:13:15 +0200 Subject: [PATCH 05/76] Added more array selectors --- DataStorage/Database/DataMapperAbstract.php | 47 +++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/DataStorage/Database/DataMapperAbstract.php b/DataStorage/Database/DataMapperAbstract.php index 4913fe973..0f059248c 100644 --- a/DataStorage/Database/DataMapperAbstract.php +++ b/DataStorage/Database/DataMapperAbstract.php @@ -1413,6 +1413,30 @@ class DataMapperAbstract implements DataMapperInterface return $row; } + /** + * Populate data. + * + * @param array $result Result set + * + * @return array + * + * @since 1.0.0 + */ + public static function populateIterableArray(array $result) : array + { + $row = []; + + foreach ($result as $element) { + if (isset($element[static::$primaryField])) { + $row[$element[static::$primaryField]] = self::populateAbstractArray($element); + } else { + $row[] = self::populateAbstractArray($element); + } + } + + return $row; + } + /** * Populate data. * @@ -1969,6 +1993,29 @@ class DataMapperAbstract implements DataMapperInterface return $obj; } + /** + * Get object. + * + * @param int $relations Load relations + * @param string $lang Language + * + * @return array + * + * @since 1.0.0 + */ + public static function getAllArray(int $relations = RelationType::ALL, string $lang = '') : array + { + if(!isset(self::$parentMapper)) { + self::setUpParentMapper(); + } + + $obj = self::populateIterableArray(self::getAllRaw($lang)); + self::fillRelationsArray($obj, $relations); + self::clear(); + + return $obj; + } + /** * Find data. * From d278918dfa085420b6d74c64eab2f2074b2c2d46 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Wed, 13 Sep 2017 13:48:18 +0200 Subject: [PATCH 06/76] experiment with CRUD pull-out --- DataStorage/Database/CreateMapperAbstract.php | 511 ++++++++ .../Database/DataMapperBaseAbstract.php | 435 +++++++ DataStorage/Database/DeleteMapperAbstract.php | 295 +++++ DataStorage/Database/ReadMapperAbstract.php | 1126 +++++++++++++++++ DataStorage/Database/UpdateMapperAbstract.php | 326 +++++ 5 files changed, 2693 insertions(+) create mode 100644 DataStorage/Database/CreateMapperAbstract.php create mode 100644 DataStorage/Database/DataMapperBaseAbstract.php create mode 100644 DataStorage/Database/DeleteMapperAbstract.php create mode 100644 DataStorage/Database/ReadMapperAbstract.php create mode 100644 DataStorage/Database/UpdateMapperAbstract.php diff --git a/DataStorage/Database/CreateMapperAbstract.php b/DataStorage/Database/CreateMapperAbstract.php new file mode 100644 index 000000000..01426b15c --- /dev/null +++ b/DataStorage/Database/CreateMapperAbstract.php @@ -0,0 +1,511 @@ +prefix(self::$db->getPrefix())->into(static::$table); + + $properties = $reflectionClass->getProperties(); + + foreach ($properties as $property) { + $propertyName = $property->getName(); + + if (isset(static::$hasMany[$propertyName]) || isset(static::$hasOne[$propertyName])) { + continue; + } + + if (!($isPublic = $property->isPublic())) { + $property->setAccessible(true); + } + + foreach (static::$columns as $key => $column) { + if (isset(static::$ownsOne[$propertyName]) && $column['internal'] === $propertyName) { + $id = self::createOwnsOne($propertyName, $property->getValue($obj)); + $value = self::parseValue($column['type'], $id); + + $query->insert($column['name'])->value($value, $column['type']); + break; + } elseif (isset(static::$belongsTo[$propertyName]) && $column['internal'] === $propertyName) { + $id = self::createBelongsTo($propertyName, $property->getValue($obj)); + $value = self::parseValue($column['type'], $id); + + $query->insert($column['name'])->value($value, $column['type']); + break; + } elseif ($column['internal'] === $propertyName && $column['type'] !== static::$primaryField) { + $value = self::parseValue($column['type'], $property->getValue($obj)); + + $query->insert($column['name'])->value($value, $column['type']); + break; + } + } + + if (!($isPublic)) { + $property->setAccessible(false); + } + } + + self::$db->con->prepare($query->toSql())->execute(); + + return self::$db->con->lastInsertId(); + } + + /** + * Create base model. + * + * @param Object $obj Model to create + * + * @return mixed + * + * @since 1.0.0 + */ + private static function createModelArray($obj) + { + $query = new Builder(self::$db); + $query->prefix(self::$db->getPrefix())->into(static::$table); + + foreach ($obj as $propertyName => &$property) { + if (isset(static::$hasMany[$propertyName]) || isset(static::$hasOne[$propertyName])) { + continue; + } + + foreach (static::$columns as $key => $column) { + if (isset(static::$ownsOne[$propertyName]) && $column['internal'] === $propertyName) { + $id = self::createOwnsOneArray($propertyName, $property); + $value = self::parseValue($column['type'], $id); + + $query->insert($column['name'])->value($value, $column['type']); + break; + } elseif (isset(static::$belongsTo[$propertyName]) && $column['internal'] === $propertyName) { + $id = self::createBelongsToArray($propertyName, $property); + $value = self::parseValue($column['type'], $id); + + $query->insert($column['name'])->value($value, $column['type']); + break; + } elseif ($column['internal'] === $propertyName && $column['type'] !== static::$primaryField) { + $value = self::parseValue($column['type'], $property); + + $query->insert($column['name'])->value($value, $column['type']); + break; + } + } + } + + self::$db->con->prepare($query->toSql())->execute(); + + return self::$db->con->lastInsertId(); + } + + /** + * Create has many + * + * @param \ReflectionClass $reflectionClass Reflection class + * @param Object $obj Object to create + * @param mixed $objId Id to set + * + * @return void + * + * @throws InvalidMapperException + * + * @since 1.0.0 + */ + private static function createHasMany(\ReflectionClass $reflectionClass, $obj, $objId) /* : void */ + { + foreach (static::$hasMany as $propertyName => $rel) { + $property = $reflectionClass->getProperty($propertyName); + + if (!($isPublic = $property->isPublic())) { + $property->setAccessible(true); + } + + $values = $property->getValue($obj); + + if (!($isPublic)) { + $property->setAccessible(false); + } + + if (!isset(static::$hasMany[$propertyName]['mapper'])) { + throw new InvalidMapperException(); + } + + /** @var DataMapperAbstract $mapper */ + $mapper = static::$hasMany[$propertyName]['mapper']; + $objsIds = []; + $relReflectionClass = null; + + foreach ($values as $key => &$value) { + if (!is_object($value)) { + // Is scalar => already in database + $objsIds[$key] = $value; + + continue; + } + + if (!isset($relReflectionClass)) { + $relReflectionClass = new \ReflectionClass(get_class($value)); + } + + $primaryKey = $mapper::getObjectId($value, $relReflectionClass); + + // already in db + if (!empty($primaryKey)) { + $objsIds[$key] = $value; + + continue; + } + + // Setting relation value (id) for relation (since the relation is not stored in an extra relation table) + /** @var string $table */ + /** @var array $columns */ + if (static::$hasMany[$propertyName]['table'] === static::$hasMany[$propertyName]['mapper']::$table) { + $relProperty = $relReflectionClass->getProperty($mapper::$columns[static::$hasMany[$propertyName]['dst']]['internal']); + + if (!$isPublic) { + $relProperty->setAccessible(true); + } + + $relProperty->setValue($value, $objId); + + if (!($isPublic)) { + $relProperty->setAccessible(false); + } + } + + $objsIds[$key] = $mapper::create($value); + } + + self::createRelationTable($propertyName, $objsIds, $objId); + } + } + + /** + * Create has many + * + * @param array $obj Object to create + * @param mixed $objId Id to set + * + * @return void + * + * @throws InvalidMapperException + * + * @since 1.0.0 + */ + private static function createHasManyArray(array &$obj, $objId) /* : void */ + { + foreach (static::$hasMany as $propertyName => $rel) { + $values = $obj[$propertyName]; + + if (!isset(static::$hasMany[$propertyName]['mapper'])) { + throw new InvalidMapperException(); + } + + /** @var DataMapperAbstract $mapper */ + $mapper = static::$hasMany[$propertyName]['mapper']; + $objsIds = []; + + foreach ($values as $key => &$value) { + if (!is_object($value)) { + // Is scalar => already in database + $objsIds[$key] = $value; + + continue; + } + + $primaryKey = $obj[static::$columns[static::$primaryField]['internal']]; + + // already in db + if (!empty($primaryKey)) { + $objsIds[$key] = $value; + + continue; + } + + // Setting relation value (id) for relation (since the relation is not stored in an extra relation table) + /** @var string $table */ + /** @var array $columns */ + if (static::$hasMany[$propertyName]['table'] === static::$hasMany[$propertyName]['mapper']::$table) { + $value[$mapper::$columns[static::$hasMany[$propertyName]['dst']]['internal']] = $objId; + } + + $objsIds[$key] = $mapper::createArray($value); + } + + self::createRelationTable($propertyName, $objsIds, $objId); + } + } + + private static function createHasOne(\ReflectionClass $reflectionClass, $obj) + { + throw new \Exception(); + + foreach (static::$hasOne as $propertyName => $rel) { + + } + } + + /** + * Create owns one + * + * The reference is stored in the main model + * + * @param string $propertyName Property name to initialize + * @param Object $obj Object to create + * + * @return mixed + * + * @since 1.0.0 + */ + private static function createOwnsOne(string $propertyName, $obj) + { + if (is_object($obj)) { + $mapper = static::$ownsOne[$propertyName]['mapper']; + $primaryKey = $mapper::getObjectId($obj); + + if (empty($primaryKey)) { + return $mapper::create($obj); + } + + return $primaryKey; + } + + return $obj; + } + + /** + * Create owns one + * + * The reference is stored in the main model + * + * @param string $propertyName Property name to initialize + * @param array $obj Object to create + * + * @return mixed + * + * @since 1.0.0 + */ + private static function createOwnsOneArray(string $propertyName, array &$obj) + { + if (is_array($obj)) { + $mapper = static::$ownsOne[$propertyName]['mapper']; + $primaryKey = $obj[static::$columns[static::$primaryField]['internal']]; + + if (empty($primaryKey)) { + return $mapper::createArray($obj); + } + + return $primaryKey; + } + + return $obj; + } + + /** + * Create owns one + * + * The reference is stored in the main model + * + * @param string $propertyName Property name to initialize + * @param Object $obj Object to create + * + * @return mixed + * + * @since 1.0.0 + */ + private static function createBelongsTo(string $propertyName, $obj) + { + if (is_object($obj)) { + /** @var DataMapperAbstract $mapper */ + $mapper = static::$belongsTo[$propertyName]['mapper']; + $primaryKey = $mapper::getObjectId($obj); + + if (empty($primaryKey)) { + return $mapper::create($obj); + } + + return $primaryKey; + } + + return $obj; + } + + /** + * Create owns one + * + * The reference is stored in the main model + * + * @param string $propertyName Property name to initialize + * @param Object $obj Object to create + * + * @return mixed + * + * @since 1.0.0 + */ + private static function createBelongsToArray(string $propertyName, array $obj) + { + if (is_array($obj)) { + /** @var DataMapperAbstract $mapper */ + $mapper = static::$belongsTo[$propertyName]['mapper']; + $primaryKey = $obj[static::$columns[static::$primaryField]['internal']]; + + if (empty($primaryKey)) { + return $mapper::createArray($obj); + } + + return $primaryKey; + } + + return $obj; + } + + /** + * Create relation table entry + * + * In case of a many to many relation the relation has to be stored in a relation table + * + * @param string $propertyName Property name to initialize + * @param array $objsIds Object ids to insert + * @param mixed $objId Model to reference + * + * @return mixed + * + * @since 1.0.0 + */ + private static function createRelationTable(string $propertyName, array $objsIds, $objId) + { + /** @var string $table */ + if ( + !empty($objsIds) + && static::$hasMany[$propertyName]['table'] !== static::$table + && static::$hasMany[$propertyName]['table'] !== static::$hasMany[$propertyName]['mapper']::$table + ) { + $relQuery = new Builder(self::$db); + $relQuery->prefix(self::$db->getPrefix()) + ->into(static::$hasMany[$propertyName]['table']) + ->insert(static::$hasMany[$propertyName]['src'], static::$hasMany[$propertyName]['dst']); + + foreach ($objsIds as $key => $src) { + $relQuery->values($src, $objId); + } + + self::$db->con->prepare($relQuery->toSql())->execute(); + } + } +} diff --git a/DataStorage/Database/DataMapperBaseAbstract.php b/DataStorage/Database/DataMapperBaseAbstract.php new file mode 100644 index 000000000..ac9d69f50 --- /dev/null +++ b/DataStorage/Database/DataMapperBaseAbstract.php @@ -0,0 +1,435 @@ + [], + 'createdAt' => [], + 'columns' => [], + 'hasMany' => [], + 'hasOne' => [], + 'ownsOne' => [], + 'table' => [], + ]; + + /** + * Constructor. + * + * @since 1.0.0 + */ + private function __construct() + { + } + + /** + * Clone. + * + * @return void + * + * @since 1.0.0 + */ + private function __clone() + { + } + + /** + * Set database connection. + * + * @param ConnectionAbstract $con Database connection + * + * @return void + * + * @since 1.0.0 + */ + public static function setConnection(ConnectionAbstract $con) /* : void */ + { + self::$db = $con; + } + + /** + * Get primary field. + * + * @return string + * + * @since 1.0.0 + */ + public static function getPrimaryField() : string + { + return static::$primaryField; + } + + /** + * Get main table. + * + * @return string + * + * @since 1.0.0 + */ + public static function getTable() : string + { + return static::$table; + } + + /** + * Collect values from extension. + * + * @param mixed $class Current extended mapper + * + * @return void + * + * @since 1.0.0 + */ + private static function extend($class) /* : void */ + { + /* todo: have to implement this in the queries, so far not used */ + self::$collection['primaryField'][] = $class::$primaryField; + self::$collection['createdAt'][] = $class::$createdAt; + self::$collection['columns'][] = $class::$columns; + self::$collection['hasMany'][] = $class::$hasMany; + self::$collection['hasOne'][] = $class::$hasOne; + self::$collection['ownsOne'][] = $class::$ownsOne; + self::$collection['table'][] = $class::$table; + + if (($parent = get_parent_class($class)) !== false && !$class::$overwrite) { + self::extend($parent); + } + } + + /** + * Resets all loaded mapper variables. + * + * This is used after one action is performed otherwise other models would use wrong settings. + * + * @return void + * + * @since 1.0.0 + */ + public static function clear() /* : void */ + { + self::$overwrite = true; + self::$primaryField = ''; + self::$createdAt = ''; + self::$columns = []; + self::$hasMany = []; + self::$hasOne = []; + self::$ownsOne = []; + self::$table = ''; + self::$fields = []; + self::$collection = [ + 'primaryField' => [], + 'createdAt' => [], + 'columns' => [], + 'hasOne' => [], + 'ownsMany' => [], + 'ownsOne' => [], + 'table' => [], + ]; + + // clear parent and objects + if(static::class === self::$parentMapper) { + self::$initObjects = []; + self::$parentMapper = null; + } + } + + /** + * Get created at column + * + * @return string + * + * @since 1.0.0 + */ + public static function getCreatedAt() : string + { + return static::$createdAt; + } + + /** + * Get id of object + * + * @param Object $obj Model to create + * @param \ReflectionClass $reflectionClass Reflection class + * + * @return mixed + * + * @since 1.0.0 + */ + private static function getObjectId($obj, \ReflectionClass $reflectionClass = null) + { + $reflectionClass = $reflectionClass ?? new \ReflectionClass(get_class($obj)); + $reflectionProperty = $reflectionClass->getProperty(static::$columns[static::$primaryField]['internal']); + + if (!($isPublic = $reflectionProperty->isPublic())) { + $reflectionProperty->setAccessible(true); + } + + $objectId = $reflectionProperty->getValue($obj); + + if (!$isPublic) { + $reflectionProperty->setAccessible(false); + } + + return $objectId; + } + + /** + * Set id to model + * + * @param \ReflectionClass $reflectionClass Reflection class + * @param Object $obj Object to create + * @param mixed $objId Id to set + * + * @return void + * + * @since 1.0.0 + */ + private static function setObjectId(\ReflectionClass $reflectionClass, $obj, $objId) /* : void */ + { + $reflectionProperty = $reflectionClass->getProperty(static::$columns[static::$primaryField]['internal']); + + if (!($isPublic = $reflectionProperty->isPublic())) { + $reflectionProperty->setAccessible(true); + } + + settype($objId, static::$columns[static::$primaryField]['type']); + $reflectionProperty->setValue($obj, $objId); + + if (!$isPublic) { + $reflectionProperty->setAccessible(false); + } + } + + /** + * Parse value + * + * @param string $type Value type + * @param mixed $value Value to parse + * + * @return mixed + * + * @since 1.0.0 + */ + private static function parseValue(string $type, $value) + { + if (is_null($value)) { + return null; + } elseif ($type === 'DateTime') { + return $value->format('Y-m-d H:i:s'); + } elseif ($type === 'Json' || $type === 'jsonSerializable') { + return json_encode($value); + } elseif ($type === 'Serializable') { + return $value->serialize(); + } elseif ($value instanceof \JsonSerializable) { + return json_encode($value->jsonSerialize()); + } elseif (is_object($value) && method_exists($value, 'getId')) { + return $value->getId(); + } elseif ($type === 'int') { + return (int) $value; + } elseif ($type === 'string') { + return (string) $value; + } elseif ($type === 'float') { + return (float) $value; + } elseif ($type === 'bool') { + return (bool) $value; + } + + return $value; + } + + /** + * Get mapper specific builder + * + * @param Builder $query Query to fill + * + * @return Builder + * + * @since 1.0.0 + */ + public static function getQuery(Builder $query = null) : Builder + { + $query = $query ?? new Builder(self::$db); + $query->prefix(self::$db->getPrefix()) + ->select('*') + ->from(static::$table); + + return $query; + } + + /** + * Define the highest mapper of this request + * + * @return void + * + * @since 1.0.0 + */ + private static function setUpParentMapper() /* : void */ + { + self::$parentMapper = static::class; + } + + private static function getColumnByMember(string $name) : string + { + foreach(static::$columns as $cName => $column) { + if($column['internal'] === $name) { + return $cName; + } + } + + throw \Exception(); + } +} diff --git a/DataStorage/Database/DeleteMapperAbstract.php b/DataStorage/Database/DeleteMapperAbstract.php new file mode 100644 index 000000000..6e3bd8661 --- /dev/null +++ b/DataStorage/Database/DeleteMapperAbstract.php @@ -0,0 +1,295 @@ + $rel) { + $property = $reflectionClass->getProperty($propertyName); + + if (!($isPublic = $property->isPublic())) { + $property->setAccessible(true); + } + + $values = $property->getValue($obj); + + if (!($isPublic)) { + $property->setAccessible(false); + } + + if (!isset(static::$hasMany[$propertyName]['mapper'])) { + throw new InvalidMapperException(); + } + + /** @var DataMapperAbstract $mapper */ + $mapper = static::$hasMany[$propertyName]['mapper']; + $objsIds = []; + $relReflectionClass = null; + + foreach ($values as $key => &$value) { + if (!is_object($value)) { + // Is scalar => already in database + $objsIds[$key] = $value; + + continue; + } + + if (!isset($relReflectionClass)) { + $relReflectionClass = new \ReflectionClass(get_class($value)); + } + + $primaryKey = $mapper::getObjectId($value, $relReflectionClass); + + // already in db + if (!empty($primaryKey)) { + if($relations === RelationType::ALL) { + $objsIds[$key] = $mapper::delete($value); + } else { + $objsIds[$key] = $primaryKey; + } + + continue; + } + + // todo: could be a problem, relation needs to be removed first?! + + } + + self::deleteRelationTable($propertyName, $objsIds, $objId); + } + } + + /** + * Delete owns one + * + * The reference is stored in the main model + * + * @param string $propertyName Property name to initialize + * @param Object $obj Object to delete + * + * @return mixed + * + * @since 1.0.0 + */ + private static function deleteOwnsOne(string $propertyName, $obj) + { + if (is_object($obj)) { + /** @var DataMapperAbstract $mapper */ + $mapper = static::$ownsOne[$propertyName]['mapper']; + + // todo: delete owned one object is not recommended since it can be owned by by something else? or does owns one mean that nothing else can have a relation to this one? + return $mapper::delete($obj); + } + + return $obj; + } + + /** + * Delete owns one + * + * The reference is stored in the main model + * + * @param string $propertyName Property name to initialize + * @param Object $obj Object to delete + * + * @return mixed + * + * @since 1.0.0 + */ + private static function deleteBelongsTo(string $propertyName, $obj) + { + if (is_object($obj)) { + /** @var DataMapperAbstract $mapper */ + $mapper = static::$belongsTo[$propertyName]['mapper']; + + return $mapper::delete($obj); + } + + return $obj; + } + + /** + * Delete object in db. + * + * @param Object $obj Model to delete + * @param mixed $objId Model id + * @param int $relations Delete all relations as well + * @param \ReflectionClass $reflectionClass Reflection class + * + * @return mixed + * + * @since 1.0.0 + */ + private static function deleteModel($obj, $objId, int $relations = RelationType::REFERENCE, \ReflectionClass $reflectionClass = null) /* : void */ + { + $query = new Builder(self::$db); + $query->prefix(self::$db->getPrefix()) + ->delete() + ->into(static::$table) + ->where(static::$primaryField, '=', $objId); + + $properties = $reflectionClass->getProperties(); + + if($relations === RelationType::ALL) { + foreach ($properties as $property) { + $propertyName = $property->getName(); + + if (isset(static::$hasMany[$propertyName]) || isset(static::$hasOne[$propertyName])) { + continue; + } + + if (!($isPublic = $property->isPublic())) { + $property->setAccessible(true); + } + + // todo: the order of deletion could be a problem. maybe looping through ownsOne and belongsTo first is better. + // todo: support other relation types as well (belongsto, ownsone) = for better control + + foreach (static::$columns as $key => $column) { + if ($relations === RelationType::ALL && isset(static::$ownsOne[$propertyName]) && $column['internal'] === $propertyName) { + self::deleteOwnsOne($propertyName, $property->getValue($obj)); + break; + } elseif ($relations === RelationType::ALL && isset(static::$belongsTo[$propertyName]) && $column['internal'] === $propertyName) { + self::deleteBelongsTo($propertyName, $property->getValue($obj)); + break; + } + } + + if (!($isPublic)) { + $property->setAccessible(false); + } + } + } + + self::$db->con->prepare($query->toSql())->execute(); + } + + /** + * Delete object in db. + * + * @param mixed $obj Object reference (gets filled with insert id) + * @param int $relations Create all relations as well + * + * @return mixed + * + * @since 1.0.0 + */ + public static function delete($obj, int $relations = RelationType::REFERENCE) + { + self::extend(__CLASS__); + $reflectionClass = new \ReflectionClass(get_class($obj)); + $objId = self::getObjectId($obj, $reflectionClass); + + if(empty($objId)) { + return null; + } + + if ($relations !== RelationType::NONE) { + self::deleteHasMany($reflectionClass, $obj, $objId, $relations); + } + + self::deleteModel($obj, $objId, $relations, $reflectionClass); + + return $objId; + } + + + /** + * Delete relation table entry + * + * @param string $propertyName Property name to initialize + * @param array $objsIds Object ids to insert + * @param mixed $objId Model to reference + * + * @return mixed + * + * @since 1.0.0 + */ + private static function deleteRelationTable(string $propertyName, array $objsIds, $objId) + { + /** @var string $table */ + if ( + !empty($objsIds) + && static::$hasMany[$propertyName]['table'] !== static::$table + && static::$hasMany[$propertyName]['table'] !== static::$hasMany[$propertyName]['mapper']::$table + ) { + foreach ($objsIds as $key => $src) { + $relQuery = new Builder(self::$db); + $relQuery->prefix(self::$db->getPrefix()) + ->into(static::$hasMany[$propertyName]['table']) + ->delete(); + + $relQuery->where(static::$hasMany[$propertyName]['src'], '=', $src) + ->where(static::$hasMany[$propertyName]['dst'], '=', $objId, 'and'); + + self::$db->con->prepare($relQuery->toSql())->execute(); + } + } + } + +} diff --git a/DataStorage/Database/ReadMapperAbstract.php b/DataStorage/Database/ReadMapperAbstract.php new file mode 100644 index 000000000..ef934f57a --- /dev/null +++ b/DataStorage/Database/ReadMapperAbstract.php @@ -0,0 +1,1126 @@ +where(static::$table . '.' . $col['name'], 'LIKE', '%' . $search . '%', 'OR'); + } + } + + return static::getAllByQuery($query); + } + + /** + * Populate data. + * + * @param array $result Result set + * + * @return array + * + * @since 1.0.0 + */ + public static function populateIterable(array $result) : array + { + $row = []; + + foreach ($result as $element) { + if (isset($element[static::$primaryField])) { + $row[$element[static::$primaryField]] = self::populate($element); + } else { + $row[] = self::populate($element); + } + } + + return $row; + } + + /** + * Populate data. + * + * @param array $result Result set + * + * @return array + * + * @since 1.0.0 + */ + public static function populateIterableArray(array $result) : array + { + $row = []; + + foreach ($result as $element) { + if (isset($element[static::$primaryField])) { + $row[$element[static::$primaryField]] = self::populateAbstractArray($element); + } else { + $row[] = self::populateAbstractArray($element); + } + } + + return $row; + } + + /** + * Populate data. + * + * @param array $result Result set + * @param mixed $obj Object to populate + * + * @return mixed + * + * @since 1.0.0 + */ + public static function populate(array $result, $obj = null) + { + $class = static::class; + $class = str_replace('Mapper', '', $class); + + if (count($result) === 0) { + $parts = explode('\\', $class); + $name = $parts[$c = (count($parts) - 1)]; + $parts[$c] = 'Null' . $name; + $class = implode('\\', $parts); + } + + if (!isset($obj)) { + $obj = new $class(); + } + + return self::populateAbstract($result, $obj); + } + + /** + * Populate data. + * + * @param array[] $result Result set + * @param mixed $obj Object to add the relations to + * + * @return void + * + * @since 1.0.0 + */ + public static function populateManyToMany(array $result, &$obj) /* : void */ + { + // todo: maybe pass reflectionClass as optional parameter for performance increase + $reflectionClass = new \ReflectionClass(get_class($obj)); + + foreach ($result as $member => $values) { + if (!empty($values) && $reflectionClass->hasProperty($member)) { + /** @var DataMapperAbstract $mapper */ + $mapper = static::$hasMany[$member]['mapper']; + $reflectionProperty = $reflectionClass->getProperty($member); + + $values = array_diff($values, array_keys(self::$initObjects[$mapper] ?? [])); + if(empty($values)) { + continue; + } + + if (!($accessible = $reflectionProperty->isPublic())) { + $reflectionProperty->setAccessible(true); + } + + $objects = $mapper::get($values); + $reflectionProperty->setValue($obj, !is_array($objects) ? [$objects] : $objects); + + if (!$accessible) { + $reflectionProperty->setAccessible(false); + } + } + } + } + + /** + * Populate data. + * + * @param array[] $result Result set + * @param array $obj Object to add the relations to + * + * @return void + * + * @since 1.0.0 + */ + public static function populateManyToManyArray(array $result, array &$obj) /* : void */ + { + foreach ($result as $member => $values) { + if (!empty($values)) { + /** @var DataMapperAbstract $mapper */ + $mapper = static::$hasMany[$member]['mapper']; + $values = array_diff($values, array_keys(self::$initObjects[$mapper] ?? [])); + if(empty($values)) { + continue; + } + + $objects = $mapper::getArray($values); + $obj[$member] = $objects; + } + } + } + + /** + * Populate data. + * + * @param mixed $obj Object to add the relations to + * + * @return void + * + * @todo accept reflection class as parameter + * + * @since 1.0.0 + */ + public static function populateHasOne(&$obj) /* : void */ + { + $reflectionClass = new \ReflectionClass(get_class($obj)); + + foreach (static::$hasOne as $member => $one) { + // todo: is that if necessary? performance is suffering for sure! + if ($reflectionClass->hasProperty($member)) { + $reflectionProperty = $reflectionClass->getProperty($member); + + if (!($accessible = $reflectionProperty->isPublic())) { + $reflectionProperty->setAccessible(true); + } + + /** @var DataMapperAbstract $mapper */ + $mapper = static::$hasOne[$member]['mapper']; + + if(self::isInitialized($mapper, $reflectionProperty->getValue($obj))) { + $value = self::$initObjects[$mapper][$id]; + } else { + $value = $mapper::get($reflectionProperty->getValue($obj)); + } + + $reflectionProperty->setValue($obj, $value); + + if (!$accessible) { + $reflectionProperty->setAccessible(false); + } + } + } + } + + /** + * Populate data. + * + * @param array $obj Object to add the relations to + * + * @return void + * + * @todo accept reflection class as parameter + * + * @since 1.0.0 + */ + public static function populateHasOneArray(array &$obj) /* : void */ + { + foreach (static::$hasOne as $member => $one) { + /** @var DataMapperAbstract $mapper */ + $mapper = static::$hasOne[$member]['mapper']; + + if(self::isInitialized($mapper, $obj['member'])) { + $value = self::$initObjects[$mapper][$id]; + } else { + $value = $mapper::getArray($obj[$member]); + } + + $obj[$member] = $value; + } + } + + /** + * Populate data. + * + * @param mixed $obj Object to add the relations to + * + * @return void + * + * @todo accept reflection class as parameter + * + * @since 1.0.0 + */ + public static function populateOwnsOne(&$obj) /* : void */ + { + $reflectionClass = new \ReflectionClass(get_class($obj)); + + foreach (static::$ownsOne as $member => $one) { + // todo: is that if necessary? performance is suffering for sure! + if ($reflectionClass->hasProperty($member)) { + $reflectionProperty = $reflectionClass->getProperty($member); + + if (!($accessible = $reflectionProperty->isPublic())) { + $reflectionProperty->setAccessible(true); + } + + /** @var DataMapperAbstract $mapper */ + $mapper = static::$ownsOne[$member]['mapper']; + + if(self::isInitialized($mapper, $reflectionProperty->getValue($obj))) { + $value = self::$initObjects[$mapper][$id]; + } else { + $value = $mapper::get($reflectionProperty->getValue($obj)); + } + + $reflectionProperty->setValue($obj, $value); + + if (!$accessible) { + $reflectionProperty->setAccessible(false); + } + } + } + } + + /** + * Populate data. + * + * @param array $obj Object to add the relations to + * + * @return void + * + * @todo accept reflection class as parameter + * + * @since 1.0.0 + */ + public static function populateOwnsOneArray(array &$obj) /* : void */ + { + foreach (static::$ownsOne as $member => $one) { + /** @var DataMapperAbstract $mapper */ + $mapper = static::$ownsOne[$member]['mapper']; + + if(self::isInitialized($mapper, $obj[$member])) { + $value = self::$initObjects[$mapper][$id]; + } else { + $value = $mapper::getArray($obj[$member]); + } + + $obj[$member] = $value; + } + } + + /** + * Populate data. + * + * @param mixed $obj Object to add the relations to + * + * @return void + * + * @todo accept reflection class as parameter + * + * @since 1.0.0 + */ + public static function populateBelongsTo(&$obj) /* : void */ + { + $reflectionClass = new \ReflectionClass(get_class($obj)); + + foreach (static::$belongsTo as $member => $one) { + // todo: is that if necessary? performance is suffering for sure! + if ($reflectionClass->hasProperty($member)) { + $reflectionProperty = $reflectionClass->getProperty($member); + + if (!($accessible = $reflectionProperty->isPublic())) { + $reflectionProperty->setAccessible(true); + } + + /** @var DataMapperAbstract $mapper */ + $mapper = static::$belongsTo[$member]['mapper']; + + if(self::isInitialized($mapper, $reflectionProperty->getValue($obj))) { + $value = self::$initObjects[$mapper][$id]; + } else { + $value = $mapper::get($reflectionProperty->getValue($obj)); + } + + $reflectionProperty->setValue($obj, $value); + + if (!$accessible) { + $reflectionProperty->setAccessible(false); + } + } + } + } + + /** + * Populate data. + * + * @param array $obj Object to add the relations to + * + * @return void + * + * @todo accept reflection class as parameter + * + * @since 1.0.0 + */ + public static function populateBelongsToArray(array &$obj) /* : void */ + { + foreach (static::$belongsTo as $member => $one) { + /** @var DataMapperAbstract $mapper */ + $mapper = static::$belongsTo[$member]['mapper']; + + if(self::isInitialized($mapper, $obj[$member])) { + $value = self::$initObjects[$mapper][$id]; + } else { + $value = $mapper::get($obj[$member]); + } + + $obj[$member] = $value; + } + } + + /** + * Populate data. + * + * @param array $result Query result set + * @param mixed $obj Object to populate + * + * @return mixed + * + * @throws \UnexpectedValueException + * + * @since 1.0.0 + */ + public static function populateAbstract(array $result, $obj) + { + $reflectionClass = new \ReflectionClass(get_class($obj)); + + foreach ($result as $column => $value) { + if (isset(static::$columns[$column]['internal']) && $reflectionClass->hasProperty(static::$columns[$column]['internal'])) { + $reflectionProperty = $reflectionClass->getProperty(static::$columns[$column]['internal']); + + if (!($accessible = $reflectionProperty->isPublic())) { + $reflectionProperty->setAccessible(true); + } + + if (in_array(static::$columns[$column]['type'], ['string', 'int', 'float', 'bool'])) { + settype($value, static::$columns[$column]['type']); + $reflectionProperty->setValue($obj, $value); + } elseif (static::$columns[$column]['type'] === 'DateTime') { + $reflectionProperty->setValue($obj, new \DateTime($value ?? '')); + } elseif (static::$columns[$column]['type'] === 'Json') { + $reflectionProperty->setValue($obj, json_decode($value, true)); + } elseif (static::$columns[$column]['type'] === 'Serializable') { + $member = $reflectionProperty->getValue($obj); + $member->unserialize($value); + } else { + throw new \UnexpectedValueException('Value "' . static::$columns[$column]['type'] . '" is not supported.'); + } + + if (!$accessible) { + $reflectionProperty->setAccessible(false); + } + } + } + + return $obj; + } + + /** + * Populate data. + * + * @param array $result Query result set + * + * @return array + * + * @throws \UnexpectedValueException + * + * @since 1.0.0 + */ + public static function populateAbstractArray(array $result) : array + { + $obj = []; + + foreach ($result as $column => $value) { + if (isset(static::$columns[$column]['internal'])) { + if (in_array(static::$columns[$column]['type'], ['string', 'int', 'float', 'bool'])) { + settype($value, static::$columns[$column]['type']); + $obj[static::$columns[$column]['internal']] = $value; + } elseif (static::$columns[$column]['type'] === 'DateTime') { + $obj[static::$columns[$column]['internal']] = new \DateTime($value ?? ''); + } elseif (static::$columns[$column]['type'] === 'Json') { + $obj[static::$columns[$column]['internal']] = json_decode($value, true); + } elseif (static::$columns[$column]['type'] === 'Serializable') { + $obj[static::$columns[$column]['internal']] = $value; + } else { + throw new \UnexpectedValueException('Value "' . static::$columns[$column]['type'] . '" is not supported.'); + } + } + } + + return $obj; + } + + /** + * Get object. + * + * @param mixed $primaryKey Key + * @param int $relations Load relations + * @param mixed $fill Object to fill + * + * @return mixed + * + * @since 1.0.0 + */ + public static function get($primaryKey, int $relations = RelationType::ALL, $fill = null) + { + if(!isset(self::$parentMapper)) { + self::setUpParentMapper(); + } + + self::extend(__CLASS__); + + $primaryKey = (array) $primaryKey; + $fill = (array) $fill; + $obj = []; + $fCount = count($fill); + $toFill = null; + + foreach ($primaryKey as $key => $value) { + if(self::isInitialized(static::class, $value)) { + continue; + } + + if ($fCount > 0) { + $toFill = current($fill); + next($fill); + } + + $obj[$value] = self::populate(self::getRaw($value), $toFill); + + if(method_exists($obj[$value], 'initialize')) { + $obj[$value]->initialize(); + } + + self::addInitialized(static::class, $value); + } + + self::fillRelations($obj, $relations); + self::clear(); + + return count($obj) === 1 ? reset($obj) : $obj; + } + + /** + * Get object. + * + * @param mixed $primaryKey Key + * @param int $relations Load relations + * + * @return mixed + * + * @since 1.0.0 + */ + public static function getArray($primaryKey, int $relations = RelationType::ALL) : array + { + if(!isset(self::$parentMapper)) { + self::setUpParentMapper(); + } + + self::extend(__CLASS__); + + $primaryKey = (array) $primaryKey; + $fill = (array) $fill; + $obj = []; + + foreach ($primaryKey as $key => $value) { + if(self::isInitialized(static::class, $value)) { + continue; + } + + $obj[$value] = self::populateAbstractArray(self::getRaw($value)); + + self::addInitialized(static::class, $value); + } + + self::fillRelationsArray($obj, $relations); + self::clear(); + + return count($obj) === 1 ? reset($obj) : $obj; + } + + /** + * Get object. + * + * @param mixed $refKey Key + * @param string $ref The field that defines the for + * @param int $relations Load relations + * @param mixed $fill Object to fill + * + * @return mixed + * + * @since 1.0.0 + */ + public static function getFor($refKey, string $ref, int $relations = RelationType::ALL, $fill = null) + { + if(!isset(self::$parentMapper)) { + self::setUpParentMapper(); + } + + self::extend(__CLASS__); + + $refKey = (array) $refKey; + $obj = []; + + foreach ($refKey as $key => $value) { + // todo: this only works for belongsTo not for many-to-many relations. Implement many-to-many + $obj[$value] = self::get(self::getPrimaryKeyBy($value, self::getColumnByMember($ref)), $relations, $fill); + } + return count($obj) === 1 ? reset($obj) : $obj; + } + + /** + * Get object. + * + * @param mixed $refKey Key + * @param string $ref The field that defines the for + * @param int $relations Load relations + * @param mixed $fill Object to fill + * + * @return mixed + * + * @since 1.0.0 + */ + public static function getForArray($refKey, string $ref, int $relations = RelationType::ALL, $fill = null) + { + if(!isset(self::$parentMapper)) { + self::setUpParentMapper(); + } + + self::extend(__CLASS__); + + $refKey = (array) $refKey; + $obj = []; + + foreach ($refKey as $key => $value) { + // todo: this only works for belongsTo not for many-to-many relations. Implement many-to-many + $obj[$value] = self::getArray(self::getPrimaryKeyBy($value, self::getColumnByMember($ref)), $relations, $fill); + } + return count($obj) === 1 ? reset($obj) : $obj; + } + + /** + * Get object. + * + * @param int $relations Load relations + * @param string $lang Language + * + * @return array + * + * @since 1.0.0 + */ + public static function getAll(int $relations = RelationType::ALL, string $lang = '') : array + { + if(!isset(self::$parentMapper)) { + self::setUpParentMapper(); + } + + $obj = self::populateIterable(self::getAllRaw($lang)); + self::fillRelations($obj, $relations); + self::clear(); + + return $obj; + } + + /** + * Get object. + * + * @param int $relations Load relations + * @param string $lang Language + * + * @return array + * + * @since 1.0.0 + */ + public static function getAllArray(int $relations = RelationType::ALL, string $lang = '') : array + { + if(!isset(self::$parentMapper)) { + self::setUpParentMapper(); + } + + $obj = self::populateIterableArray(self::getAllRaw($lang)); + self::fillRelationsArray($obj, $relations); + self::clear(); + + return $obj; + } + + /** + * Find data. + * + * @param Builder $query Query + * + * @return array + * + * @since 1.0.0 + */ + public static function listResults(Builder $query) : array + { + $sth = self::$db->con->prepare($query->toSql()); + $sth->execute(); + + return self::populateIterable($sth->fetchAll(\PDO::FETCH_ASSOC)); + } + + /** + * Get newest. + * + * This will fall back to the insert id if no datetime column is present. + * + * @param int $limit Newest limit + * @param Builder $query Pre-defined query + * @param int $relations Load relations + * @param string $lang Language + * + * @return mixed + * + * @since 1.0.0 + */ + public static function getNewest(int $limit = 1, Builder $query = null, int $relations = RelationType::ALL, string $lang = '') : array + { + self::extend(__CLASS__); + + $query = $query ?? new Builder(self::$db); + $query = self::getQuery($query); + $query->limit($limit); /* todo: limit is not working, setting this to 2 doesn't have any effect!!! */ + + if (!empty(static::$createdAt)) { + $query->orderBy(static::$table . '.' . static::$columns[static::$createdAt]['name'], 'DESC'); + } else { + $query->orderBy(static::$table . '.' . static::$columns[static::$primaryField]['name'], 'DESC'); + } + + if (!empty(self::$language_field) && !empty($lang)) { + $query->where(static::$table . '.' . static::$language_field, '=', $lang, 'AND'); + } + + $sth = self::$db->con->prepare($query->toSql()); + $sth->execute(); + + $results = $sth->fetchAll(\PDO::FETCH_ASSOC); + $obj = self::populateIterable(is_bool($results) ? [] : $results); + + self::fillRelations($obj, $relations); + self::clear(); + + return $obj; + + } + + /** + * Get all by custom query. + * + * @param Builder $query Query + * @param int $relations Relations + * + * @return array + * + * @since 1.0.0 + */ + public static function getAllByQuery(Builder $query, int $relations = RelationType::ALL) : array + { + $sth = self::$db->con->prepare($query->toSql()); + $sth->execute(); + + $results = $sth->fetchAll(\PDO::FETCH_ASSOC); + $results = is_bool($results) ? [] : $results; + + $obj = self::populateIterable($results); + self::fillRelations($obj, $relations); + self::clear(); + + return $obj; + } + + /** + * Get random object + * + * @param int $amount Amount of random models + * @param int $relations Relations type + * + * @return mixed + * + * @since 1.0.0 + */ + public static function getRandom(int $amount = 1, int $relations = RelationType::ALL) + { + $query = new Builder(self::$db); + $query->prefix(self::$db->getPrefix()) + ->random(static::$primaryField) + ->from(static::$table) + ->limit($amount); + + $sth = self::$db->con->prepare($query->toSql()); + $sth->execute(); + + return self::get($sth->fetchAll(), $relations); + } + + /** + * Fill object with relations + * + * @param mixed $obj Objects to fill + * @param int $relations Relations type + * + * @return void + * + * @since 1.0.0 + */ + public static function fillRelations(array &$obj, int $relations = RelationType::ALL) /* : void */ + { + $hasMany = !empty(static::$hasMany); + $hasOne = !empty(static::$hasOne); + $ownsOne = !empty(static::$ownsOne); + $belongsTo = !empty(static::$belongsTo); + + if ($relations !== RelationType::NONE && ($hasMany || $hasOne || $ownsOne || $belongsTo)) { + foreach ($obj as $key => $value) { + /* loading relations from relations table and populating them and then adding them to the object */ + if ($hasMany) { + self::populateManyToMany(self::getHasManyRaw($key, $relations), $obj[$key]); + } + + if ($hasOne) { + self::populateHasOne($obj[$key]); + } + + if ($ownsOne) { + self::populateOwnsOne($obj[$key]); + } + + if ($belongsTo) { + self::populateBelongsTo($obj[$key]); + } + } + } + } + + /** + * Fill object with relations + * + * @param mixed $obj Objects to fill + * @param int $relations Relations type + * + * @return void + * + * @since 1.0.0 + */ + public static function fillRelationsArray(array &$obj, int $relations = RelationType::ALL) /* : void */ + { + $hasMany = !empty(static::$hasMany); + $hasOne = !empty(static::$hasOne); + $ownsOne = !empty(static::$ownsOne); + $belongsTo = !empty(static::$belongsTo); + + if ($relations !== RelationType::NONE && ($hasMany || $hasOne || $ownsOne || $belongsTo)) { + foreach ($obj as $key => $value) { + /* loading relations from relations table and populating them and then adding them to the object */ + if ($hasMany) { + self::populateManyToManyArray(self::getHasManyRaw($key, $relations), $obj[$key]); + } + + if ($hasOne) { + self::populateHasOneArray($obj[$key]); + } + + if ($ownsOne) { + self::populateOwnsOneArray($obj[$key]); + } + + if ($belongsTo) { + self::populateBelongsToArray($obj[$key]); + } + } + } + } + + /** + * Get object. + * + * @param mixed $primaryKey Key + * + * @return mixed + * + * @since 1.0.0 + */ + public static function getRaw($primaryKey) : array + { + $query = self::getQuery(); + $query->where(static::$table . '.' . static::$primaryField, '=', $primaryKey); + + $sth = self::$db->con->prepare($query->toSql()); + $sth->execute(); + + $results = $sth->fetch(\PDO::FETCH_ASSOC); + + return is_bool($results) ? [] : $results; + } + + /** + * Get object. + * + * @param mixed $refKey Key + * @param string $ref Ref + * + * @return mixed + * + * @since 1.0.0 + */ + public static function getPrimaryKeyBy($refKey, string $ref) : array + { + $query = self::getQuery(); + $query->select(static::$primaryField) + ->from(static::$table) + ->where(static::$table . '.' . $ref, '=', $refKey); + + $sth = self::$db->con->prepare($query->toSql()); + $sth->execute(); + + $results = array_column($sth->fetchAll(\PDO::FETCH_NUM) ?? [], 0); + + return $results; + } + + /** + * Get all in raw output. + * + * @param string $lang Language + * + * @return array + * + * @since 1.0.0 + */ + public static function getAllRaw(string $lang = '') : array + { + $query = self::getQuery(); + + if (!empty(self::$language_field) && !empty($lang)) { + $query->where(static::$table . '.' . static::$language_field, '=', $lang, 'AND'); + } + + $sth = self::$db->con->prepare($query->toSql()); + $sth->execute(); + + $results = $sth->fetchAll(\PDO::FETCH_ASSOC); + + return is_bool($results) ? [] : $results; + } + + /** + * Get raw by primary key + * + * @param mixed $primaryKey Primary key + * @param int $relations Load relations + * + * @return array + * + * @since 1.0.0 + */ + public static function getHasManyRaw($primaryKey, int $relations = RelationType::ALL) : array + { + $result = []; + + foreach (static::$hasMany as $member => $value) { + $query = new Builder(self::$db); + $query->prefix(self::$db->getPrefix()); + + if ($relations === RelationType::ALL) { + /** @var string $primaryField */ + $src = $value['src'] ?? $value['mapper']::$primaryField; + + $query->select($value['table'] . '.' . $src) + ->from($value['table']) + ->where($value['table'] . '.' . $value['dst'], '=', $primaryKey); + } elseif ($relations === RelationType::NEWEST) { + + /* + SELECT c.*, p1.* + FROM customer c + JOIN purchase p1 ON (c.id = p1.customer_id) + LEFT OUTER JOIN purchase p2 ON (c.id = p2.customer_id AND + (p1.date < p2.date OR p1.date = p2.date AND p1.id < p2.id)) + WHERE p2.id IS NULL; + */ + /* + $query->select(static::$table . '.' . static::$primaryField, $value['table'] . '.' . $value['src']) + ->from(static::$table) + ->join($value['table']) + ->on(static::$table . '.' . static::$primaryField, '=', $value['table'] . '.' . $value['dst']) + ->leftOuterJoin($value['table']) + ->on(new And('1', new And(new Or('d1', 'd2'), 'id'))) + ->where($value['table'] . '.' . $value['dst'], '=', 'NULL'); + */ + } + + $sth = self::$db->con->prepare($query->toSql()); + $sth->execute(); + $result[$member] = $sth->fetchAll(\PDO::FETCH_COLUMN); + } + + return $result; + } + + /** + * Get mapper specific builder + * + * @param Builder $query Query to fill + * + * @return Builder + * + * @since 1.0.0 + */ + public static function getQuery(Builder $query = null) : Builder + { + $query = $query ?? new Builder(self::$db); + $query->prefix(self::$db->getPrefix()) + ->select('*') + ->from(static::$table); + + return $query; + } + + /** + * Get model based on request object + * + * @todo: change to graphql + * + * @param RequestAbstract $request Request object + * + * @return mixed + * + * @since 1.0.0 + */ + public static function getByRequest(RequestAbstract $request) + { + if (!is_null($request->getData('id'))) { + $result = static::get($request->getData('id')); + } elseif (!is_null($filter = $request->getData('filter'))) { + $filter = strtolower($filter); + + if ($filter === 'all') { + $result = static::getAll(); + } elseif ($filter === 'list') { + $list = $request->getData('list'); + $result = static::get(json_decode($list, true)); + } else { + $limit = (int) ($request->getData('limit') ?? 1); + $from = !is_null($request->getData('from')) ? new \DateTime($request->getData('from')) : null; + $to = !is_null($request->getData('to')) ? new \DateTime($request->getData('to')) : null; + + $query = static::getQuery(); + $query->limit($limit); + + if (isset($from, $to) && !empty(static::getCreatedAt())) { + $query->where(static::getCreatedAt(), '>=', $from); + $query->where(static::getCreatedAt(), '<=', $to); + } + + $result = static::getAllByQuery($query); + } + } else { + $class = static::class; + $class = str_replace('Mapper', '', $class); + $parts = explode('\\', $class); + $name = $parts[$c = (count($parts) - 1)]; + $parts[$c] = 'Null' . $name; + $class = implode('\\', $parts); + $result = new $class(); + } + + return $result; + } + + /** + * Add initialized object to local cache + * + * @param string $mapper Mapper name + * @param mixed $id Object id + * @param object $obj Model to cache locally + * + * @return void + * + * @since 1.0.0 + */ + private static function addInitialized(string $mapper, $id, $obj = null) /* : void */ + { + if(!isset(self::$initObjects[$mapper])) { + self::$initObjects[$mapper] = []; + } + + self::$initObjects[$mapper][$id] = $obj; + } + + /** + * Check if a object is initialized + * + * @param string $mapper Mapper name + * @param mixed $id Object id + * + * @return bool + * + * @since 1.0.0 + */ + private static function isInitialized($mapper, $id) : bool + { + return isset(self::$initObjects[$mapper]) && isset(self::$initObjects[$mapper][$id]); + } +} diff --git a/DataStorage/Database/UpdateMapperAbstract.php b/DataStorage/Database/UpdateMapperAbstract.php new file mode 100644 index 000000000..f3cda33bb --- /dev/null +++ b/DataStorage/Database/UpdateMapperAbstract.php @@ -0,0 +1,326 @@ + $rel) { + $property = $reflectionClass->getProperty($propertyName); + + if (!($isPublic = $property->isPublic())) { + $property->setAccessible(true); + } + + $values = $property->getValue($obj); + + if (!($isPublic)) { + $property->setAccessible(false); + } + + if (!isset(static::$hasMany[$propertyName]['mapper'])) { + throw new InvalidMapperException(); + } + + /** @var DataMapperAbstract $mapper */ + $mapper = static::$hasMany[$propertyName]['mapper']; + $objsIds = []; + $relReflectionClass = null; + + foreach ($values as $key => &$value) { + if (!is_object($value)) { + // Is scalar => already in database + $objsIds[$key] = $value; + + continue; + } + + if (!isset($relReflectionClass)) { + $relReflectionClass = new \ReflectionClass(get_class($value)); + } + + $primaryKey = $mapper::getObjectId($value, $relReflectionClass); + + // already in db + if (!empty($primaryKey)) { + $objsIds[$key] = $value; + + continue; + } + + // create if not existing + /** @var string $table */ + /** @var array $columns */ + if (static::$hasMany[$propertyName]['table'] === static::$hasMany[$propertyName]['mapper']::$table) { + $relProperty = $relReflectionClass->getProperty($mapper::$columns[static::$hasMany[$propertyName]['dst']]['internal']); + + if (!$isPublic) { + $relProperty->setAccessible(true); + } + + $relProperty->setValue($value, $objId); + + if (!($isPublic)) { + $relProperty->setAccessible(false); + } + } + + $objsIds[$key] = $mapper::create($value); + } + + self::updateRelationTable($propertyName, $objsIds, $objId); + } + } + + /** + * Update relation table entry + * + * Deletes old entries and creates new ones + * + * @param string $propertyName Property name to initialize + * @param array $objsIds Object ids to insert + * @param mixed $objId Model to reference + * + * @return mixed + * + * @throws \Exception + * + * @since 1.0.0 + */ + private static function updateRelationTable(string $propertyName, array $objsIds, $objId) + { + /** @var string $table */ + if ( + !empty($objsIds) + && static::$hasMany[$propertyName]['table'] !== static::$table + && static::$hasMany[$propertyName]['table'] !== static::$hasMany[$propertyName]['mapper']::$table + ) { + $many = self::getHasManyRaw($objId); + + foreach(static::$hasMany as $member => $value) { + // todo: definately an error here. needs testing + throw new \Exception(); + $removes = array_diff_key($many[$member], $objsIds[$member]); + $adds = array_diff_key($objsIds[$member], $many[$member]); + + if(!empty($removes)) { + self::deleteRelationTable($propertyName, $removes, $objId); + } + + if(!empty($adds)) { + self::createRelationTable($propertyName, $adds, $objId); + } + } + } + } + + /** + * Update owns one + * + * The reference is stored in the main model + * + * @param string $propertyName Property name to initialize + * @param Object $obj Object to update + * + * @return mixed + * + * @since 1.0.0 + */ + private static function updateOwnsOne(string $propertyName, $obj) + { + if (is_object($obj)) { + /** @var DataMapperAbstract $mapper */ + $mapper = static::$ownsOne[$propertyName]['mapper']; + + // todo: delete owned one object is not recommended since it can be owned by by something else? or does owns one mean that nothing else can have a relation to this one? + + return $mapper::update($obj); + } + + return $obj; + } + + /** + * Update owns one + * + * The reference is stored in the main model + * + * @param string $propertyName Property name to initialize + * @param Object $obj Object to update + * + * @return mixed + * + * @since 1.0.0 + */ + private static function updateBelongsTo(string $propertyName, $obj) + { + if (is_object($obj)) { + /** @var DataMapperAbstract $mapper */ + $mapper = static::$belongsTo[$propertyName]['mapper']; + + return $mapper::update($obj); + } + + return $obj; + } + + /** + * Update object in db. + * + * @param Object $obj Model to update + * @param mixed $objId Model id + * @param \ReflectionClass $reflectionClass Reflection class + * + * @return mixed + * + * @since 1.0.0 + */ + private static function updateModel($obj, $objId, \ReflectionClass $reflectionClass = null) /* : void */ + { + $query = new Builder(self::$db); + $query->prefix(self::$db->getPrefix()) + ->into(static::$table) + ->where(static::$primaryField, '=', $objId); + + $properties = $reflectionClass->getProperties(); + + foreach ($properties as $property) { + $propertyName = $property->getName(); + + if (isset(static::$hasMany[$propertyName]) || isset(static::$hasOne[$propertyName])) { + continue; + } + + if (!($isPublic = $property->isPublic())) { + $property->setAccessible(true); + } + + // todo: the order of updating could be a problem. maybe looping through ownsOne and belongsTo first is better. + + foreach (static::$columns as $key => $column) { + if (isset(static::$ownsOne[$propertyName]) && $column['internal'] === $propertyName) { + $id = self::updateOwnsOne($propertyName, $property->getValue($obj)); + $value = self::parseValue($column['type'], $id); + + // todo: should not be done if the id didn't change. but for now don't know if id changed + $query->update($column['name'])->value($value, $column['type']); + break; + } elseif (isset(static::$belongsTo[$propertyName]) && $column['internal'] === $propertyName) { + $id = self::updateBelongsTo($propertyName, $property->getValue($obj)); + $value = self::parseValue($column['type'], $id); + + // todo: should not be done if the id didn't change. but for now don't know if id changed + $query->update($column['name'])->value($value, $column['type']); + break; + } elseif ($column['internal'] === $propertyName && $column['type'] !== static::$primaryField) { + $value = self::parseValue($column['type'], $property->getValue($obj)); + + $query->update($column['name'])->value($value, $column['type']); + break; + } + } + + if (!($isPublic)) { + $property->setAccessible(false); + } + } + + self::$db->con->prepare($query->toSql())->execute(); + } + + /** + * Update object in db. + * + * @param mixed $obj Object reference (gets filled with insert id) + * @param int $relations Create all relations as well + * + * @return int + * + * @since 1.0.0 + */ + public static function update($obj, int $relations = RelationType::ALL) : int + { + self::extend(__CLASS__); + $reflectionClass = new \ReflectionClass(get_class($obj)); + $objId = self::getObjectId($obj, $reflectionClass); + $update = true; + + if(empty($objId)) { + $update = false; + self::create($obj, $relations); + } + + if ($relations === RelationType::ALL) { + self::updateHasMany($reflectionClass, $obj, $objId); + } + + if($update) { + self::updateModel($obj, $objId, $reflectionClass); + } + + return $objId; + } +} From 9958f81c081211a9e3e10346768f9d23370faa87 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Thu, 14 Sep 2017 08:51:45 +0200 Subject: [PATCH 07/76] fix #121 --- DataStorage/Database/GrammarAbstract.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/DataStorage/Database/GrammarAbstract.php b/DataStorage/Database/GrammarAbstract.php index 99e0c5e47..1039e97ab 100644 --- a/DataStorage/Database/GrammarAbstract.php +++ b/DataStorage/Database/GrammarAbstract.php @@ -172,6 +172,10 @@ abstract class GrammarAbstract foreach ($elements as $key => $element) { if (is_string($element) && $element !== '*') { + if(strpos($element, '.')) { + $prefix = ''; + } + $expression .= $this->compileSystem($element, $prefix) . ', '; } elseif (is_string($element) && $element === '*') { $expression .= '*, '; From a4e277184e95c7aafa5234ec8859889b187738b3 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Thu, 14 Sep 2017 08:59:09 +0200 Subject: [PATCH 08/76] Fix grammar bugs --- DataStorage/Database/DataMapperAbstract.php | 9 +++-- DataStorage/Database/GrammarAbstract.php | 33 ++++++++++++++++++- .../Database/Query/Grammar/Grammar.php | 2 +- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/DataStorage/Database/DataMapperAbstract.php b/DataStorage/Database/DataMapperAbstract.php index 0f059248c..6bab26dac 100644 --- a/DataStorage/Database/DataMapperAbstract.php +++ b/DataStorage/Database/DataMapperAbstract.php @@ -2239,11 +2239,14 @@ class DataMapperAbstract implements DataMapperInterface */ public static function getPrimaryKeyBy($refKey, string $ref) : array { - $query = self::getQuery(); - $query->select(static::$primaryField) + $query = new Builder(self::$db); + $query->prefix(self::$db->getPrefix()) + ->select(static::$table . '.' . static::$primaryField) ->from(static::$table) ->where(static::$table . '.' . $ref, '=', $refKey); + var_dump($query->toSql()); + $sth = self::$db->con->prepare($query->toSql()); $sth->execute(); @@ -2493,6 +2496,6 @@ class DataMapperAbstract implements DataMapperInterface } } - throw \Exception(); + throw new \Exception('Invalid member name'); } } diff --git a/DataStorage/Database/GrammarAbstract.php b/DataStorage/Database/GrammarAbstract.php index 1039e97ab..a221750b1 100644 --- a/DataStorage/Database/GrammarAbstract.php +++ b/DataStorage/Database/GrammarAbstract.php @@ -172,7 +172,7 @@ abstract class GrammarAbstract foreach ($elements as $key => $element) { if (is_string($element) && $element !== '*') { - if(strpos($element, '.')) { + if(strpos($element, '.') === false) { $prefix = ''; } @@ -191,6 +191,37 @@ abstract class GrammarAbstract return rtrim($expression, ', '); } + /** + * Expressionize elements. + * + * @param array $elements Elements + * @param string $prefix Prefix for table + * + * @return string + * + * @since 1.0.0 + */ + protected function expressionizeTable(array $elements, string $prefix = '') : string + { + $expression = ''; + + foreach ($elements as $key => $element) { + if (is_string($element) && $element !== '*') { + $expression .= $this->compileSystem($element, $prefix) . ', '; + } elseif (is_string($element) && $element === '*') { + $expression .= '*, '; + } elseif ($element instanceof \Closure) { + $expression .= $element() . ', '; + } elseif ($element instanceof BuilderAbstract) { + $expression .= $element->toSql() . ', '; + } else { + throw new \InvalidArgumentException(); + } + } + + return rtrim($expression, ', '); + } + /** * Compile system. * diff --git a/DataStorage/Database/Query/Grammar/Grammar.php b/DataStorage/Database/Query/Grammar/Grammar.php index a67b302b1..f3269307c 100644 --- a/DataStorage/Database/Query/Grammar/Grammar.php +++ b/DataStorage/Database/Query/Grammar/Grammar.php @@ -169,7 +169,7 @@ class Grammar extends GrammarAbstract */ protected function compileFrom(Builder $query, array $table) : string { - $expression = $this->expressionizeTableColumn($table, $query->getPrefix()); + $expression = $this->expressionizeTable($table, $query->getPrefix()); if ($expression === '') { return ''; From b991f3f865cc7b6338e2e17cc4cf057c62f2ebfd Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Thu, 14 Sep 2017 09:00:06 +0200 Subject: [PATCH 09/76] remove dump --- DataStorage/Database/DataMapperAbstract.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/DataStorage/Database/DataMapperAbstract.php b/DataStorage/Database/DataMapperAbstract.php index 6bab26dac..274418a3e 100644 --- a/DataStorage/Database/DataMapperAbstract.php +++ b/DataStorage/Database/DataMapperAbstract.php @@ -2245,8 +2245,6 @@ class DataMapperAbstract implements DataMapperInterface ->from(static::$table) ->where(static::$table . '.' . $ref, '=', $refKey); - var_dump($query->toSql()); - $sth = self::$db->con->prepare($query->toSql()); $sth->execute(); From 3afc442cf0c596b6915102bcc8558feda9b590b3 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Thu, 14 Sep 2017 09:15:15 +0200 Subject: [PATCH 10/76] add space --- DataStorage/Database/DataMapperAbstract.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DataStorage/Database/DataMapperAbstract.php b/DataStorage/Database/DataMapperAbstract.php index 274418a3e..8fe38be08 100644 --- a/DataStorage/Database/DataMapperAbstract.php +++ b/DataStorage/Database/DataMapperAbstract.php @@ -1937,6 +1937,7 @@ class DataMapperAbstract implements DataMapperInterface // todo: this only works for belongsTo not for many-to-many relations. Implement many-to-many $obj[$value] = self::get(self::getPrimaryKeyBy($value, self::getColumnByMember($ref)), $relations, $fill); } + return count($obj) === 1 ? reset($obj) : $obj; } @@ -1967,6 +1968,7 @@ class DataMapperAbstract implements DataMapperInterface // todo: this only works for belongsTo not for many-to-many relations. Implement many-to-many $obj[$value] = self::getArray(self::getPrimaryKeyBy($value, self::getColumnByMember($ref)), $relations, $fill); } + return count($obj) === 1 ? reset($obj) : $obj; } From c608caa0e25765e30d6223906e4bbbb7a59b44ca Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Thu, 14 Sep 2017 10:17:40 +0200 Subject: [PATCH 11/76] fix datamapper null value for obj --- DataStorage/Database/DataMapperAbstract.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/DataStorage/Database/DataMapperAbstract.php b/DataStorage/Database/DataMapperAbstract.php index 8fe38be08..8e9dfbc11 100644 --- a/DataStorage/Database/DataMapperAbstract.php +++ b/DataStorage/Database/DataMapperAbstract.php @@ -1765,7 +1765,10 @@ class DataMapperAbstract implements DataMapperInterface } if (in_array(static::$columns[$column]['type'], ['string', 'int', 'float', 'bool'])) { - settype($value, static::$columns[$column]['type']); + if($reflectionProperty->getValue($obj) !== null) { + settype($value, static::$columns[$column]['type']); + } + $reflectionProperty->setValue($obj, $value); } elseif (static::$columns[$column]['type'] === 'DateTime') { $reflectionProperty->setValue($obj, new \DateTime($value ?? '')); From cb0a443c55a64e9fbd25e1af681e0c0c363b9c51 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Thu, 14 Sep 2017 10:18:01 +0200 Subject: [PATCH 12/76] pull out permission to framework --- Account/Account.php | 22 ++++++ Account/PermissionAbstract.php | 136 +++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 Account/PermissionAbstract.php diff --git a/Account/Account.php b/Account/Account.php index 32c6174af..b26249b62 100644 --- a/Account/Account.php +++ b/Account/Account.php @@ -207,6 +207,28 @@ class Account implements ArrayableInterface, \JsonSerializable $this->l11n = $l11n; } + public function setPermissions(array $permissions) /* : void */ + { + $this->permissions = $permissions; + } + + public function hasPermission(int $permission, int $unit = null, string $app = null, int $module = null, int $type = null, $element = null, $component = null) : bool + { + foreach($this->permissions as $p) { + if(($p->getUnit() === $unit || $p->getUnit() === null) + && ($p->getApp() === $app || $p->getApp() === null) + && ($p->getModule() === $module || $p->getModule() === null) + && ($p->getType() === $type || $p->getType() === null) + && ($p->getElement() === $element || $p->getElement() === null) + && ($p->getComponent() === $component || $p->getComponent() === null) + && ($p->getPermission() | $permission) === $p->getPermission()) { + return true; + } + } + + return false; + } + /** * Get name. * diff --git a/Account/PermissionAbstract.php b/Account/PermissionAbstract.php new file mode 100644 index 000000000..ee6736ea4 --- /dev/null +++ b/Account/PermissionAbstract.php @@ -0,0 +1,136 @@ +unit; + } + + public function getApp() + { + return $this->app; + } + + public function getModule() + { + return $this->module; + } + + public function getFrom() + { + return $this->from; + } + + public function getType() + { + return $this->type; + } + + public function getElement() + { + return $this->element; + } + + public function getComponent() + { + return $this->component; + } + + public function getPermission() : int + { + return $this->permission; + } + + public function setUnit(int $unit = null) /* : void */ + { + $this->unit = $unit; + } + + public function setApp(int $app = null) /* : void */ + { + $this->app = $app; + } + + public function setModule(int $module = null) /* : void */ + { + $this->module = $module; + } + + public function setFrom(int $from = null) /* : void */ + { + $this->from = $from; + } + + public function setType(int $type = null) /* : void */ + { + $this->type = $type; + } + + public function setElement(int $element = null) /* : void */ + { + $this->element = $element; + } + + public function setComponent(int $component = null) /* : void */ + { + $this->component = $component; + } + + public function setPermission(int $permission = 0) /* : void */ + { + if($permission === 0) { + $this->permission = 0; + } else { + $this->permission |= $permission; + } + } +} From 8a6659cdd2f50a147666bf6b81d5530377d92500 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Thu, 14 Sep 2017 11:05:25 +0200 Subject: [PATCH 13/76] set empty result set as null --- DataStorage/Database/DataMapperAbstract.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/DataStorage/Database/DataMapperAbstract.php b/DataStorage/Database/DataMapperAbstract.php index 8e9dfbc11..ecbcc601d 100644 --- a/DataStorage/Database/DataMapperAbstract.php +++ b/DataStorage/Database/DataMapperAbstract.php @@ -1703,7 +1703,7 @@ class DataMapperAbstract implements DataMapperInterface } else { $value = $mapper::get($reflectionProperty->getValue($obj)); } - + $reflectionProperty->setValue($obj, $value); if (!$accessible) { @@ -1765,10 +1765,10 @@ class DataMapperAbstract implements DataMapperInterface } if (in_array(static::$columns[$column]['type'], ['string', 'int', 'float', 'bool'])) { - if($reflectionProperty->getValue($obj) !== null) { + if($reflectionProperty->getValue($obj) !== null || $value !== null) { settype($value, static::$columns[$column]['type']); } - + $reflectionProperty->setValue($obj, $value); } elseif (static::$columns[$column]['type'] === 'DateTime') { $reflectionProperty->setValue($obj, new \DateTime($value ?? '')); @@ -1872,7 +1872,15 @@ class DataMapperAbstract implements DataMapperInterface self::fillRelations($obj, $relations); self::clear(); - return count($obj) === 1 ? reset($obj) : $obj; + $countResulsts = count($obj); + + if($countResulsts === 0) { + return null; + } elseif($countResulsts === 1) { + return reset($obj); + } + + return $obj; } /** From b66feafa7e3b9d990fbb3e0f0750de4294e5432b Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Thu, 14 Sep 2017 14:01:29 +0200 Subject: [PATCH 14/76] fix #89 --- DataStorage/Database/DataMapperAbstract.php | 60 ++++++++++++++++++--- 1 file changed, 54 insertions(+), 6 deletions(-) diff --git a/DataStorage/Database/DataMapperAbstract.php b/DataStorage/Database/DataMapperAbstract.php index ecbcc601d..24aa590c7 100644 --- a/DataStorage/Database/DataMapperAbstract.php +++ b/DataStorage/Database/DataMapperAbstract.php @@ -1945,11 +1945,26 @@ class DataMapperAbstract implements DataMapperInterface $obj = []; foreach ($refKey as $key => $value) { - // todo: this only works for belongsTo not for many-to-many relations. Implement many-to-many - $obj[$value] = self::get(self::getPrimaryKeyBy($value, self::getColumnByMember($ref)), $relations, $fill); + $toLoad = []; + + if(isset(static::$hasMany[$ref]) && static::$hasMany[$ref]['src'] !== null) { + $toLoad = self::getHasManyPrimaryKeys($value, $ref); + } else { + $toLoad = self::getPrimaryKeysBy($value, self::getColumnByMember($ref)); + } + + $obj[$value] = self::get($toLoad, $relations, $fill); } - return count($obj) === 1 ? reset($obj) : $obj; + $countResulsts = count($obj); + + if($countResulsts === 0) { + return null; + } elseif($countResulsts === 1) { + return reset($obj); + } + + return $obj; } /** @@ -1976,8 +1991,15 @@ class DataMapperAbstract implements DataMapperInterface $obj = []; foreach ($refKey as $key => $value) { - // todo: this only works for belongsTo not for many-to-many relations. Implement many-to-many - $obj[$value] = self::getArray(self::getPrimaryKeyBy($value, self::getColumnByMember($ref)), $relations, $fill); + $toLoad = []; + + if(isset(static::$hasMany[$ref]) && static::$hasMany[$ref]['src'] !== null) { + $toLoad = self::getHasManyPrimaryKeys($value, $ref); + } else { + $toLoad = self::getPrimaryKeysBy($value, self::getColumnByMember($ref)); + } + + $obj[$value] = self::get($toLoad, $relations, $fill); } return count($obj) === 1 ? reset($obj) : $obj; @@ -2250,7 +2272,7 @@ class DataMapperAbstract implements DataMapperInterface * * @since 1.0.0 */ - public static function getPrimaryKeyBy($refKey, string $ref) : array + public static function getPrimaryKeysBy($refKey, string $ref) : array { $query = new Builder(self::$db); $query->prefix(self::$db->getPrefix()) @@ -2266,6 +2288,32 @@ class DataMapperAbstract implements DataMapperInterface return $results; } + /** + * Get object. + * + * @param mixed $refKey Key + * @param string $ref Ref + * + * @return mixed + * + * @since 1.0.0 + */ + public static function getHasManyPrimaryKeys($refKey, string $ref) : array + { + $query = new Builder(self::$db); + $query->prefix(self::$db->getPrefix()) + ->select(static::$hasMany[$ref]['table'] . '.' . static::$hasMany[$ref]['dst']) + ->from(static::$hasMany[$ref]['table']) + ->where(static::$hasMany[$ref]['table'] . '.' . static::$hasMany[$ref]['src'], '=', $refKey); + + $sth = self::$db->con->prepare($query->toSql()); + $sth->execute(); + + $results = array_column($sth->fetchAll(\PDO::FETCH_NUM) ?? [], 0); + + return $results; + } + /** * Get all in raw output. * From 49133a58f6aedcbb1ace7523025a196634f1763d Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Thu, 14 Sep 2017 15:21:58 +0200 Subject: [PATCH 15/76] visual fixes and alignments --- Account/AccountStatus.php | 8 +-- Account/AccountType.php | 4 +- Account/GroupStatus.php | 8 ++- Asset/AssetType.php | 6 +-- Auth/LoginReturnType.php | 18 +++---- Business/Marketing/NetPromoterScore.php | 4 +- DataStorage/Database/DataMapperAbstract.php | 43 ++++++++------- DataStorage/Database/DeleteMapperAbstract.php | 2 +- Message/Http/Header.php | 8 +-- Message/Http/OSType.php | 44 +++++++-------- Message/Http/Request.php | 7 +-- Message/Http/RequestMethod.php | 12 ++--- Message/Http/RequestStatus.php | 54 ------------------- Message/Http/RequestStatusCode.php | 54 ------------------- Module/ModuleManager.php | 5 +- System/File/ContentPutMode.php | 8 +-- System/File/ExtensionType.php | 18 +++---- System/File/FileUtils.php | 16 +++--- System/SystemType.php | 8 +-- Uri/UriScheme.php | 24 ++++----- Utils/ArrayUtils.php | 2 +- Utils/Permutation.php | 2 + Utils/StringUtils.php | 20 ++++++- 23 files changed, 145 insertions(+), 230 deletions(-) diff --git a/Account/AccountStatus.php b/Account/AccountStatus.php index c7aa95269..e8d8efd75 100644 --- a/Account/AccountStatus.php +++ b/Account/AccountStatus.php @@ -28,8 +28,8 @@ use phpOMS\Stdlib\Base\Enum; */ abstract class AccountStatus extends Enum { - /* public */ const ACTIVE = 1; - /* public */ const INACTIVE = 2; - /* public */ const TIMEOUT = 3; - /* public */ const BANNED = 4; + /* public */ const ACTIVE = 1; + /* public */ const INACTIVE = 2; + /* public */ const TIMEOUT = 3; + /* public */ const BANNED = 4; } diff --git a/Account/AccountType.php b/Account/AccountType.php index 92369d6c9..8e63e53b7 100644 --- a/Account/AccountType.php +++ b/Account/AccountType.php @@ -28,6 +28,6 @@ use phpOMS\Stdlib\Base\Enum; */ abstract class AccountType extends Enum { - /* public */ const USER = 0; - /* public */ const GROUP = 1; + /* public */ const USER = 0; + /* public */ const GROUP = 1; } diff --git a/Account/GroupStatus.php b/Account/GroupStatus.php index 14916b4ef..b5fdbf19c 100644 --- a/Account/GroupStatus.php +++ b/Account/GroupStatus.php @@ -28,9 +28,7 @@ use phpOMS\Stdlib\Base\Enum; */ abstract class GroupStatus extends Enum { - /* public */ const ACTIVE = 1; - - /* public */ const INACTIVE = 2; - - /* public */ const HIDDEN = 4; + /* public */ const ACTIVE = 1; + /* public */ const INACTIVE = 2; + /* public */ const HIDDEN = 4; } diff --git a/Asset/AssetType.php b/Asset/AssetType.php index 7f710555f..95fd69919 100644 --- a/Asset/AssetType.php +++ b/Asset/AssetType.php @@ -28,7 +28,7 @@ use phpOMS\Stdlib\Base\Enum; */ abstract class AssetType extends Enum { - /* public */ const CSS = 0; - /* public */ const JS = 1; - /* public */ const JSLATE = 2; + /* public */ const CSS = 0; + /* public */ const JS = 1; + /* public */ const JSLATE = 2; } diff --git a/Auth/LoginReturnType.php b/Auth/LoginReturnType.php index 8ce0352ae..b18aa8db0 100644 --- a/Auth/LoginReturnType.php +++ b/Auth/LoginReturnType.php @@ -30,14 +30,14 @@ use phpOMS\Stdlib\Base\Enum; */ abstract class LoginReturnType extends Enum { - /* public */ const OK = 0; /* Everything is ok and the user got authed */ - /* public */ const FAILURE = -1; /* Authentication resulted in a unexpected failure */ - /* public */ const WRONG_PASSWORD = -2; /* Authentication with wrong password */ - /* public */ const WRONG_USERNAME = -3; /* Authentication with unknown user */ - /* public */ const WRONG_PERMISSION = -4; /* User doesn't have permission to authenticate */ - /* public */ const NOT_ACTIVATED = -5; /* The user is not activated yet */ + /* public */ const OK = 0; /* Everything is ok and the user got authed */ + /* public */ const FAILURE = -1; /* Authentication resulted in a unexpected failure */ + /* public */ const WRONG_PASSWORD = -2; /* Authentication with wrong password */ + /* public */ const WRONG_USERNAME = -3; /* Authentication with unknown user */ + /* public */ const WRONG_PERMISSION = -4; /* User doesn't have permission to authenticate */ + /* public */ const NOT_ACTIVATED = -5; /* The user is not activated yet */ /* public */ const WRONG_INPUT_EXCEEDED = -6; /* Too many wrong logins recently */ - /* public */ const TIMEOUTED = -7; /* User received a timeout and can not log in until a certain date */ - /* public */ const BANNED = -8; /* User is banned */ - /* public */ const INACTIVE = -9; /* User is inactive */ + /* public */ const TIMEOUTED = -7; /* User received a timeout and can not log in until a certain date */ + /* public */ const BANNED = -8; /* User is banned */ + /* public */ const INACTIVE = -9; /* User is inactive */ } diff --git a/Business/Marketing/NetPromoterScore.php b/Business/Marketing/NetPromoterScore.php index 81a857fd3..7063632af 100644 --- a/Business/Marketing/NetPromoterScore.php +++ b/Business/Marketing/NetPromoterScore.php @@ -65,8 +65,8 @@ class NetPromoterScore { */ public function getScore() : int { - $promoters = 0; - $passives = 0; + $promoters = 0; + $passives = 0; $detractors = 0; foreach($this->scores as $score) { diff --git a/DataStorage/Database/DataMapperAbstract.php b/DataStorage/Database/DataMapperAbstract.php index 24aa590c7..26df425b6 100644 --- a/DataStorage/Database/DataMapperAbstract.php +++ b/DataStorage/Database/DataMapperAbstract.php @@ -505,7 +505,7 @@ class DataMapperAbstract implements DataMapperInterface */ private static function getObjectId($obj, \ReflectionClass $reflectionClass = null) { - $reflectionClass = $reflectionClass ?? new \ReflectionClass(get_class($obj)); + $reflectionClass = $reflectionClass ?? new \ReflectionClass(get_class($obj)); $reflectionProperty = $reflectionClass->getProperty(static::$columns[static::$primaryField]['internal']); if (!($isPublic = $reflectionProperty->isPublic())) { @@ -710,7 +710,7 @@ class DataMapperAbstract implements DataMapperInterface private static function createOwnsOne(string $propertyName, $obj) { if (is_object($obj)) { - $mapper = static::$ownsOne[$propertyName]['mapper']; + $mapper = static::$ownsOne[$propertyName]['mapper']; $primaryKey = $mapper::getObjectId($obj); if (empty($primaryKey)) { @@ -738,7 +738,7 @@ class DataMapperAbstract implements DataMapperInterface private static function createOwnsOneArray(string $propertyName, array &$obj) { if (is_array($obj)) { - $mapper = static::$ownsOne[$propertyName]['mapper']; + $mapper = static::$ownsOne[$propertyName]['mapper']; $primaryKey = $obj[static::$columns[static::$primaryField]['internal']]; if (empty($primaryKey)) { @@ -767,7 +767,7 @@ class DataMapperAbstract implements DataMapperInterface { if (is_object($obj)) { /** @var DataMapperAbstract $mapper */ - $mapper = static::$belongsTo[$propertyName]['mapper']; + $mapper = static::$belongsTo[$propertyName]['mapper']; $primaryKey = $mapper::getObjectId($obj); if (empty($primaryKey)) { @@ -796,7 +796,7 @@ class DataMapperAbstract implements DataMapperInterface { if (is_array($obj)) { /** @var DataMapperAbstract $mapper */ - $mapper = static::$belongsTo[$propertyName]['mapper']; + $mapper = static::$belongsTo[$propertyName]['mapper']; $primaryKey = $obj[static::$columns[static::$primaryField]['internal']]; if (empty($primaryKey)) { @@ -991,7 +991,7 @@ class DataMapperAbstract implements DataMapperInterface // todo: definately an error here. needs testing throw new \Exception(); $removes = array_diff_key($many[$member], $objsIds[$member]); - $adds = array_diff_key($objsIds[$member], $many[$member]); + $adds = array_diff_key($objsIds[$member], $many[$member]); if(!empty($removes)) { self::deleteRelationTable($propertyName, $removes, $objId); @@ -1122,7 +1122,7 @@ class DataMapperAbstract implements DataMapperInterface foreach (static::$columns as $key => $column) { if (isset(static::$ownsOne[$propertyName]) && $column['internal'] === $propertyName) { - $id = self::updateOwnsOne($propertyName, $property->getValue($obj)); + $id = self::updateOwnsOne($propertyName, $property->getValue($obj)); $value = self::parseValue($column['type'], $id); // todo: should not be done if the id didn't change. but for now don't know if id changed @@ -1164,9 +1164,10 @@ class DataMapperAbstract implements DataMapperInterface public static function update($obj, int $relations = RelationType::ALL) : int { self::extend(__CLASS__); + $reflectionClass = new \ReflectionClass(get_class($obj)); - $objId = self::getObjectId($obj, $reflectionClass); - $update = true; + $objId = self::getObjectId($obj, $reflectionClass); + $update = true; if(empty($objId)) { $update = false; @@ -1373,8 +1374,9 @@ class DataMapperAbstract implements DataMapperInterface public static function delete($obj, int $relations = RelationType::REFERENCE) { self::extend(__CLASS__); + $reflectionClass = new \ReflectionClass(get_class($obj)); - $objId = self::getObjectId($obj, $reflectionClass); + $objId = self::getObjectId($obj, $reflectionClass); if(empty($objId)) { return null; @@ -1521,8 +1523,9 @@ class DataMapperAbstract implements DataMapperInterface foreach ($result as $member => $values) { if (!empty($values)) { /** @var DataMapperAbstract $mapper */ - $mapper = static::$hasMany[$member]['mapper']; + $mapper = static::$hasMany[$member]['mapper']; $values = array_diff($values, array_keys(self::$initObjects[$mapper] ?? [])); + if(empty($values)) { continue; } @@ -1942,7 +1945,7 @@ class DataMapperAbstract implements DataMapperInterface self::extend(__CLASS__); $refKey = (array) $refKey; - $obj = []; + $obj = []; foreach ($refKey as $key => $value) { $toLoad = []; @@ -2125,7 +2128,7 @@ class DataMapperAbstract implements DataMapperInterface */ public static function getAllByQuery(Builder $query, int $relations = RelationType::ALL) : array { - $sth = self::$db->con->prepare($query->toSql()); + $sth = self::$db->con->prepare($query->toSql()); $sth->execute(); $results = $sth->fetchAll(\PDO::FETCH_ASSOC); @@ -2174,9 +2177,9 @@ class DataMapperAbstract implements DataMapperInterface */ public static function fillRelations(array &$obj, int $relations = RelationType::ALL) /* : void */ { - $hasMany = !empty(static::$hasMany); - $hasOne = !empty(static::$hasOne); - $ownsOne = !empty(static::$ownsOne); + $hasMany = !empty(static::$hasMany); + $hasOne = !empty(static::$hasOne); + $ownsOne = !empty(static::$ownsOne); $belongsTo = !empty(static::$belongsTo); if ($relations !== RelationType::NONE && ($hasMany || $hasOne || $ownsOne || $belongsTo)) { @@ -2213,9 +2216,9 @@ class DataMapperAbstract implements DataMapperInterface */ public static function fillRelationsArray(array &$obj, int $relations = RelationType::ALL) /* : void */ { - $hasMany = !empty(static::$hasMany); - $hasOne = !empty(static::$hasOne); - $ownsOne = !empty(static::$ownsOne); + $hasMany = !empty(static::$hasMany); + $hasOne = !empty(static::$hasOne); + $ownsOne = !empty(static::$ownsOne); $belongsTo = !empty(static::$belongsTo); if ($relations !== RelationType::NONE && ($hasMany || $hasOne || $ownsOne || $belongsTo)) { @@ -2331,7 +2334,7 @@ class DataMapperAbstract implements DataMapperInterface $query->where(static::$table . '.' . static::$language_field, '=', $lang, 'AND'); } - $sth = self::$db->con->prepare($query->toSql()); + $sth = self::$db->con->prepare($query->toSql()); $sth->execute(); $results = $sth->fetchAll(\PDO::FETCH_ASSOC); diff --git a/DataStorage/Database/DeleteMapperAbstract.php b/DataStorage/Database/DeleteMapperAbstract.php index 6e3bd8661..7ca8fed90 100644 --- a/DataStorage/Database/DeleteMapperAbstract.php +++ b/DataStorage/Database/DeleteMapperAbstract.php @@ -243,7 +243,7 @@ class DeleteMapperAbstract extends DataMapperBaseAbstract { self::extend(__CLASS__); $reflectionClass = new \ReflectionClass(get_class($obj)); - $objId = self::getObjectId($obj, $reflectionClass); + $objId = self::getObjectId($obj, $reflectionClass); if(empty($objId)) { return null; diff --git a/Message/Http/Header.php b/Message/Http/Header.php index 0a8e341b0..f53d0a24b 100644 --- a/Message/Http/Header.php +++ b/Message/Http/Header.php @@ -111,10 +111,10 @@ class Header extends HeaderAbstract */ private function isSecurityHeader(string $key) : bool { - return $key === 'content-security-policy' || - $key === 'x-xss-protection' || - $key === 'x-content-type-options' || - $key === 'x-frame-options'; + return $key === 'content-security-policy' + || $key === 'x-xss-protection' + || $key === 'x-content-type-options' + || $key === 'x-frame-options'; } /** diff --git a/Message/Http/OSType.php b/Message/Http/OSType.php index 343381749..3c5c76f66 100644 --- a/Message/Http/OSType.php +++ b/Message/Http/OSType.php @@ -30,27 +30,27 @@ use phpOMS\Stdlib\Base\Enum; */ abstract class OSType extends Enum { - /* public */ const WINDOWS_81 = 'windows nt 6.3'; /* Windows 8.1 */ - /* public */ const WINDOWS_8 = 'windows nt 6.2'; /* Windows 8 */ - /* public */ const WINDOWS_7 = 'windows nt 6.1'; /* Windows 7 */ - /* public */ const WINDOWS_VISTA = 'windows nt 6.0'; /* Windows Vista */ + /* public */ const WINDOWS_81 = 'windows nt 6.3'; /* Windows 8.1 */ + /* public */ const WINDOWS_8 = 'windows nt 6.2'; /* Windows 8 */ + /* public */ const WINDOWS_7 = 'windows nt 6.1'; /* Windows 7 */ + /* public */ const WINDOWS_VISTA = 'windows nt 6.0'; /* Windows Vista */ /* public */ const WINDOWS_SERVER = 'windows nt 5.2'; /* Windows Server 2003/XP x64 */ - /* public */ const WINDOWS_XP = 'windows nt 5.1'; /* Windows XP */ - /* public */ const WINDOWS_XP_2 = 'windows xp'; /* Windows XP */ - /* public */ const WINDOWS_2000 = 'windows nt 5.0'; /* Windows 2000 */ - /* public */ const WINDOWS_ME = 'windows me'; /* Windows ME */ - /* public */ const WINDOWS_98 = 'win98'; /* Windows 98 */ - /* public */ const WINDOWS_95 = 'win95'; /* Windows 95 */ - /* public */ const WINDOWS_311 = 'win16'; /* Windows 3.11 */ - /* public */ const MAC_OS_X = 'macintosh'; /* Mac OS X */ - /* public */ const MAC_OS_X_2 = 'mac os x'; /* Mac OS X */ - /* public */ const MAC_OS_9 = 'mac_powerpc'; /* Mac OS 9 */ - /* public */ const LINUX = 'linux'; /* Linux */ - /* public */ const UBUNTU = 'ubuntu'; /* Ubuntu */ - /* public */ const IPHONE = 'iphone'; /* IPhone */ - /* public */ const IPOD = 'ipod'; /* IPod */ - /* public */ const IPAD = 'ipad'; /* IPad */ - /* public */ const ANDROID = 'android'; /* Android */ - /* public */ const BLACKBERRY = 'blackberry'; /* Blackberry */ - /* public */ const MOBILE = 'webos'; /* Mobile */ + /* public */ const WINDOWS_XP = 'windows nt 5.1'; /* Windows XP */ + /* public */ const WINDOWS_XP_2 = 'windows xp'; /* Windows XP */ + /* public */ const WINDOWS_2000 = 'windows nt 5.0'; /* Windows 2000 */ + /* public */ const WINDOWS_ME = 'windows me'; /* Windows ME */ + /* public */ const WINDOWS_98 = 'win98'; /* Windows 98 */ + /* public */ const WINDOWS_95 = 'win95'; /* Windows 95 */ + /* public */ const WINDOWS_311 = 'win16'; /* Windows 3.11 */ + /* public */ const MAC_OS_X = 'macintosh'; /* Mac OS X */ + /* public */ const MAC_OS_X_2 = 'mac os x'; /* Mac OS X */ + /* public */ const MAC_OS_9 = 'mac_powerpc'; /* Mac OS 9 */ + /* public */ const LINUX = 'linux'; /* Linux */ + /* public */ const UBUNTU = 'ubuntu'; /* Ubuntu */ + /* public */ const IPHONE = 'iphone'; /* IPhone */ + /* public */ const IPOD = 'ipod'; /* IPod */ + /* public */ const IPAD = 'ipad'; /* IPad */ + /* public */ const ANDROID = 'android'; /* Android */ + /* public */ const BLACKBERRY = 'blackberry'; /* Blackberry */ + /* public */ const MOBILE = 'webos'; /* Mobile */ } diff --git a/Message/Http/Request.php b/Message/Http/Request.php index 6f29e33c4..b4ab48c72 100644 --- a/Message/Http/Request.php +++ b/Message/Http/Request.php @@ -140,9 +140,9 @@ class Request extends RequestAbstract */ private function initCurrentRequest() /* : void */ { - $this->uri = new Http(Http::getCurrent()); - $this->data = $_GET ?? []; - $this->files = $_FILES ?? []; + $this->uri = new Http(Http::getCurrent()); + $this->data = $_GET ?? []; + $this->files = $_FILES ?? []; $this->language = $this->loadRequestLanguage(); if (isset($_SERVER['CONTENT_TYPE'])) { @@ -330,6 +330,7 @@ class Request extends RequestAbstract if (!isset($this->os)) { $arr = OSType::getConstants(); $http_request_type = strtolower($_SERVER['HTTP_USER_AGENT']); + foreach ($arr as $key => $val) { if (stripos($http_request_type, $val)) { $this->os = $val; diff --git a/Message/Http/RequestMethod.php b/Message/Http/RequestMethod.php index c287f14ee..d68d133cf 100644 --- a/Message/Http/RequestMethod.php +++ b/Message/Http/RequestMethod.php @@ -28,10 +28,10 @@ use phpOMS\Stdlib\Base\Enum; */ abstract class RequestMethod extends Enum { - /* public */ const GET = 'GET'; /* GET */ - /* public */ const POST = 'POST'; /* POST */ - /* public */ const PUT = 'PUT'; /* PUT */ - /* public */ const DELETE = 'DELETE'; /* DELETE */ - /* public */ const HEAD = 'HEAD'; /* HEAD */ - /* public */ const TRACE = 'TRACE'; /* TRACE */ + /* public */ const GET = 'GET'; /* GET */ + /* public */ const POST = 'POST'; /* POST */ + /* public */ const PUT = 'PUT'; /* PUT */ + /* public */ const DELETE = 'DELETE'; /* DELETE */ + /* public */ const HEAD = 'HEAD'; /* HEAD */ + /* public */ const TRACE = 'TRACE'; /* TRACE */ } diff --git a/Message/Http/RequestStatus.php b/Message/Http/RequestStatus.php index 537aabc46..0a573911a 100644 --- a/Message/Http/RequestStatus.php +++ b/Message/Http/RequestStatus.php @@ -29,112 +29,58 @@ use phpOMS\Stdlib\Base\Enum; abstract class RequestStatus extends Enum { /* public */ const R_100 = 'Continue'; - /* public */ const R_101 = 'Switching Protocols'; - /* public */ const R_102 = 'Processing'; - /* public */ const R_200 = 'OK'; - /* public */ const R_201 = 'Created'; - /* public */ const R_202 = 'Accepted'; - /* public */ const R_203 = 'Non-Authoritative Information'; - /* public */ const R_204 = 'No Content'; - /* public */ const R_205 = 'Reset Content'; - /* public */ const R_206 = 'Partial Content'; - /* public */ const R_207 = 'Multi-Status'; - /* public */ const R_300 = 'Multiple Choices'; - /* public */ const R_301 = 'Moved Permanently'; - /* public */ const R_302 = 'Found'; - /* public */ const R_303 = 'See Other'; - /* public */ const R_304 = 'Not Modified'; - /* public */ const R_305 = 'Use Proxy'; - /* public */ const R_306 = 'Switch Proxy'; - /* public */ const R_307 = 'Temporary Redirect'; - /* public */ const R_400 = 'Bad Request'; - /* public */ const R_401 = 'Unauthorized'; - /* public */ const R_402 = 'Payment Required'; - /* public */ const R_403 = 'Forbidden'; - /* public */ const R_404 = 'Not Found'; - /* public */ const R_405 = 'Method Not Allowed'; - /* public */ const R_406 = 'Not Acceptable'; - /* public */ const R_407 = 'Proxy Authentication Required'; - /* public */ const R_408 = 'Request Timeout'; - /* public */ const R_409 = 'Conflict'; - /* public */ const R_410 = 'Gone'; - /* public */ const R_411 = 'Length Required'; - /* public */ const R_412 = 'Precondition Failed'; - /* public */ const R_413 = 'Request Entity Too Large'; - /* public */ const R_414 = 'Request-URI Too Long'; - /* public */ const R_415 = 'Unsupported Media Type'; - /* public */ const R_416 = 'Requested Range Not Satisfiable'; - /* public */ const R_417 = 'Expectation Failed'; - /* public */ const R_418 = 'I\'m a teapot'; - /* public */ const R_422 = 'Unprocessable Entity'; - /* public */ const R_423 = 'Locked'; - /* public */ const R_424 = 'Failed Dependency'; - /* public */ const R_425 = 'Unordered Collection'; - /* public */ const R_426 = 'Upgrade Required'; - /* public */ const R_449 = 'Retry With'; - /* public */ const R_450 = 'Blocked by Windows Parental Controls'; - /* public */ const R_500 = 'Internal Server Error'; - /* public */ const R_501 = 'Not Implemented'; - /* public */ const R_502 = 'Bad Gateway'; - /* public */ const R_503 = 'Service Unavailable'; - /* public */ const R_504 = 'Gateway Timeout'; - /* public */ const R_505 = 'HTTP Version Not Supported'; - /* public */ const R_506 = 'Variant Also Negotiates'; - /* public */ const R_507 = 'Insufficient Storage'; - /* public */ const R_509 = 'Bandwidth Limit Exceeded'; - /* public */ const R_510 = 'Not Extended'; } diff --git a/Message/Http/RequestStatusCode.php b/Message/Http/RequestStatusCode.php index ea849833b..2d45d292c 100644 --- a/Message/Http/RequestStatusCode.php +++ b/Message/Http/RequestStatusCode.php @@ -28,112 +28,58 @@ use phpOMS\Stdlib\Base\Enum; abstract class RequestStatusCode extends Enum { /* public */ const R_100 = 100; - /* public */ const R_101 = 101; - /* public */ const R_102 = 102; - /* public */ const R_200 = 200; - /* public */ const R_201 = 201; - /* public */ const R_202 = 202; - /* public */ const R_203 = 203; - /* public */ const R_204 = 204; - /* public */ const R_205 = 205; - /* public */ const R_206 = 206; - /* public */ const R_207 = 207; - /* public */ const R_300 = 300; - /* public */ const R_301 = 301; - /* public */ const R_302 = 302; - /* public */ const R_303 = 303; - /* public */ const R_304 = 304; - /* public */ const R_305 = 305; - /* public */ const R_306 = 306; - /* public */ const R_307 = 307; - /* public */ const R_400 = 400; - /* public */ const R_401 = 401; - /* public */ const R_402 = 402; - /* public */ const R_403 = 403; - /* public */ const R_404 = 404; - /* public */ const R_405 = 405; - /* public */ const R_406 = 406; - /* public */ const R_407 = 407; - /* public */ const R_408 = 408; - /* public */ const R_409 = 409; - /* public */ const R_410 = 410; - /* public */ const R_411 = 411; - /* public */ const R_412 = 412; - /* public */ const R_413 = 413; - /* public */ const R_414 = 414; - /* public */ const R_415 = 415; - /* public */ const R_416 = 416; - /* public */ const R_417 = 417; - /* public */ const R_418 = 418; - /* public */ const R_422 = 422; - /* public */ const R_423 = 423; - /* public */ const R_424 = 424; - /* public */ const R_425 = 425; - /* public */ const R_426 = 426; - /* public */ const R_449 = 449; - /* public */ const R_450 = 450; - /* public */ const R_500 = 500; - /* public */ const R_501 = 501; - /* public */ const R_502 = 502; - /* public */ const R_503 = 503; - /* public */ const R_504 = 504; - /* public */ const R_505 = 505; - /* public */ const R_506 = 506; - /* public */ const R_507 = 507; - /* public */ const R_509 = 509; - /* public */ const R_510 = 510; } diff --git a/Module/ModuleManager.php b/Module/ModuleManager.php index 5fce9799f..e6235cfb9 100644 --- a/Module/ModuleManager.php +++ b/Module/ModuleManager.php @@ -116,9 +116,9 @@ class ModuleManager */ public function getRoutedModules(Request $request) : array { - $files = $this->getUriLoad($request); - + $files = $this->getUriLoad($request); $modules = []; + if (isset($files[4])) { foreach ($files[4] as $module) { $modules[] = $module['module_load_file']; @@ -147,6 +147,7 @@ class ModuleManager $i = 1; $c = count($uriHash); + for ($k = 0; $k < $c; $k++) { $uriPdo .= ':pid' . $i . ','; $i++; diff --git a/System/File/ContentPutMode.php b/System/File/ContentPutMode.php index 1293af244..a7af7c67a 100644 --- a/System/File/ContentPutMode.php +++ b/System/File/ContentPutMode.php @@ -30,8 +30,8 @@ use phpOMS\Stdlib\Base\Enum; */ abstract class ContentPutMode extends Enum { - /* public */ const APPEND = 1; - /* public */ const PREPEND = 2; - /* public */ const REPLACE = 4; - /* public */ const CREATE = 8; + /* public */ const APPEND = 1; + /* public */ const PREPEND = 2; + /* public */ const REPLACE = 4; + /* public */ const CREATE = 8; } \ No newline at end of file diff --git a/System/File/ExtensionType.php b/System/File/ExtensionType.php index 0eeb6ce57..7d034ee66 100644 --- a/System/File/ExtensionType.php +++ b/System/File/ExtensionType.php @@ -30,14 +30,14 @@ use phpOMS\Stdlib\Base\Enum; */ abstract class ExtensionType extends Enum { - /* public */ const UNKNOWN = 1; - /* public */ const CODE = 2; - /* public */ const AUDIO = 4; - /* public */ const VIDEO = 8; - /* public */ const TEXT = 16; - /* public */ const SPREADSHEET = 32; - /* public */ const PDF = 64; - /* public */ const ARCHIVE = 128; + /* public */ const UNKNOWN = 1; + /* public */ const CODE = 2; + /* public */ const AUDIO = 4; + /* public */ const VIDEO = 8; + /* public */ const TEXT = 16; + /* public */ const SPREADSHEET = 32; + /* public */ const PDF = 64; + /* public */ const ARCHIVE = 128; /* public */ const PRESENTATION = 256; - /* public */ const IMAGE = 512; + /* public */ const IMAGE = 512; } \ No newline at end of file diff --git a/System/File/FileUtils.php b/System/File/FileUtils.php index 089c7e3c5..4819bb5b9 100644 --- a/System/File/FileUtils.php +++ b/System/File/FileUtils.php @@ -26,15 +26,15 @@ namespace phpOMS\System\File; */ class FileUtils { - /* public */ const CODE_EXTENSION = ['cpp', 'c', 'h', 'hpp', 'cs', 'css', 'htm', 'html', 'php', 'rb']; - /* public */ const TEXT_EXTENSION = ['doc', 'docx', 'txt', 'md', 'csv']; + /* public */ const CODE_EXTENSION = ['cpp', 'c', 'h', 'hpp', 'cs', 'css', 'htm', 'html', 'php', 'rb']; + /* public */ const TEXT_EXTENSION = ['doc', 'docx', 'txt', 'md', 'csv']; /* public */ const PRESENTATION_EXTENSION = ['ppt', 'pptx']; - /* public */ const PDF_EXTENSION = ['pdf']; - /* public */ const ARCHIVE_EXTENSION = ['zip', '7z', 'rar']; - /* public */ const AUDIO_EXTENSION = ['mp3', 'wav']; - /* public */ const VIDEO_EXTENSION = ['mp4']; - /* public */ const SPREADSHEET_EXTENSION = ['xls', 'xlsm']; - /* public */ const IMAGE_EXTENSION = ['png', 'gif', 'jpg', 'jpeg', 'tiff', 'bmp']; + /* public */ const PDF_EXTENSION = ['pdf']; + /* public */ const ARCHIVE_EXTENSION = ['zip', '7z', 'rar']; + /* public */ const AUDIO_EXTENSION = ['mp3', 'wav']; + /* public */ const VIDEO_EXTENSION = ['mp4']; + /* public */ const SPREADSHEET_EXTENSION = ['xls', 'xlsm']; + /* public */ const IMAGE_EXTENSION = ['png', 'gif', 'jpg', 'jpeg', 'tiff', 'bmp']; private function __construct() { diff --git a/System/SystemType.php b/System/SystemType.php index a24a98490..5c630fe64 100644 --- a/System/SystemType.php +++ b/System/SystemType.php @@ -30,8 +30,8 @@ use phpOMS\Stdlib\Base\Enum; */ abstract class SystemType extends Enum { - /* public */ const UNKNOWN = 1; - /* public */ const WIN = 2; - /* public */ const LINUX = 3; - /* public */ const OSX = 4; + /* public */ const UNKNOWN = 1; + /* public */ const WIN = 2; + /* public */ const LINUX = 3; + /* public */ const OSX = 4; } \ No newline at end of file diff --git a/Uri/UriScheme.php b/Uri/UriScheme.php index f616af2be..1f8f6df2d 100644 --- a/Uri/UriScheme.php +++ b/Uri/UriScheme.php @@ -28,19 +28,19 @@ use phpOMS\Stdlib\Base\Enum; */ abstract class UriScheme extends Enum { - /* public */ const HTTP = 0; /* Http */ - /* public */ const FILE = 1; /* File */ + /* public */ const HTTP = 0; /* Http */ + /* public */ const FILE = 1; /* File */ /* public */ const MAILTO = 2; /* Mail */ - /* public */ const FTP = 3; /* FTP */ - /* public */ const HTTPS = 4; /* Https */ - /* public */ const IRC = 5; /* IRC */ - /* public */ const TEL = 6; /* Telephone */ + /* public */ const FTP = 3; /* FTP */ + /* public */ const HTTPS = 4; /* Https */ + /* public */ const IRC = 5; /* IRC */ + /* public */ const TEL = 6; /* Telephone */ /* public */ const TELNET = 7; /* Telnet */ - /* public */ const SSH = 8; /* SSH */ - /* public */ const SKYPE = 9; /* Skype */ - /* public */ const SSL = 10; /* SSL */ - /* public */ const NFS = 11; /* Network File System */ - /* public */ const GEO = 12; /* Geo location */ + /* public */ const SSH = 8; /* SSH */ + /* public */ const SKYPE = 9; /* Skype */ + /* public */ const SSL = 10; /* SSL */ + /* public */ const NFS = 11; /* Network File System */ + /* public */ const GEO = 12; /* Geo location */ /* public */ const MARKET = 13; /* Android Market */ - /* public */ const ITMS = 14; /* iTunes */ + /* public */ const ITMS = 14; /* iTunes */ } diff --git a/Utils/ArrayUtils.php b/Utils/ArrayUtils.php index f5907c521..814d4a3b9 100644 --- a/Utils/ArrayUtils.php +++ b/Utils/ArrayUtils.php @@ -294,6 +294,7 @@ class ArrayUtils // see collection collapse as alternative?! $flat = []; $stack = array_values($array); + while (!empty($stack)) { $value = array_shift($stack); @@ -322,7 +323,6 @@ class ArrayUtils { $count = $count === 0 ? count($array) : $start + $count; $sum = 0; - $array = array_values($array); for ($i = $start; $i <= $count - 1; $i++) { diff --git a/Utils/Permutation.php b/Utils/Permutation.php index 207530c4f..cdc0efd38 100644 --- a/Utils/Permutation.php +++ b/Utils/Permutation.php @@ -47,7 +47,9 @@ class Permutation $newArr = $toPermute; $newres = $result; $newres[] = $val; + unset($newArr[$key]); + $permutations = array_merge($permutations, self::permut($newArr, $newres)); } } diff --git a/Utils/StringUtils.php b/Utils/StringUtils.php index a0d175b0e..dcc3a2ce7 100644 --- a/Utils/StringUtils.php +++ b/Utils/StringUtils.php @@ -346,6 +346,15 @@ class StringUtils return $count; } + /** + * Calculate string entropy + * + * @param string $string String to analyze. + * + * @return float + * + * @since 1.0.0 + */ public static function getEntropy(string $value) : float { $entroy = 0.0; @@ -360,8 +369,17 @@ class StringUtils return $entroy; } + /** + * Count chars of utf-8 string. + * + * @param string $string String to count chars. + * + * @return int + * + * @since 1.0.0 + */ public static function mb_count_chars(string $input) { - $l = mb_strlen($input, 'UTF-8'); + $l = mb_strlen($input, 'UTF-8'); $unique = []; for($i = 0; $i < $l; $i++) { From d451301a33d0c985cd4d9e1818a40b61afec8a5b Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Thu, 14 Sep 2017 17:47:33 +0200 Subject: [PATCH 16/76] Perform code optimization from cachegrind --- DataStorage/Database/DataMapperAbstract.php | 6 +++--- DataStorage/Database/GrammarAbstract.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/DataStorage/Database/DataMapperAbstract.php b/DataStorage/Database/DataMapperAbstract.php index 26df425b6..3991f7e37 100644 --- a/DataStorage/Database/DataMapperAbstract.php +++ b/DataStorage/Database/DataMapperAbstract.php @@ -1454,7 +1454,7 @@ class DataMapperAbstract implements DataMapperInterface $class = static::class; $class = str_replace('Mapper', '', $class); - if (count($result) === 0) { + if (empty($result)) { $parts = explode('\\', $class); $name = $parts[$c = (count($parts) - 1)]; $parts[$c] = 'Null' . $name; @@ -1760,7 +1760,7 @@ class DataMapperAbstract implements DataMapperInterface $reflectionClass = new \ReflectionClass(get_class($obj)); foreach ($result as $column => $value) { - if (isset(static::$columns[$column]['internal']) && $reflectionClass->hasProperty(static::$columns[$column]['internal'])) { + if (isset(static::$columns[$column]['internal']) /* && $reflectionClass->hasProperty(static::$columns[$column]['internal']) */) { $reflectionProperty = $reflectionClass->getProperty(static::$columns[$column]['internal']); if (!($accessible = $reflectionProperty->isPublic())) { @@ -1768,7 +1768,7 @@ class DataMapperAbstract implements DataMapperInterface } if (in_array(static::$columns[$column]['type'], ['string', 'int', 'float', 'bool'])) { - if($reflectionProperty->getValue($obj) !== null || $value !== null) { + if($value !== null || $reflectionProperty->getValue($obj) !== null) { settype($value, static::$columns[$column]['type']); } diff --git a/DataStorage/Database/GrammarAbstract.php b/DataStorage/Database/GrammarAbstract.php index a221750b1..9140a1b6b 100644 --- a/DataStorage/Database/GrammarAbstract.php +++ b/DataStorage/Database/GrammarAbstract.php @@ -240,7 +240,7 @@ abstract class GrammarAbstract $identifier = $this->systemIdentifier; foreach($this->specialKeywords as $keyword) { - if(StringUtils::startsWith($system, $keyword)) { + if($keyword === '' || strrpos($system, $keyword, -strlen($system)) !== false) { $prefix = ''; $identifier = ''; } From 34c465766eb794dd1acbe49f41d7b9480974eeba Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Thu, 14 Sep 2017 19:52:53 +0200 Subject: [PATCH 17/76] Code inspection fixes --- Account/Account.php | 28 +- Account/PermissionAbstract.php | 232 +++- Account/PermissionType.php | 41 + Auth/Auth.php | 1 - Business/Sales/MarketShareEstimation.php | 2 +- DataStorage/Database/CreateMapperAbstract.php | 511 -------- DataStorage/Database/DataMapperAbstract.php | 66 +- .../Database/DatabaseExceptionFactory.php | 2 + DataStorage/Database/DatabaseStatus.php | 10 +- DataStorage/Database/DatabaseType.php | 10 +- DataStorage/Database/DeleteMapperAbstract.php | 295 ----- DataStorage/Database/GrammarAbstract.php | 4 +- DataStorage/Database/ReadMapperAbstract.php | 1126 ----------------- DataStorage/Database/RelationType.php | 12 +- DataStorage/Database/UpdateMapperAbstract.php | 326 ----- Localization/L11nManager.php | 24 +- Log/FileLogger.php | 2 - .../Regression/RegressionAbstract.php | 43 +- Math/Stochastic/NaiveBayesFilter.php | 2 +- Message/HeaderAbstract.php | 4 +- Message/Http/Header.php | 26 +- Message/Http/Request.php | 21 +- Message/Http/Response.php | 2 +- Message/ResponseAbstract.php | 1 - Module/InstallerAbstract.php | 2 +- Module/ModuleManager.php | 1 + Stdlib/Base/Iban.php | 2 - Stdlib/Base/Location.php | 37 + Stdlib/Base/SmartDateTime.php | 4 +- System/File/FileUtils.php | 14 + System/File/Storage.php | 1 + System/File/StorageAbstract.php | 5 +- UnhandledHandler.php | 13 +- Uri/Http.php | 5 +- Uri/UriInterface.php | 9 + Utils/EDI/AnsiX12/FunctionalGroupHeader.php | 2 +- .../EDI/AnsiX12/InterchangeControlHeader.php | 2 +- Utils/Encoding/Caesar.php | 2 +- Utils/IO/Zip/Gz.php | 8 +- Utils/IO/Zip/Tar.php | 3 +- Utils/IO/Zip/TarGz.php | 2 +- Utils/IO/Zip/Zip.php | 3 +- Utils/JobQueue/JobQueue.php | 2 +- Utils/StringCompare.php | 10 +- Utils/StringUtils.php | 13 +- Utils/TestUtils.php | 4 +- Validation/Finance/Iban.php | 6 +- Validation/Network/Ip.php | 18 + Validation/ValidatorAbstract.php | 7 + Views/View.php | 2 +- Views/ViewAbstract.php | 12 +- 51 files changed, 547 insertions(+), 2433 deletions(-) create mode 100644 Account/PermissionType.php delete mode 100644 DataStorage/Database/CreateMapperAbstract.php delete mode 100644 DataStorage/Database/DeleteMapperAbstract.php delete mode 100644 DataStorage/Database/ReadMapperAbstract.php delete mode 100644 DataStorage/Database/UpdateMapperAbstract.php diff --git a/Account/Account.php b/Account/Account.php index b26249b62..baed21b9f 100644 --- a/Account/Account.php +++ b/Account/Account.php @@ -109,7 +109,7 @@ class Account implements ArrayableInterface, \JsonSerializable /** * Permissions. * - * @var array + * @var PermissionAbstract[] * @since 1.0.0 */ protected $permissions = []; @@ -125,7 +125,7 @@ class Account implements ArrayableInterface, \JsonSerializable /** * Password. * - * @var Password + * @var string * @since 1.0.0 */ protected $password = ''; @@ -207,11 +207,35 @@ class Account implements ArrayableInterface, \JsonSerializable $this->l11n = $l11n; } + /** + * Set permissions. + * + * @param PermissionAbstract[] $permissions + * + * @return void + * + * @since 1.0.0 + */ public function setPermissions(array $permissions) /* : void */ { $this->permissions = $permissions; } + /** + * Has permissions. + * + * @param int $permission Check if user has this permission + * @param int $unit Unit + * @param string $app App + * @param int $module Module + * @param int $type Type (e.g. customer) + * @param int $element (e.g. customer id) + * @param int $component (e.g. address) + * + * @return bool + * + * @since 1.0.0 + */ public function hasPermission(int $permission, int $unit = null, string $app = null, int $module = null, int $type = null, $element = null, $component = null) : bool { foreach($this->permissions as $p) { diff --git a/Account/PermissionAbstract.php b/Account/PermissionAbstract.php index ee6736ea4..3cdc5824d 100644 --- a/Account/PermissionAbstract.php +++ b/Account/PermissionAbstract.php @@ -13,6 +13,7 @@ */ declare(strict_types=1); namespace phpOMS\Account; +use Modules\Admin\Models\PermissionType; /** * InfoManager class. @@ -27,110 +28,309 @@ namespace phpOMS\Account; */ abstract class PermissionAbstract { + /** + * Permission id. + * + * @var int + * @since 1.0.0 + */ protected $id = 0; + /** + * Unit id. + * + * @var int + * @since 1.0.0 + */ protected $unit = null; + /** + * App name. + * + * @var string + * @since 1.0.0 + */ protected $app = null; + /** + * Module id. + * + * @var int + * @since 1.0.0 + */ protected $module = null; + /** + * Providing module id. + * + * @var int + * @since 1.0.0 + */ protected $from = 0; + /** + * Type. + * + * @var int + * @since 1.0.0 + */ protected $type = null; + /** + * Element id. + * + * @var int + * @since 1.0.0 + */ protected $element = null; + /** + * Component id. + * + * @var int + * @since 1.0.0 + */ protected $component = null; - protected $permission = 0; + /** + * Permission. + * + * @var int + * @since 1.0.0 + */ + protected $permission = PermissionType::NONE; - public function getId() + /** + * Get permission id. + * + * @return int + * + * @since 1.0.0 + */ + public function getId() : int { - return $id; + return $this->id; } - public function getUnit() + /** + * Get unit id. + * + * @return int + * + * @since 1.0.0 + */ + public function getUnit() /* : ?int */ { return $this->unit; } - public function getApp() + /** + * Get app name. + * + * @return string + * + * @since 1.0.0 + */ + public function getApp() /* : ?string */ { return $this->app; } - public function getModule() + /** + * Get module id. + * + * @return int + * + * @since 1.0.0 + */ + public function getModule() /* : ?int */ { return $this->module; } - public function getFrom() + /** + * Get providing module id. + * + * @return int + * + * @since 1.0.0 + */ + public function getFrom() /* : ?int */ { return $this->from; } - public function getType() + /** + * Get type. + * + * @return int + * + * @since 1.0.0 + */ + public function getType() /* : ?int */ { return $this->type; } - public function getElement() + /** + * Get element id. + * + * @return int + * + * @since 1.0.0 + */ + public function getElement() /* : ?int */ { return $this->element; } - public function getComponent() + /** + * Get component id. + * + * @return int + * + * @since 1.0.0 + */ + public function getComponent() /* : ?int */ { return $this->component; } + /** + * Get permission + * + * @return int + * + * @since 1.0.0 + */ public function getPermission() : int { return $this->permission; } + /** + * Set unit id. + * + * @param int $unit Unit + * + * @return void + * + * @since 1.0.0 + */ public function setUnit(int $unit = null) /* : void */ { $this->unit = $unit; } - public function setApp(int $app = null) /* : void */ + /** + * Set app name. + * + * @param string $app App name + * + * @return void + * + * @since 1.0.0 + */ + public function setApp(string $app = null) /* : void */ { $this->app = $app; } + /** + * Set module id. + * + * @param int $module Module + * + * @return void + * + * @since 1.0.0 + */ public function setModule(int $module = null) /* : void */ { $this->module = $module; } + /** + * Set providing module id. + * + * @param int $from Providing module + * + * @return void + * + * @since 1.0.0 + */ public function setFrom(int $from = null) /* : void */ { $this->from = $from; } + /** + * Set type. + * + * @param int $type Type + * + * @return void + * + * @since 1.0.0 + */ public function setType(int $type = null) /* : void */ { $this->type = $type; } + /** + * Set element id. + * + * @param int $element Element id + * + * @return void + * + * @since 1.0.0 + */ public function setElement(int $element = null) /* : void */ { $this->element = $element; } + /** + * Set component id. + * + * @param int $component Component + * + * @return void + * + * @since 1.0.0 + */ public function setComponent(int $component = null) /* : void */ { $this->component = $component; } + /** + * Set permission. + * + * @param int $permission Permission + * + * @return void + * + * @since 1.0.0 + */ public function setPermission(int $permission = 0) /* : void */ { - if($permission === 0) { - $this->permission = 0; - } else { - $this->permission |= $permission; - } + $this->permission = $permission; + } + + /** + * Add permission. + * + * @param int $permission Permission + * + * @return void + * + * @since 1.0.0 + */ + public function addPermission(int $permission = 0) /* : void */ + { + $this->permission |= $permission; } } diff --git a/Account/PermissionType.php b/Account/PermissionType.php new file mode 100644 index 000000000..4722dd7e7 --- /dev/null +++ b/Account/PermissionType.php @@ -0,0 +1,41 @@ + + * @author Dennis Eichhorn + * @copyright Dennis Eichhorn + * @license OMS License 1.0 + * @version 1.0.0 + * @link http://orange-management.com + */ +declare(strict_types=1); + +namespace phpOMS\Account; + +use phpOMS\Stdlib\Base\Enum; + +/** + * Permission type enum. + * + * @category Framework + * @package phpOMS\DataStorage\Database + * @author OMS Development Team + * @author Dennis Eichhorn + * @license OMS License 1.0 + * @link http://orange-management.com + * @since 1.0.0 + */ +abstract class PermissionType extends Enum +{ + /* public */ const NONE = 0; + /* public */ const READ = 1; + /* public */ const CREATE = 2; + /* public */ const MODIFY = 4; + /* public */ const DELETE = 8; + /* public */ const PERMISSION = 16; +} diff --git a/Auth/Auth.php b/Auth/Auth.php index 38a80b112..c5b64706d 100644 --- a/Auth/Auth.php +++ b/Auth/Auth.php @@ -16,7 +16,6 @@ declare(strict_types=1); namespace phpOMS\Auth; use phpOMS\DataStorage\Database\Connection\ConnectionAbstract; -use phpOMS\DataStorage\Database\DatabaseType; use phpOMS\DataStorage\Session\SessionInterface; /** diff --git a/Business/Sales/MarketShareEstimation.php b/Business/Sales/MarketShareEstimation.php index 3b870bd16..268923691 100644 --- a/Business/Sales/MarketShareEstimation.php +++ b/Business/Sales/MarketShareEstimation.php @@ -32,7 +32,7 @@ class MarketShareEstimation { * @param float $marketShare (m) * @param float $modifier (s) * - * @return float + * @return int * * @since 1.0.0 */ diff --git a/DataStorage/Database/CreateMapperAbstract.php b/DataStorage/Database/CreateMapperAbstract.php deleted file mode 100644 index 01426b15c..000000000 --- a/DataStorage/Database/CreateMapperAbstract.php +++ /dev/null @@ -1,511 +0,0 @@ -prefix(self::$db->getPrefix())->into(static::$table); - - $properties = $reflectionClass->getProperties(); - - foreach ($properties as $property) { - $propertyName = $property->getName(); - - if (isset(static::$hasMany[$propertyName]) || isset(static::$hasOne[$propertyName])) { - continue; - } - - if (!($isPublic = $property->isPublic())) { - $property->setAccessible(true); - } - - foreach (static::$columns as $key => $column) { - if (isset(static::$ownsOne[$propertyName]) && $column['internal'] === $propertyName) { - $id = self::createOwnsOne($propertyName, $property->getValue($obj)); - $value = self::parseValue($column['type'], $id); - - $query->insert($column['name'])->value($value, $column['type']); - break; - } elseif (isset(static::$belongsTo[$propertyName]) && $column['internal'] === $propertyName) { - $id = self::createBelongsTo($propertyName, $property->getValue($obj)); - $value = self::parseValue($column['type'], $id); - - $query->insert($column['name'])->value($value, $column['type']); - break; - } elseif ($column['internal'] === $propertyName && $column['type'] !== static::$primaryField) { - $value = self::parseValue($column['type'], $property->getValue($obj)); - - $query->insert($column['name'])->value($value, $column['type']); - break; - } - } - - if (!($isPublic)) { - $property->setAccessible(false); - } - } - - self::$db->con->prepare($query->toSql())->execute(); - - return self::$db->con->lastInsertId(); - } - - /** - * Create base model. - * - * @param Object $obj Model to create - * - * @return mixed - * - * @since 1.0.0 - */ - private static function createModelArray($obj) - { - $query = new Builder(self::$db); - $query->prefix(self::$db->getPrefix())->into(static::$table); - - foreach ($obj as $propertyName => &$property) { - if (isset(static::$hasMany[$propertyName]) || isset(static::$hasOne[$propertyName])) { - continue; - } - - foreach (static::$columns as $key => $column) { - if (isset(static::$ownsOne[$propertyName]) && $column['internal'] === $propertyName) { - $id = self::createOwnsOneArray($propertyName, $property); - $value = self::parseValue($column['type'], $id); - - $query->insert($column['name'])->value($value, $column['type']); - break; - } elseif (isset(static::$belongsTo[$propertyName]) && $column['internal'] === $propertyName) { - $id = self::createBelongsToArray($propertyName, $property); - $value = self::parseValue($column['type'], $id); - - $query->insert($column['name'])->value($value, $column['type']); - break; - } elseif ($column['internal'] === $propertyName && $column['type'] !== static::$primaryField) { - $value = self::parseValue($column['type'], $property); - - $query->insert($column['name'])->value($value, $column['type']); - break; - } - } - } - - self::$db->con->prepare($query->toSql())->execute(); - - return self::$db->con->lastInsertId(); - } - - /** - * Create has many - * - * @param \ReflectionClass $reflectionClass Reflection class - * @param Object $obj Object to create - * @param mixed $objId Id to set - * - * @return void - * - * @throws InvalidMapperException - * - * @since 1.0.0 - */ - private static function createHasMany(\ReflectionClass $reflectionClass, $obj, $objId) /* : void */ - { - foreach (static::$hasMany as $propertyName => $rel) { - $property = $reflectionClass->getProperty($propertyName); - - if (!($isPublic = $property->isPublic())) { - $property->setAccessible(true); - } - - $values = $property->getValue($obj); - - if (!($isPublic)) { - $property->setAccessible(false); - } - - if (!isset(static::$hasMany[$propertyName]['mapper'])) { - throw new InvalidMapperException(); - } - - /** @var DataMapperAbstract $mapper */ - $mapper = static::$hasMany[$propertyName]['mapper']; - $objsIds = []; - $relReflectionClass = null; - - foreach ($values as $key => &$value) { - if (!is_object($value)) { - // Is scalar => already in database - $objsIds[$key] = $value; - - continue; - } - - if (!isset($relReflectionClass)) { - $relReflectionClass = new \ReflectionClass(get_class($value)); - } - - $primaryKey = $mapper::getObjectId($value, $relReflectionClass); - - // already in db - if (!empty($primaryKey)) { - $objsIds[$key] = $value; - - continue; - } - - // Setting relation value (id) for relation (since the relation is not stored in an extra relation table) - /** @var string $table */ - /** @var array $columns */ - if (static::$hasMany[$propertyName]['table'] === static::$hasMany[$propertyName]['mapper']::$table) { - $relProperty = $relReflectionClass->getProperty($mapper::$columns[static::$hasMany[$propertyName]['dst']]['internal']); - - if (!$isPublic) { - $relProperty->setAccessible(true); - } - - $relProperty->setValue($value, $objId); - - if (!($isPublic)) { - $relProperty->setAccessible(false); - } - } - - $objsIds[$key] = $mapper::create($value); - } - - self::createRelationTable($propertyName, $objsIds, $objId); - } - } - - /** - * Create has many - * - * @param array $obj Object to create - * @param mixed $objId Id to set - * - * @return void - * - * @throws InvalidMapperException - * - * @since 1.0.0 - */ - private static function createHasManyArray(array &$obj, $objId) /* : void */ - { - foreach (static::$hasMany as $propertyName => $rel) { - $values = $obj[$propertyName]; - - if (!isset(static::$hasMany[$propertyName]['mapper'])) { - throw new InvalidMapperException(); - } - - /** @var DataMapperAbstract $mapper */ - $mapper = static::$hasMany[$propertyName]['mapper']; - $objsIds = []; - - foreach ($values as $key => &$value) { - if (!is_object($value)) { - // Is scalar => already in database - $objsIds[$key] = $value; - - continue; - } - - $primaryKey = $obj[static::$columns[static::$primaryField]['internal']]; - - // already in db - if (!empty($primaryKey)) { - $objsIds[$key] = $value; - - continue; - } - - // Setting relation value (id) for relation (since the relation is not stored in an extra relation table) - /** @var string $table */ - /** @var array $columns */ - if (static::$hasMany[$propertyName]['table'] === static::$hasMany[$propertyName]['mapper']::$table) { - $value[$mapper::$columns[static::$hasMany[$propertyName]['dst']]['internal']] = $objId; - } - - $objsIds[$key] = $mapper::createArray($value); - } - - self::createRelationTable($propertyName, $objsIds, $objId); - } - } - - private static function createHasOne(\ReflectionClass $reflectionClass, $obj) - { - throw new \Exception(); - - foreach (static::$hasOne as $propertyName => $rel) { - - } - } - - /** - * Create owns one - * - * The reference is stored in the main model - * - * @param string $propertyName Property name to initialize - * @param Object $obj Object to create - * - * @return mixed - * - * @since 1.0.0 - */ - private static function createOwnsOne(string $propertyName, $obj) - { - if (is_object($obj)) { - $mapper = static::$ownsOne[$propertyName]['mapper']; - $primaryKey = $mapper::getObjectId($obj); - - if (empty($primaryKey)) { - return $mapper::create($obj); - } - - return $primaryKey; - } - - return $obj; - } - - /** - * Create owns one - * - * The reference is stored in the main model - * - * @param string $propertyName Property name to initialize - * @param array $obj Object to create - * - * @return mixed - * - * @since 1.0.0 - */ - private static function createOwnsOneArray(string $propertyName, array &$obj) - { - if (is_array($obj)) { - $mapper = static::$ownsOne[$propertyName]['mapper']; - $primaryKey = $obj[static::$columns[static::$primaryField]['internal']]; - - if (empty($primaryKey)) { - return $mapper::createArray($obj); - } - - return $primaryKey; - } - - return $obj; - } - - /** - * Create owns one - * - * The reference is stored in the main model - * - * @param string $propertyName Property name to initialize - * @param Object $obj Object to create - * - * @return mixed - * - * @since 1.0.0 - */ - private static function createBelongsTo(string $propertyName, $obj) - { - if (is_object($obj)) { - /** @var DataMapperAbstract $mapper */ - $mapper = static::$belongsTo[$propertyName]['mapper']; - $primaryKey = $mapper::getObjectId($obj); - - if (empty($primaryKey)) { - return $mapper::create($obj); - } - - return $primaryKey; - } - - return $obj; - } - - /** - * Create owns one - * - * The reference is stored in the main model - * - * @param string $propertyName Property name to initialize - * @param Object $obj Object to create - * - * @return mixed - * - * @since 1.0.0 - */ - private static function createBelongsToArray(string $propertyName, array $obj) - { - if (is_array($obj)) { - /** @var DataMapperAbstract $mapper */ - $mapper = static::$belongsTo[$propertyName]['mapper']; - $primaryKey = $obj[static::$columns[static::$primaryField]['internal']]; - - if (empty($primaryKey)) { - return $mapper::createArray($obj); - } - - return $primaryKey; - } - - return $obj; - } - - /** - * Create relation table entry - * - * In case of a many to many relation the relation has to be stored in a relation table - * - * @param string $propertyName Property name to initialize - * @param array $objsIds Object ids to insert - * @param mixed $objId Model to reference - * - * @return mixed - * - * @since 1.0.0 - */ - private static function createRelationTable(string $propertyName, array $objsIds, $objId) - { - /** @var string $table */ - if ( - !empty($objsIds) - && static::$hasMany[$propertyName]['table'] !== static::$table - && static::$hasMany[$propertyName]['table'] !== static::$hasMany[$propertyName]['mapper']::$table - ) { - $relQuery = new Builder(self::$db); - $relQuery->prefix(self::$db->getPrefix()) - ->into(static::$hasMany[$propertyName]['table']) - ->insert(static::$hasMany[$propertyName]['src'], static::$hasMany[$propertyName]['dst']); - - foreach ($objsIds as $key => $src) { - $relQuery->values($src, $objId); - } - - self::$db->con->prepare($relQuery->toSql())->execute(); - } - } -} diff --git a/DataStorage/Database/DataMapperAbstract.php b/DataStorage/Database/DataMapperAbstract.php index 3991f7e37..579820dce 100644 --- a/DataStorage/Database/DataMapperAbstract.php +++ b/DataStorage/Database/DataMapperAbstract.php @@ -268,7 +268,7 @@ class DataMapperAbstract implements DataMapperInterface self::$fields = $objects; - return __CLASS__; + //return __CLASS__; } /** @@ -450,7 +450,7 @@ class DataMapperAbstract implements DataMapperInterface /** * Create base model. * - * @param Object $obj Model to create + * @param array $obj Model to create * * @return mixed * @@ -580,7 +580,7 @@ class DataMapperAbstract implements DataMapperInterface throw new InvalidMapperException(); } - /** @var DataMapperAbstract $mapper */ + /** @var string $mapper */ $mapper = static::$hasMany[$propertyName]['mapper']; $objsIds = []; $relReflectionClass = null; @@ -651,7 +651,7 @@ class DataMapperAbstract implements DataMapperInterface throw new InvalidMapperException(); } - /** @var DataMapperAbstract $mapper */ + /** @var string $mapper */ $mapper = static::$hasMany[$propertyName]['mapper']; $objsIds = []; @@ -766,7 +766,7 @@ class DataMapperAbstract implements DataMapperInterface private static function createBelongsTo(string $propertyName, $obj) { if (is_object($obj)) { - /** @var DataMapperAbstract $mapper */ + /** @var string $mapper */ $mapper = static::$belongsTo[$propertyName]['mapper']; $primaryKey = $mapper::getObjectId($obj); @@ -786,7 +786,7 @@ class DataMapperAbstract implements DataMapperInterface * The reference is stored in the main model * * @param string $propertyName Property name to initialize - * @param Object $obj Object to create + * @param array $obj Object to create * * @return mixed * @@ -795,7 +795,7 @@ class DataMapperAbstract implements DataMapperInterface private static function createBelongsToArray(string $propertyName, array $obj) { if (is_array($obj)) { - /** @var DataMapperAbstract $mapper */ + /** @var string $mapper */ $mapper = static::$belongsTo[$propertyName]['mapper']; $primaryKey = $obj[static::$columns[static::$primaryField]['internal']]; @@ -912,7 +912,7 @@ class DataMapperAbstract implements DataMapperInterface throw new InvalidMapperException(); } - /** @var DataMapperAbstract $mapper */ + /** @var string $mapper */ $mapper = static::$hasMany[$propertyName]['mapper']; $objsIds = []; $relReflectionClass = null; @@ -1052,7 +1052,7 @@ class DataMapperAbstract implements DataMapperInterface private static function updateOwnsOne(string $propertyName, $obj) { if (is_object($obj)) { - /** @var DataMapperAbstract $mapper */ + /** @var string $mapper */ $mapper = static::$ownsOne[$propertyName]['mapper']; // todo: delete owned one object is not recommended since it can be owned by by something else? or does owns one mean that nothing else can have a relation to this one? @@ -1078,7 +1078,7 @@ class DataMapperAbstract implements DataMapperInterface private static function updateBelongsTo(string $propertyName, $obj) { if (is_object($obj)) { - /** @var DataMapperAbstract $mapper */ + /** @var string $mapper */ $mapper = static::$belongsTo[$propertyName]['mapper']; return $mapper::update($obj); @@ -1218,7 +1218,7 @@ class DataMapperAbstract implements DataMapperInterface throw new InvalidMapperException(); } - /** @var DataMapperAbstract $mapper */ + /** @var string $mapper */ $mapper = static::$hasMany[$propertyName]['mapper']; $objsIds = []; $relReflectionClass = null; @@ -1271,7 +1271,7 @@ class DataMapperAbstract implements DataMapperInterface private static function deleteOwnsOne(string $propertyName, $obj) { if (is_object($obj)) { - /** @var DataMapperAbstract $mapper */ + /** @var string $mapper */ $mapper = static::$ownsOne[$propertyName]['mapper']; // todo: delete owned one object is not recommended since it can be owned by by something else? or does owns one mean that nothing else can have a relation to this one? @@ -1296,7 +1296,7 @@ class DataMapperAbstract implements DataMapperInterface private static function deleteBelongsTo(string $propertyName, $obj) { if (is_object($obj)) { - /** @var DataMapperAbstract $mapper */ + /** @var string $mapper */ $mapper = static::$belongsTo[$propertyName]['mapper']; return $mapper::delete($obj); @@ -1485,7 +1485,7 @@ class DataMapperAbstract implements DataMapperInterface foreach ($result as $member => $values) { if (!empty($values) && $reflectionClass->hasProperty($member)) { - /** @var DataMapperAbstract $mapper */ + /** @var string $mapper */ $mapper = static::$hasMany[$member]['mapper']; $reflectionProperty = $reflectionClass->getProperty($member); @@ -1522,7 +1522,7 @@ class DataMapperAbstract implements DataMapperInterface { foreach ($result as $member => $values) { if (!empty($values)) { - /** @var DataMapperAbstract $mapper */ + /** @var string $mapper */ $mapper = static::$hasMany[$member]['mapper']; $values = array_diff($values, array_keys(self::$initObjects[$mapper] ?? [])); @@ -1560,10 +1560,10 @@ class DataMapperAbstract implements DataMapperInterface $reflectionProperty->setAccessible(true); } - /** @var DataMapperAbstract $mapper */ + /** @var string $mapper */ $mapper = static::$hasOne[$member]['mapper']; - if(self::isInitialized($mapper, $reflectionProperty->getValue($obj))) { + if(self::isInitialized($mapper, ($id = $reflectionProperty->getValue($obj)))) { $value = self::$initObjects[$mapper][$id]; } else { $value = $mapper::get($reflectionProperty->getValue($obj)); @@ -1592,11 +1592,11 @@ class DataMapperAbstract implements DataMapperInterface public static function populateHasOneArray(array &$obj) /* : void */ { foreach (static::$hasOne as $member => $one) { - /** @var DataMapperAbstract $mapper */ + /** @var string $mapper */ $mapper = static::$hasOne[$member]['mapper']; if(self::isInitialized($mapper, $obj['member'])) { - $value = self::$initObjects[$mapper][$id]; + $value = self::$initObjects[$mapper][$obj['member']]; } else { $value = $mapper::getArray($obj[$member]); } @@ -1629,10 +1629,10 @@ class DataMapperAbstract implements DataMapperInterface $reflectionProperty->setAccessible(true); } - /** @var DataMapperAbstract $mapper */ + /** @var string $mapper */ $mapper = static::$ownsOne[$member]['mapper']; - if(self::isInitialized($mapper, $reflectionProperty->getValue($obj))) { + if(self::isInitialized($mapper, ($id = $reflectionProperty->getValue($obj)))) { $value = self::$initObjects[$mapper][$id]; } else { $value = $mapper::get($reflectionProperty->getValue($obj)); @@ -1661,11 +1661,11 @@ class DataMapperAbstract implements DataMapperInterface public static function populateOwnsOneArray(array &$obj) /* : void */ { foreach (static::$ownsOne as $member => $one) { - /** @var DataMapperAbstract $mapper */ + /** @var string $mapper */ $mapper = static::$ownsOne[$member]['mapper']; if(self::isInitialized($mapper, $obj[$member])) { - $value = self::$initObjects[$mapper][$id]; + $value = self::$initObjects[$mapper][$obj[$member]]; } else { $value = $mapper::getArray($obj[$member]); } @@ -1698,10 +1698,10 @@ class DataMapperAbstract implements DataMapperInterface $reflectionProperty->setAccessible(true); } - /** @var DataMapperAbstract $mapper */ + /** @var string $mapper */ $mapper = static::$belongsTo[$member]['mapper']; - if(self::isInitialized($mapper, $reflectionProperty->getValue($obj))) { + if(self::isInitialized($mapper, ($id = $reflectionProperty->getValue($obj)))) { $value = self::$initObjects[$mapper][$id]; } else { $value = $mapper::get($reflectionProperty->getValue($obj)); @@ -1730,11 +1730,11 @@ class DataMapperAbstract implements DataMapperInterface public static function populateBelongsToArray(array &$obj) /* : void */ { foreach (static::$belongsTo as $member => $one) { - /** @var DataMapperAbstract $mapper */ + /** @var string $mapper */ $mapper = static::$belongsTo[$member]['mapper']; if(self::isInitialized($mapper, $obj[$member])) { - $value = self::$initObjects[$mapper][$id]; + $value = self::$initObjects[$mapper][$obj[$member]]; } else { $value = $mapper::get($obj[$member]); } @@ -1905,7 +1905,6 @@ class DataMapperAbstract implements DataMapperInterface self::extend(__CLASS__); $primaryKey = (array) $primaryKey; - $fill = (array) $fill; $obj = []; foreach ($primaryKey as $key => $value) { @@ -2550,6 +2549,17 @@ class DataMapperAbstract implements DataMapperInterface return count($results) === 0; } + /** + * Find database column name by member name + * + * @param string $name member name + * + * @return string + * + * @throws \Exception Throws this exception if the member couldn't be found + * + * @since 1.0.0 + */ private static function getColumnByMember(string $name) : string { foreach(static::$columns as $cName => $column) { diff --git a/DataStorage/Database/DatabaseExceptionFactory.php b/DataStorage/Database/DatabaseExceptionFactory.php index 7a88508d4..99565eb00 100644 --- a/DataStorage/Database/DatabaseExceptionFactory.php +++ b/DataStorage/Database/DatabaseExceptionFactory.php @@ -15,6 +15,8 @@ declare(strict_types=1); namespace phpOMS\DataStorage\Database; +use phpOMS\DataStorage\Database\Schema\Exception\TableException; + /** * Database exception factory. * diff --git a/DataStorage/Database/DatabaseStatus.php b/DataStorage/Database/DatabaseStatus.php index db73f88cb..1a1877a05 100644 --- a/DataStorage/Database/DatabaseStatus.php +++ b/DataStorage/Database/DatabaseStatus.php @@ -30,10 +30,10 @@ use phpOMS\Stdlib\Base\Enum; */ abstract class DatabaseStatus extends Enum { - /* public */ const OK = 0; /* Database connection successful */ + /* public */ const OK = 0; /* Database connection successful */ /* public */ const MISSING_DATABASE = 1; /* Couldn't find database */ - /* public */ const MISSING_TABLE = 2; /* One of the core tables couldn't be found */ - /* public */ const FAILURE = 3; /* Unknown failure */ - /* public */ const READONLY = 4; /* Database connection is in readonly (but ok) */ - /* public */ const CLOSED = 5; /* Database connection closed */ + /* public */ const MISSING_TABLE = 2; /* One of the core tables couldn't be found */ + /* public */ const FAILURE = 3; /* Unknown failure */ + /* public */ const READONLY = 4; /* Database connection is in readonly (but ok) */ + /* public */ const CLOSED = 5; /* Database connection closed */ } diff --git a/DataStorage/Database/DatabaseType.php b/DataStorage/Database/DatabaseType.php index f0ac90eb4..2de4a65c0 100644 --- a/DataStorage/Database/DatabaseType.php +++ b/DataStorage/Database/DatabaseType.php @@ -30,9 +30,9 @@ use phpOMS\Stdlib\Base\Enum; */ abstract class DatabaseType extends Enum { - /* public */ const MYSQL = 'mysql'; /* MySQL */ - /* public */ const SQLITE = 'sqlite'; /* SQLITE */ - /* public */ const PGSQL = 2; /* PostgreSQL */ - /* public */ const ORACLE = 3; /* Oracle */ - /* public */ const SQLSRV = 'mssql'; /* Microsoft SQL Server */ + /* public */ const MYSQL = 'mysql'; /* MySQL */ + /* public */ const SQLITE = 'sqlite'; /* SQLITE */ + /* public */ const PGSQL = 2; /* PostgreSQL */ + /* public */ const ORACLE = 3; /* Oracle */ + /* public */ const SQLSRV = 'mssql'; /* Microsoft SQL Server */ } diff --git a/DataStorage/Database/DeleteMapperAbstract.php b/DataStorage/Database/DeleteMapperAbstract.php deleted file mode 100644 index 7ca8fed90..000000000 --- a/DataStorage/Database/DeleteMapperAbstract.php +++ /dev/null @@ -1,295 +0,0 @@ - $rel) { - $property = $reflectionClass->getProperty($propertyName); - - if (!($isPublic = $property->isPublic())) { - $property->setAccessible(true); - } - - $values = $property->getValue($obj); - - if (!($isPublic)) { - $property->setAccessible(false); - } - - if (!isset(static::$hasMany[$propertyName]['mapper'])) { - throw new InvalidMapperException(); - } - - /** @var DataMapperAbstract $mapper */ - $mapper = static::$hasMany[$propertyName]['mapper']; - $objsIds = []; - $relReflectionClass = null; - - foreach ($values as $key => &$value) { - if (!is_object($value)) { - // Is scalar => already in database - $objsIds[$key] = $value; - - continue; - } - - if (!isset($relReflectionClass)) { - $relReflectionClass = new \ReflectionClass(get_class($value)); - } - - $primaryKey = $mapper::getObjectId($value, $relReflectionClass); - - // already in db - if (!empty($primaryKey)) { - if($relations === RelationType::ALL) { - $objsIds[$key] = $mapper::delete($value); - } else { - $objsIds[$key] = $primaryKey; - } - - continue; - } - - // todo: could be a problem, relation needs to be removed first?! - - } - - self::deleteRelationTable($propertyName, $objsIds, $objId); - } - } - - /** - * Delete owns one - * - * The reference is stored in the main model - * - * @param string $propertyName Property name to initialize - * @param Object $obj Object to delete - * - * @return mixed - * - * @since 1.0.0 - */ - private static function deleteOwnsOne(string $propertyName, $obj) - { - if (is_object($obj)) { - /** @var DataMapperAbstract $mapper */ - $mapper = static::$ownsOne[$propertyName]['mapper']; - - // todo: delete owned one object is not recommended since it can be owned by by something else? or does owns one mean that nothing else can have a relation to this one? - return $mapper::delete($obj); - } - - return $obj; - } - - /** - * Delete owns one - * - * The reference is stored in the main model - * - * @param string $propertyName Property name to initialize - * @param Object $obj Object to delete - * - * @return mixed - * - * @since 1.0.0 - */ - private static function deleteBelongsTo(string $propertyName, $obj) - { - if (is_object($obj)) { - /** @var DataMapperAbstract $mapper */ - $mapper = static::$belongsTo[$propertyName]['mapper']; - - return $mapper::delete($obj); - } - - return $obj; - } - - /** - * Delete object in db. - * - * @param Object $obj Model to delete - * @param mixed $objId Model id - * @param int $relations Delete all relations as well - * @param \ReflectionClass $reflectionClass Reflection class - * - * @return mixed - * - * @since 1.0.0 - */ - private static function deleteModel($obj, $objId, int $relations = RelationType::REFERENCE, \ReflectionClass $reflectionClass = null) /* : void */ - { - $query = new Builder(self::$db); - $query->prefix(self::$db->getPrefix()) - ->delete() - ->into(static::$table) - ->where(static::$primaryField, '=', $objId); - - $properties = $reflectionClass->getProperties(); - - if($relations === RelationType::ALL) { - foreach ($properties as $property) { - $propertyName = $property->getName(); - - if (isset(static::$hasMany[$propertyName]) || isset(static::$hasOne[$propertyName])) { - continue; - } - - if (!($isPublic = $property->isPublic())) { - $property->setAccessible(true); - } - - // todo: the order of deletion could be a problem. maybe looping through ownsOne and belongsTo first is better. - // todo: support other relation types as well (belongsto, ownsone) = for better control - - foreach (static::$columns as $key => $column) { - if ($relations === RelationType::ALL && isset(static::$ownsOne[$propertyName]) && $column['internal'] === $propertyName) { - self::deleteOwnsOne($propertyName, $property->getValue($obj)); - break; - } elseif ($relations === RelationType::ALL && isset(static::$belongsTo[$propertyName]) && $column['internal'] === $propertyName) { - self::deleteBelongsTo($propertyName, $property->getValue($obj)); - break; - } - } - - if (!($isPublic)) { - $property->setAccessible(false); - } - } - } - - self::$db->con->prepare($query->toSql())->execute(); - } - - /** - * Delete object in db. - * - * @param mixed $obj Object reference (gets filled with insert id) - * @param int $relations Create all relations as well - * - * @return mixed - * - * @since 1.0.0 - */ - public static function delete($obj, int $relations = RelationType::REFERENCE) - { - self::extend(__CLASS__); - $reflectionClass = new \ReflectionClass(get_class($obj)); - $objId = self::getObjectId($obj, $reflectionClass); - - if(empty($objId)) { - return null; - } - - if ($relations !== RelationType::NONE) { - self::deleteHasMany($reflectionClass, $obj, $objId, $relations); - } - - self::deleteModel($obj, $objId, $relations, $reflectionClass); - - return $objId; - } - - - /** - * Delete relation table entry - * - * @param string $propertyName Property name to initialize - * @param array $objsIds Object ids to insert - * @param mixed $objId Model to reference - * - * @return mixed - * - * @since 1.0.0 - */ - private static function deleteRelationTable(string $propertyName, array $objsIds, $objId) - { - /** @var string $table */ - if ( - !empty($objsIds) - && static::$hasMany[$propertyName]['table'] !== static::$table - && static::$hasMany[$propertyName]['table'] !== static::$hasMany[$propertyName]['mapper']::$table - ) { - foreach ($objsIds as $key => $src) { - $relQuery = new Builder(self::$db); - $relQuery->prefix(self::$db->getPrefix()) - ->into(static::$hasMany[$propertyName]['table']) - ->delete(); - - $relQuery->where(static::$hasMany[$propertyName]['src'], '=', $src) - ->where(static::$hasMany[$propertyName]['dst'], '=', $objId, 'and'); - - self::$db->con->prepare($relQuery->toSql())->execute(); - } - } - } - -} diff --git a/DataStorage/Database/GrammarAbstract.php b/DataStorage/Database/GrammarAbstract.php index 9140a1b6b..bd5bcc1c3 100644 --- a/DataStorage/Database/GrammarAbstract.php +++ b/DataStorage/Database/GrammarAbstract.php @@ -15,8 +15,6 @@ declare(strict_types=1); namespace phpOMS\DataStorage\Database; -use phpOMS\Utils\StringUtils; - /** * Grammar. * @@ -79,7 +77,7 @@ abstract class GrammarAbstract /** * Special keywords. * - * @var string + * @var array * @since 1.0.0 */ protected $specialKeywords = [ diff --git a/DataStorage/Database/ReadMapperAbstract.php b/DataStorage/Database/ReadMapperAbstract.php deleted file mode 100644 index ef934f57a..000000000 --- a/DataStorage/Database/ReadMapperAbstract.php +++ /dev/null @@ -1,1126 +0,0 @@ -where(static::$table . '.' . $col['name'], 'LIKE', '%' . $search . '%', 'OR'); - } - } - - return static::getAllByQuery($query); - } - - /** - * Populate data. - * - * @param array $result Result set - * - * @return array - * - * @since 1.0.0 - */ - public static function populateIterable(array $result) : array - { - $row = []; - - foreach ($result as $element) { - if (isset($element[static::$primaryField])) { - $row[$element[static::$primaryField]] = self::populate($element); - } else { - $row[] = self::populate($element); - } - } - - return $row; - } - - /** - * Populate data. - * - * @param array $result Result set - * - * @return array - * - * @since 1.0.0 - */ - public static function populateIterableArray(array $result) : array - { - $row = []; - - foreach ($result as $element) { - if (isset($element[static::$primaryField])) { - $row[$element[static::$primaryField]] = self::populateAbstractArray($element); - } else { - $row[] = self::populateAbstractArray($element); - } - } - - return $row; - } - - /** - * Populate data. - * - * @param array $result Result set - * @param mixed $obj Object to populate - * - * @return mixed - * - * @since 1.0.0 - */ - public static function populate(array $result, $obj = null) - { - $class = static::class; - $class = str_replace('Mapper', '', $class); - - if (count($result) === 0) { - $parts = explode('\\', $class); - $name = $parts[$c = (count($parts) - 1)]; - $parts[$c] = 'Null' . $name; - $class = implode('\\', $parts); - } - - if (!isset($obj)) { - $obj = new $class(); - } - - return self::populateAbstract($result, $obj); - } - - /** - * Populate data. - * - * @param array[] $result Result set - * @param mixed $obj Object to add the relations to - * - * @return void - * - * @since 1.0.0 - */ - public static function populateManyToMany(array $result, &$obj) /* : void */ - { - // todo: maybe pass reflectionClass as optional parameter for performance increase - $reflectionClass = new \ReflectionClass(get_class($obj)); - - foreach ($result as $member => $values) { - if (!empty($values) && $reflectionClass->hasProperty($member)) { - /** @var DataMapperAbstract $mapper */ - $mapper = static::$hasMany[$member]['mapper']; - $reflectionProperty = $reflectionClass->getProperty($member); - - $values = array_diff($values, array_keys(self::$initObjects[$mapper] ?? [])); - if(empty($values)) { - continue; - } - - if (!($accessible = $reflectionProperty->isPublic())) { - $reflectionProperty->setAccessible(true); - } - - $objects = $mapper::get($values); - $reflectionProperty->setValue($obj, !is_array($objects) ? [$objects] : $objects); - - if (!$accessible) { - $reflectionProperty->setAccessible(false); - } - } - } - } - - /** - * Populate data. - * - * @param array[] $result Result set - * @param array $obj Object to add the relations to - * - * @return void - * - * @since 1.0.0 - */ - public static function populateManyToManyArray(array $result, array &$obj) /* : void */ - { - foreach ($result as $member => $values) { - if (!empty($values)) { - /** @var DataMapperAbstract $mapper */ - $mapper = static::$hasMany[$member]['mapper']; - $values = array_diff($values, array_keys(self::$initObjects[$mapper] ?? [])); - if(empty($values)) { - continue; - } - - $objects = $mapper::getArray($values); - $obj[$member] = $objects; - } - } - } - - /** - * Populate data. - * - * @param mixed $obj Object to add the relations to - * - * @return void - * - * @todo accept reflection class as parameter - * - * @since 1.0.0 - */ - public static function populateHasOne(&$obj) /* : void */ - { - $reflectionClass = new \ReflectionClass(get_class($obj)); - - foreach (static::$hasOne as $member => $one) { - // todo: is that if necessary? performance is suffering for sure! - if ($reflectionClass->hasProperty($member)) { - $reflectionProperty = $reflectionClass->getProperty($member); - - if (!($accessible = $reflectionProperty->isPublic())) { - $reflectionProperty->setAccessible(true); - } - - /** @var DataMapperAbstract $mapper */ - $mapper = static::$hasOne[$member]['mapper']; - - if(self::isInitialized($mapper, $reflectionProperty->getValue($obj))) { - $value = self::$initObjects[$mapper][$id]; - } else { - $value = $mapper::get($reflectionProperty->getValue($obj)); - } - - $reflectionProperty->setValue($obj, $value); - - if (!$accessible) { - $reflectionProperty->setAccessible(false); - } - } - } - } - - /** - * Populate data. - * - * @param array $obj Object to add the relations to - * - * @return void - * - * @todo accept reflection class as parameter - * - * @since 1.0.0 - */ - public static function populateHasOneArray(array &$obj) /* : void */ - { - foreach (static::$hasOne as $member => $one) { - /** @var DataMapperAbstract $mapper */ - $mapper = static::$hasOne[$member]['mapper']; - - if(self::isInitialized($mapper, $obj['member'])) { - $value = self::$initObjects[$mapper][$id]; - } else { - $value = $mapper::getArray($obj[$member]); - } - - $obj[$member] = $value; - } - } - - /** - * Populate data. - * - * @param mixed $obj Object to add the relations to - * - * @return void - * - * @todo accept reflection class as parameter - * - * @since 1.0.0 - */ - public static function populateOwnsOne(&$obj) /* : void */ - { - $reflectionClass = new \ReflectionClass(get_class($obj)); - - foreach (static::$ownsOne as $member => $one) { - // todo: is that if necessary? performance is suffering for sure! - if ($reflectionClass->hasProperty($member)) { - $reflectionProperty = $reflectionClass->getProperty($member); - - if (!($accessible = $reflectionProperty->isPublic())) { - $reflectionProperty->setAccessible(true); - } - - /** @var DataMapperAbstract $mapper */ - $mapper = static::$ownsOne[$member]['mapper']; - - if(self::isInitialized($mapper, $reflectionProperty->getValue($obj))) { - $value = self::$initObjects[$mapper][$id]; - } else { - $value = $mapper::get($reflectionProperty->getValue($obj)); - } - - $reflectionProperty->setValue($obj, $value); - - if (!$accessible) { - $reflectionProperty->setAccessible(false); - } - } - } - } - - /** - * Populate data. - * - * @param array $obj Object to add the relations to - * - * @return void - * - * @todo accept reflection class as parameter - * - * @since 1.0.0 - */ - public static function populateOwnsOneArray(array &$obj) /* : void */ - { - foreach (static::$ownsOne as $member => $one) { - /** @var DataMapperAbstract $mapper */ - $mapper = static::$ownsOne[$member]['mapper']; - - if(self::isInitialized($mapper, $obj[$member])) { - $value = self::$initObjects[$mapper][$id]; - } else { - $value = $mapper::getArray($obj[$member]); - } - - $obj[$member] = $value; - } - } - - /** - * Populate data. - * - * @param mixed $obj Object to add the relations to - * - * @return void - * - * @todo accept reflection class as parameter - * - * @since 1.0.0 - */ - public static function populateBelongsTo(&$obj) /* : void */ - { - $reflectionClass = new \ReflectionClass(get_class($obj)); - - foreach (static::$belongsTo as $member => $one) { - // todo: is that if necessary? performance is suffering for sure! - if ($reflectionClass->hasProperty($member)) { - $reflectionProperty = $reflectionClass->getProperty($member); - - if (!($accessible = $reflectionProperty->isPublic())) { - $reflectionProperty->setAccessible(true); - } - - /** @var DataMapperAbstract $mapper */ - $mapper = static::$belongsTo[$member]['mapper']; - - if(self::isInitialized($mapper, $reflectionProperty->getValue($obj))) { - $value = self::$initObjects[$mapper][$id]; - } else { - $value = $mapper::get($reflectionProperty->getValue($obj)); - } - - $reflectionProperty->setValue($obj, $value); - - if (!$accessible) { - $reflectionProperty->setAccessible(false); - } - } - } - } - - /** - * Populate data. - * - * @param array $obj Object to add the relations to - * - * @return void - * - * @todo accept reflection class as parameter - * - * @since 1.0.0 - */ - public static function populateBelongsToArray(array &$obj) /* : void */ - { - foreach (static::$belongsTo as $member => $one) { - /** @var DataMapperAbstract $mapper */ - $mapper = static::$belongsTo[$member]['mapper']; - - if(self::isInitialized($mapper, $obj[$member])) { - $value = self::$initObjects[$mapper][$id]; - } else { - $value = $mapper::get($obj[$member]); - } - - $obj[$member] = $value; - } - } - - /** - * Populate data. - * - * @param array $result Query result set - * @param mixed $obj Object to populate - * - * @return mixed - * - * @throws \UnexpectedValueException - * - * @since 1.0.0 - */ - public static function populateAbstract(array $result, $obj) - { - $reflectionClass = new \ReflectionClass(get_class($obj)); - - foreach ($result as $column => $value) { - if (isset(static::$columns[$column]['internal']) && $reflectionClass->hasProperty(static::$columns[$column]['internal'])) { - $reflectionProperty = $reflectionClass->getProperty(static::$columns[$column]['internal']); - - if (!($accessible = $reflectionProperty->isPublic())) { - $reflectionProperty->setAccessible(true); - } - - if (in_array(static::$columns[$column]['type'], ['string', 'int', 'float', 'bool'])) { - settype($value, static::$columns[$column]['type']); - $reflectionProperty->setValue($obj, $value); - } elseif (static::$columns[$column]['type'] === 'DateTime') { - $reflectionProperty->setValue($obj, new \DateTime($value ?? '')); - } elseif (static::$columns[$column]['type'] === 'Json') { - $reflectionProperty->setValue($obj, json_decode($value, true)); - } elseif (static::$columns[$column]['type'] === 'Serializable') { - $member = $reflectionProperty->getValue($obj); - $member->unserialize($value); - } else { - throw new \UnexpectedValueException('Value "' . static::$columns[$column]['type'] . '" is not supported.'); - } - - if (!$accessible) { - $reflectionProperty->setAccessible(false); - } - } - } - - return $obj; - } - - /** - * Populate data. - * - * @param array $result Query result set - * - * @return array - * - * @throws \UnexpectedValueException - * - * @since 1.0.0 - */ - public static function populateAbstractArray(array $result) : array - { - $obj = []; - - foreach ($result as $column => $value) { - if (isset(static::$columns[$column]['internal'])) { - if (in_array(static::$columns[$column]['type'], ['string', 'int', 'float', 'bool'])) { - settype($value, static::$columns[$column]['type']); - $obj[static::$columns[$column]['internal']] = $value; - } elseif (static::$columns[$column]['type'] === 'DateTime') { - $obj[static::$columns[$column]['internal']] = new \DateTime($value ?? ''); - } elseif (static::$columns[$column]['type'] === 'Json') { - $obj[static::$columns[$column]['internal']] = json_decode($value, true); - } elseif (static::$columns[$column]['type'] === 'Serializable') { - $obj[static::$columns[$column]['internal']] = $value; - } else { - throw new \UnexpectedValueException('Value "' . static::$columns[$column]['type'] . '" is not supported.'); - } - } - } - - return $obj; - } - - /** - * Get object. - * - * @param mixed $primaryKey Key - * @param int $relations Load relations - * @param mixed $fill Object to fill - * - * @return mixed - * - * @since 1.0.0 - */ - public static function get($primaryKey, int $relations = RelationType::ALL, $fill = null) - { - if(!isset(self::$parentMapper)) { - self::setUpParentMapper(); - } - - self::extend(__CLASS__); - - $primaryKey = (array) $primaryKey; - $fill = (array) $fill; - $obj = []; - $fCount = count($fill); - $toFill = null; - - foreach ($primaryKey as $key => $value) { - if(self::isInitialized(static::class, $value)) { - continue; - } - - if ($fCount > 0) { - $toFill = current($fill); - next($fill); - } - - $obj[$value] = self::populate(self::getRaw($value), $toFill); - - if(method_exists($obj[$value], 'initialize')) { - $obj[$value]->initialize(); - } - - self::addInitialized(static::class, $value); - } - - self::fillRelations($obj, $relations); - self::clear(); - - return count($obj) === 1 ? reset($obj) : $obj; - } - - /** - * Get object. - * - * @param mixed $primaryKey Key - * @param int $relations Load relations - * - * @return mixed - * - * @since 1.0.0 - */ - public static function getArray($primaryKey, int $relations = RelationType::ALL) : array - { - if(!isset(self::$parentMapper)) { - self::setUpParentMapper(); - } - - self::extend(__CLASS__); - - $primaryKey = (array) $primaryKey; - $fill = (array) $fill; - $obj = []; - - foreach ($primaryKey as $key => $value) { - if(self::isInitialized(static::class, $value)) { - continue; - } - - $obj[$value] = self::populateAbstractArray(self::getRaw($value)); - - self::addInitialized(static::class, $value); - } - - self::fillRelationsArray($obj, $relations); - self::clear(); - - return count($obj) === 1 ? reset($obj) : $obj; - } - - /** - * Get object. - * - * @param mixed $refKey Key - * @param string $ref The field that defines the for - * @param int $relations Load relations - * @param mixed $fill Object to fill - * - * @return mixed - * - * @since 1.0.0 - */ - public static function getFor($refKey, string $ref, int $relations = RelationType::ALL, $fill = null) - { - if(!isset(self::$parentMapper)) { - self::setUpParentMapper(); - } - - self::extend(__CLASS__); - - $refKey = (array) $refKey; - $obj = []; - - foreach ($refKey as $key => $value) { - // todo: this only works for belongsTo not for many-to-many relations. Implement many-to-many - $obj[$value] = self::get(self::getPrimaryKeyBy($value, self::getColumnByMember($ref)), $relations, $fill); - } - return count($obj) === 1 ? reset($obj) : $obj; - } - - /** - * Get object. - * - * @param mixed $refKey Key - * @param string $ref The field that defines the for - * @param int $relations Load relations - * @param mixed $fill Object to fill - * - * @return mixed - * - * @since 1.0.0 - */ - public static function getForArray($refKey, string $ref, int $relations = RelationType::ALL, $fill = null) - { - if(!isset(self::$parentMapper)) { - self::setUpParentMapper(); - } - - self::extend(__CLASS__); - - $refKey = (array) $refKey; - $obj = []; - - foreach ($refKey as $key => $value) { - // todo: this only works for belongsTo not for many-to-many relations. Implement many-to-many - $obj[$value] = self::getArray(self::getPrimaryKeyBy($value, self::getColumnByMember($ref)), $relations, $fill); - } - return count($obj) === 1 ? reset($obj) : $obj; - } - - /** - * Get object. - * - * @param int $relations Load relations - * @param string $lang Language - * - * @return array - * - * @since 1.0.0 - */ - public static function getAll(int $relations = RelationType::ALL, string $lang = '') : array - { - if(!isset(self::$parentMapper)) { - self::setUpParentMapper(); - } - - $obj = self::populateIterable(self::getAllRaw($lang)); - self::fillRelations($obj, $relations); - self::clear(); - - return $obj; - } - - /** - * Get object. - * - * @param int $relations Load relations - * @param string $lang Language - * - * @return array - * - * @since 1.0.0 - */ - public static function getAllArray(int $relations = RelationType::ALL, string $lang = '') : array - { - if(!isset(self::$parentMapper)) { - self::setUpParentMapper(); - } - - $obj = self::populateIterableArray(self::getAllRaw($lang)); - self::fillRelationsArray($obj, $relations); - self::clear(); - - return $obj; - } - - /** - * Find data. - * - * @param Builder $query Query - * - * @return array - * - * @since 1.0.0 - */ - public static function listResults(Builder $query) : array - { - $sth = self::$db->con->prepare($query->toSql()); - $sth->execute(); - - return self::populateIterable($sth->fetchAll(\PDO::FETCH_ASSOC)); - } - - /** - * Get newest. - * - * This will fall back to the insert id if no datetime column is present. - * - * @param int $limit Newest limit - * @param Builder $query Pre-defined query - * @param int $relations Load relations - * @param string $lang Language - * - * @return mixed - * - * @since 1.0.0 - */ - public static function getNewest(int $limit = 1, Builder $query = null, int $relations = RelationType::ALL, string $lang = '') : array - { - self::extend(__CLASS__); - - $query = $query ?? new Builder(self::$db); - $query = self::getQuery($query); - $query->limit($limit); /* todo: limit is not working, setting this to 2 doesn't have any effect!!! */ - - if (!empty(static::$createdAt)) { - $query->orderBy(static::$table . '.' . static::$columns[static::$createdAt]['name'], 'DESC'); - } else { - $query->orderBy(static::$table . '.' . static::$columns[static::$primaryField]['name'], 'DESC'); - } - - if (!empty(self::$language_field) && !empty($lang)) { - $query->where(static::$table . '.' . static::$language_field, '=', $lang, 'AND'); - } - - $sth = self::$db->con->prepare($query->toSql()); - $sth->execute(); - - $results = $sth->fetchAll(\PDO::FETCH_ASSOC); - $obj = self::populateIterable(is_bool($results) ? [] : $results); - - self::fillRelations($obj, $relations); - self::clear(); - - return $obj; - - } - - /** - * Get all by custom query. - * - * @param Builder $query Query - * @param int $relations Relations - * - * @return array - * - * @since 1.0.0 - */ - public static function getAllByQuery(Builder $query, int $relations = RelationType::ALL) : array - { - $sth = self::$db->con->prepare($query->toSql()); - $sth->execute(); - - $results = $sth->fetchAll(\PDO::FETCH_ASSOC); - $results = is_bool($results) ? [] : $results; - - $obj = self::populateIterable($results); - self::fillRelations($obj, $relations); - self::clear(); - - return $obj; - } - - /** - * Get random object - * - * @param int $amount Amount of random models - * @param int $relations Relations type - * - * @return mixed - * - * @since 1.0.0 - */ - public static function getRandom(int $amount = 1, int $relations = RelationType::ALL) - { - $query = new Builder(self::$db); - $query->prefix(self::$db->getPrefix()) - ->random(static::$primaryField) - ->from(static::$table) - ->limit($amount); - - $sth = self::$db->con->prepare($query->toSql()); - $sth->execute(); - - return self::get($sth->fetchAll(), $relations); - } - - /** - * Fill object with relations - * - * @param mixed $obj Objects to fill - * @param int $relations Relations type - * - * @return void - * - * @since 1.0.0 - */ - public static function fillRelations(array &$obj, int $relations = RelationType::ALL) /* : void */ - { - $hasMany = !empty(static::$hasMany); - $hasOne = !empty(static::$hasOne); - $ownsOne = !empty(static::$ownsOne); - $belongsTo = !empty(static::$belongsTo); - - if ($relations !== RelationType::NONE && ($hasMany || $hasOne || $ownsOne || $belongsTo)) { - foreach ($obj as $key => $value) { - /* loading relations from relations table and populating them and then adding them to the object */ - if ($hasMany) { - self::populateManyToMany(self::getHasManyRaw($key, $relations), $obj[$key]); - } - - if ($hasOne) { - self::populateHasOne($obj[$key]); - } - - if ($ownsOne) { - self::populateOwnsOne($obj[$key]); - } - - if ($belongsTo) { - self::populateBelongsTo($obj[$key]); - } - } - } - } - - /** - * Fill object with relations - * - * @param mixed $obj Objects to fill - * @param int $relations Relations type - * - * @return void - * - * @since 1.0.0 - */ - public static function fillRelationsArray(array &$obj, int $relations = RelationType::ALL) /* : void */ - { - $hasMany = !empty(static::$hasMany); - $hasOne = !empty(static::$hasOne); - $ownsOne = !empty(static::$ownsOne); - $belongsTo = !empty(static::$belongsTo); - - if ($relations !== RelationType::NONE && ($hasMany || $hasOne || $ownsOne || $belongsTo)) { - foreach ($obj as $key => $value) { - /* loading relations from relations table and populating them and then adding them to the object */ - if ($hasMany) { - self::populateManyToManyArray(self::getHasManyRaw($key, $relations), $obj[$key]); - } - - if ($hasOne) { - self::populateHasOneArray($obj[$key]); - } - - if ($ownsOne) { - self::populateOwnsOneArray($obj[$key]); - } - - if ($belongsTo) { - self::populateBelongsToArray($obj[$key]); - } - } - } - } - - /** - * Get object. - * - * @param mixed $primaryKey Key - * - * @return mixed - * - * @since 1.0.0 - */ - public static function getRaw($primaryKey) : array - { - $query = self::getQuery(); - $query->where(static::$table . '.' . static::$primaryField, '=', $primaryKey); - - $sth = self::$db->con->prepare($query->toSql()); - $sth->execute(); - - $results = $sth->fetch(\PDO::FETCH_ASSOC); - - return is_bool($results) ? [] : $results; - } - - /** - * Get object. - * - * @param mixed $refKey Key - * @param string $ref Ref - * - * @return mixed - * - * @since 1.0.0 - */ - public static function getPrimaryKeyBy($refKey, string $ref) : array - { - $query = self::getQuery(); - $query->select(static::$primaryField) - ->from(static::$table) - ->where(static::$table . '.' . $ref, '=', $refKey); - - $sth = self::$db->con->prepare($query->toSql()); - $sth->execute(); - - $results = array_column($sth->fetchAll(\PDO::FETCH_NUM) ?? [], 0); - - return $results; - } - - /** - * Get all in raw output. - * - * @param string $lang Language - * - * @return array - * - * @since 1.0.0 - */ - public static function getAllRaw(string $lang = '') : array - { - $query = self::getQuery(); - - if (!empty(self::$language_field) && !empty($lang)) { - $query->where(static::$table . '.' . static::$language_field, '=', $lang, 'AND'); - } - - $sth = self::$db->con->prepare($query->toSql()); - $sth->execute(); - - $results = $sth->fetchAll(\PDO::FETCH_ASSOC); - - return is_bool($results) ? [] : $results; - } - - /** - * Get raw by primary key - * - * @param mixed $primaryKey Primary key - * @param int $relations Load relations - * - * @return array - * - * @since 1.0.0 - */ - public static function getHasManyRaw($primaryKey, int $relations = RelationType::ALL) : array - { - $result = []; - - foreach (static::$hasMany as $member => $value) { - $query = new Builder(self::$db); - $query->prefix(self::$db->getPrefix()); - - if ($relations === RelationType::ALL) { - /** @var string $primaryField */ - $src = $value['src'] ?? $value['mapper']::$primaryField; - - $query->select($value['table'] . '.' . $src) - ->from($value['table']) - ->where($value['table'] . '.' . $value['dst'], '=', $primaryKey); - } elseif ($relations === RelationType::NEWEST) { - - /* - SELECT c.*, p1.* - FROM customer c - JOIN purchase p1 ON (c.id = p1.customer_id) - LEFT OUTER JOIN purchase p2 ON (c.id = p2.customer_id AND - (p1.date < p2.date OR p1.date = p2.date AND p1.id < p2.id)) - WHERE p2.id IS NULL; - */ - /* - $query->select(static::$table . '.' . static::$primaryField, $value['table'] . '.' . $value['src']) - ->from(static::$table) - ->join($value['table']) - ->on(static::$table . '.' . static::$primaryField, '=', $value['table'] . '.' . $value['dst']) - ->leftOuterJoin($value['table']) - ->on(new And('1', new And(new Or('d1', 'd2'), 'id'))) - ->where($value['table'] . '.' . $value['dst'], '=', 'NULL'); - */ - } - - $sth = self::$db->con->prepare($query->toSql()); - $sth->execute(); - $result[$member] = $sth->fetchAll(\PDO::FETCH_COLUMN); - } - - return $result; - } - - /** - * Get mapper specific builder - * - * @param Builder $query Query to fill - * - * @return Builder - * - * @since 1.0.0 - */ - public static function getQuery(Builder $query = null) : Builder - { - $query = $query ?? new Builder(self::$db); - $query->prefix(self::$db->getPrefix()) - ->select('*') - ->from(static::$table); - - return $query; - } - - /** - * Get model based on request object - * - * @todo: change to graphql - * - * @param RequestAbstract $request Request object - * - * @return mixed - * - * @since 1.0.0 - */ - public static function getByRequest(RequestAbstract $request) - { - if (!is_null($request->getData('id'))) { - $result = static::get($request->getData('id')); - } elseif (!is_null($filter = $request->getData('filter'))) { - $filter = strtolower($filter); - - if ($filter === 'all') { - $result = static::getAll(); - } elseif ($filter === 'list') { - $list = $request->getData('list'); - $result = static::get(json_decode($list, true)); - } else { - $limit = (int) ($request->getData('limit') ?? 1); - $from = !is_null($request->getData('from')) ? new \DateTime($request->getData('from')) : null; - $to = !is_null($request->getData('to')) ? new \DateTime($request->getData('to')) : null; - - $query = static::getQuery(); - $query->limit($limit); - - if (isset($from, $to) && !empty(static::getCreatedAt())) { - $query->where(static::getCreatedAt(), '>=', $from); - $query->where(static::getCreatedAt(), '<=', $to); - } - - $result = static::getAllByQuery($query); - } - } else { - $class = static::class; - $class = str_replace('Mapper', '', $class); - $parts = explode('\\', $class); - $name = $parts[$c = (count($parts) - 1)]; - $parts[$c] = 'Null' . $name; - $class = implode('\\', $parts); - $result = new $class(); - } - - return $result; - } - - /** - * Add initialized object to local cache - * - * @param string $mapper Mapper name - * @param mixed $id Object id - * @param object $obj Model to cache locally - * - * @return void - * - * @since 1.0.0 - */ - private static function addInitialized(string $mapper, $id, $obj = null) /* : void */ - { - if(!isset(self::$initObjects[$mapper])) { - self::$initObjects[$mapper] = []; - } - - self::$initObjects[$mapper][$id] = $obj; - } - - /** - * Check if a object is initialized - * - * @param string $mapper Mapper name - * @param mixed $id Object id - * - * @return bool - * - * @since 1.0.0 - */ - private static function isInitialized($mapper, $id) : bool - { - return isset(self::$initObjects[$mapper]) && isset(self::$initObjects[$mapper][$id]); - } -} diff --git a/DataStorage/Database/RelationType.php b/DataStorage/Database/RelationType.php index 206e5d019..aedbcd0f4 100644 --- a/DataStorage/Database/RelationType.php +++ b/DataStorage/Database/RelationType.php @@ -30,11 +30,11 @@ use phpOMS\Stdlib\Base\Enum; */ abstract class RelationType extends Enum { - /* public */ const NONE = 0; - /* public */ const NEWEST = 1; + /* public */ const NONE = 0; + /* public */ const NEWEST = 1; /* public */ const BELONGS_TO = 2; - /* public */ const OWNS_ONE = 4; - /* public */ const HAS_MANY = 8; - /* public */ const ALL = 16; - /* public */ const REFERENCE = 32; + /* public */ const OWNS_ONE = 4; + /* public */ const HAS_MANY = 8; + /* public */ const ALL = 16; + /* public */ const REFERENCE = 32; } diff --git a/DataStorage/Database/UpdateMapperAbstract.php b/DataStorage/Database/UpdateMapperAbstract.php deleted file mode 100644 index f3cda33bb..000000000 --- a/DataStorage/Database/UpdateMapperAbstract.php +++ /dev/null @@ -1,326 +0,0 @@ - $rel) { - $property = $reflectionClass->getProperty($propertyName); - - if (!($isPublic = $property->isPublic())) { - $property->setAccessible(true); - } - - $values = $property->getValue($obj); - - if (!($isPublic)) { - $property->setAccessible(false); - } - - if (!isset(static::$hasMany[$propertyName]['mapper'])) { - throw new InvalidMapperException(); - } - - /** @var DataMapperAbstract $mapper */ - $mapper = static::$hasMany[$propertyName]['mapper']; - $objsIds = []; - $relReflectionClass = null; - - foreach ($values as $key => &$value) { - if (!is_object($value)) { - // Is scalar => already in database - $objsIds[$key] = $value; - - continue; - } - - if (!isset($relReflectionClass)) { - $relReflectionClass = new \ReflectionClass(get_class($value)); - } - - $primaryKey = $mapper::getObjectId($value, $relReflectionClass); - - // already in db - if (!empty($primaryKey)) { - $objsIds[$key] = $value; - - continue; - } - - // create if not existing - /** @var string $table */ - /** @var array $columns */ - if (static::$hasMany[$propertyName]['table'] === static::$hasMany[$propertyName]['mapper']::$table) { - $relProperty = $relReflectionClass->getProperty($mapper::$columns[static::$hasMany[$propertyName]['dst']]['internal']); - - if (!$isPublic) { - $relProperty->setAccessible(true); - } - - $relProperty->setValue($value, $objId); - - if (!($isPublic)) { - $relProperty->setAccessible(false); - } - } - - $objsIds[$key] = $mapper::create($value); - } - - self::updateRelationTable($propertyName, $objsIds, $objId); - } - } - - /** - * Update relation table entry - * - * Deletes old entries and creates new ones - * - * @param string $propertyName Property name to initialize - * @param array $objsIds Object ids to insert - * @param mixed $objId Model to reference - * - * @return mixed - * - * @throws \Exception - * - * @since 1.0.0 - */ - private static function updateRelationTable(string $propertyName, array $objsIds, $objId) - { - /** @var string $table */ - if ( - !empty($objsIds) - && static::$hasMany[$propertyName]['table'] !== static::$table - && static::$hasMany[$propertyName]['table'] !== static::$hasMany[$propertyName]['mapper']::$table - ) { - $many = self::getHasManyRaw($objId); - - foreach(static::$hasMany as $member => $value) { - // todo: definately an error here. needs testing - throw new \Exception(); - $removes = array_diff_key($many[$member], $objsIds[$member]); - $adds = array_diff_key($objsIds[$member], $many[$member]); - - if(!empty($removes)) { - self::deleteRelationTable($propertyName, $removes, $objId); - } - - if(!empty($adds)) { - self::createRelationTable($propertyName, $adds, $objId); - } - } - } - } - - /** - * Update owns one - * - * The reference is stored in the main model - * - * @param string $propertyName Property name to initialize - * @param Object $obj Object to update - * - * @return mixed - * - * @since 1.0.0 - */ - private static function updateOwnsOne(string $propertyName, $obj) - { - if (is_object($obj)) { - /** @var DataMapperAbstract $mapper */ - $mapper = static::$ownsOne[$propertyName]['mapper']; - - // todo: delete owned one object is not recommended since it can be owned by by something else? or does owns one mean that nothing else can have a relation to this one? - - return $mapper::update($obj); - } - - return $obj; - } - - /** - * Update owns one - * - * The reference is stored in the main model - * - * @param string $propertyName Property name to initialize - * @param Object $obj Object to update - * - * @return mixed - * - * @since 1.0.0 - */ - private static function updateBelongsTo(string $propertyName, $obj) - { - if (is_object($obj)) { - /** @var DataMapperAbstract $mapper */ - $mapper = static::$belongsTo[$propertyName]['mapper']; - - return $mapper::update($obj); - } - - return $obj; - } - - /** - * Update object in db. - * - * @param Object $obj Model to update - * @param mixed $objId Model id - * @param \ReflectionClass $reflectionClass Reflection class - * - * @return mixed - * - * @since 1.0.0 - */ - private static function updateModel($obj, $objId, \ReflectionClass $reflectionClass = null) /* : void */ - { - $query = new Builder(self::$db); - $query->prefix(self::$db->getPrefix()) - ->into(static::$table) - ->where(static::$primaryField, '=', $objId); - - $properties = $reflectionClass->getProperties(); - - foreach ($properties as $property) { - $propertyName = $property->getName(); - - if (isset(static::$hasMany[$propertyName]) || isset(static::$hasOne[$propertyName])) { - continue; - } - - if (!($isPublic = $property->isPublic())) { - $property->setAccessible(true); - } - - // todo: the order of updating could be a problem. maybe looping through ownsOne and belongsTo first is better. - - foreach (static::$columns as $key => $column) { - if (isset(static::$ownsOne[$propertyName]) && $column['internal'] === $propertyName) { - $id = self::updateOwnsOne($propertyName, $property->getValue($obj)); - $value = self::parseValue($column['type'], $id); - - // todo: should not be done if the id didn't change. but for now don't know if id changed - $query->update($column['name'])->value($value, $column['type']); - break; - } elseif (isset(static::$belongsTo[$propertyName]) && $column['internal'] === $propertyName) { - $id = self::updateBelongsTo($propertyName, $property->getValue($obj)); - $value = self::parseValue($column['type'], $id); - - // todo: should not be done if the id didn't change. but for now don't know if id changed - $query->update($column['name'])->value($value, $column['type']); - break; - } elseif ($column['internal'] === $propertyName && $column['type'] !== static::$primaryField) { - $value = self::parseValue($column['type'], $property->getValue($obj)); - - $query->update($column['name'])->value($value, $column['type']); - break; - } - } - - if (!($isPublic)) { - $property->setAccessible(false); - } - } - - self::$db->con->prepare($query->toSql())->execute(); - } - - /** - * Update object in db. - * - * @param mixed $obj Object reference (gets filled with insert id) - * @param int $relations Create all relations as well - * - * @return int - * - * @since 1.0.0 - */ - public static function update($obj, int $relations = RelationType::ALL) : int - { - self::extend(__CLASS__); - $reflectionClass = new \ReflectionClass(get_class($obj)); - $objId = self::getObjectId($obj, $reflectionClass); - $update = true; - - if(empty($objId)) { - $update = false; - self::create($obj, $relations); - } - - if ($relations === RelationType::ALL) { - self::updateHasMany($reflectionClass, $obj, $objId); - } - - if($update) { - self::updateModel($obj, $objId, $reflectionClass); - } - - return $objId; - } -} diff --git a/Localization/L11nManager.php b/Localization/L11nManager.php index 7d8216e4f..c4157e707 100644 --- a/Localization/L11nManager.php +++ b/Localization/L11nManager.php @@ -16,7 +16,6 @@ declare(strict_types=1); namespace phpOMS\Localization; use phpOMS\Log\FileLogger; -use phpOMS\Log\LoggerInterface; use phpOMS\Module\ModuleAbstract; /** @@ -39,24 +38,13 @@ class L11nManager */ private $language = []; - /** - * Logger. - * - * @var LoggerInterface - * @since 1.0.0 - */ - private $logger = null; - /** * Construct. * - * @param LoggerInterface $logger Logger - * * @since 1.0.0 */ - public function __construct(LoggerInterface $logger = null) + public function __construct() { - $this->logger = $logger; } /** @@ -170,16 +158,10 @@ class L11nManager $this->loadLanguage($code, $module, $class::getLocalization($code, $theme)); if (!isset($this->language[$code][$module][$translation])) { - if(isset($this->logger)) { - $this->logger->warning(FileLogger::MSG_FULL, [ - 'message' => 'Undefined translation for \'' . $code . '/' . $module . '/' . $translation . '\'.', - ]); - } - return 'ERROR'; } - } catch(\Excpetion $e) { - $this->logger->warning(FileLogger::MSG_FULL, [ + } catch(\Exception $e) { + FileLogger::getInstance()->warning(FileLogger::MSG_FULL, [ 'message' => 'Undefined translation for \'' . $code . '/' . $module . '/' . $translation . '\'.', ]); diff --git a/Log/FileLogger.php b/Log/FileLogger.php index 4a23e6319..230df4ad0 100644 --- a/Log/FileLogger.php +++ b/Log/FileLogger.php @@ -17,8 +17,6 @@ namespace phpOMS\Log; use phpOMS\Stdlib\Base\Exception\InvalidEnumValue; use phpOMS\System\File\Local\File; -use phpOMS\System\File\PathException; -use phpOMS\Utils\StringUtils; /** * Logging class. diff --git a/Math/Statistic/Forecast/Regression/RegressionAbstract.php b/Math/Statistic/Forecast/Regression/RegressionAbstract.php index b8f7cda32..8c4068702 100644 --- a/Math/Statistic/Forecast/Regression/RegressionAbstract.php +++ b/Math/Statistic/Forecast/Regression/RegressionAbstract.php @@ -12,13 +12,22 @@ * @link http://orange-management.com */ declare(strict_types=1); - namespace phpOMS\Math\Statistic\Forecast\Regression; +namespace phpOMS\Math\Statistic\Forecast\Regression; use phpOMS\Math\Statistic\Average; use phpOMS\Math\Statistic\Forecast\ForecastIntervalMultiplier; use phpOMS\Math\Statistic\MeasureOfDispersion; use phpOMS\Math\Matrix\Exception\InvalidDimensionException; +/** + * Regression abstract class. + * + * @category Framework + * @package phpOMS\Math\Statistic + * @license OMS License 1.0 + * @link http://orange-management.com + * @since 1.0.0 + */ abstract class RegressionAbstract { /** @@ -146,7 +155,35 @@ abstract class RegressionAbstract return Average::arithmeticMean($y) - $b1 * Average::arithmeticMean($x); } - abstract public static function getSlope(float $b1, float $y, float $x) : float; + /** + * Get slope + * + * @param float $b1 Beta 1 + * @param float $x Obersved x values + * @param float $y Observed y values + * + * @return float + * + * @since 1.0.0 + */ + public static function getSlope(float $b1, float $y, float $x) : float + { + return 0.0; + } - abstract public static function getElasticity(float $b1, float $y, float $x): float; + /** + * Get elasticity + * + * @param float $b1 Beta 1 + * @param float $x Obersved x values + * @param float $y Observed y values + * + * @return float + * + * @since 1.0.0 + */ + public static function getElasticity(float $b1, float $y, float $x): float + { + return 0.0; + } } \ No newline at end of file diff --git a/Math/Stochastic/NaiveBayesFilter.php b/Math/Stochastic/NaiveBayesFilter.php index 99bcee44c..e16a98450 100644 --- a/Math/Stochastic/NaiveBayesFilter.php +++ b/Math/Stochastic/NaiveBayesFilter.php @@ -49,7 +49,7 @@ class NaiveBayesFilter } } - return 1 / (1+exp(M_E, $n)); + return 1 / (1+exp($n)); } private function normalizeDictionary() : array diff --git a/Message/HeaderAbstract.php b/Message/HeaderAbstract.php index 0fd00cc2b..e3ede1c63 100644 --- a/Message/HeaderAbstract.php +++ b/Message/HeaderAbstract.php @@ -85,7 +85,7 @@ abstract class HeaderAbstract /** * Set localization * - * @param int $localization Localization + * @param Localization $l11n Localization * * @return void * @@ -135,7 +135,7 @@ abstract class HeaderAbstract public function setStatusCode(int $status) /* : void */ { $this->status = $status; - $this->header->generate($status); + $this->generate($status); } /** diff --git a/Message/Http/Header.php b/Message/Http/Header.php index f53d0a24b..a8aa9a873 100644 --- a/Message/Http/Header.php +++ b/Message/Http/Header.php @@ -16,7 +16,7 @@ declare(strict_types=1); namespace phpOMS\Message\Http; use phpOMS\Message\HeaderAbstract; -use phpOMS\DataStorage\LockExcpetion; +use phpOMS\DataStorage\LockException; /** * Response class. @@ -68,7 +68,7 @@ class Header extends HeaderAbstract public function set(string $key, string $header, bool $overwrite = false) : bool { if (self::$isLocked) { - throw new LockExcpetion('HTTP header'); + throw new LockException('HTTP header'); } $key = strtolower($key); @@ -145,18 +145,6 @@ class Header extends HeaderAbstract return self::getAllHeaders(); } - /** - * Get pushed header by name. - * - * @return string - * - * @since 1.0.0 - */ - public function getHeader(string $name) : string - { - return self::getAllHeaders()[$name] ?? ''; - } - /** * Get all headers for apache and nginx * @@ -194,7 +182,7 @@ class Header extends HeaderAbstract public function remove(int $key) : bool { if (self::$isLocked) { - throw new \LockException('HTTP header'); + throw new LockException('HTTP header'); } if (isset($this->header[$key])) { @@ -209,7 +197,7 @@ class Header extends HeaderAbstract /** * Get header by name. * - * @param int $key Header key + * @param string $key Header key * * @return array * @@ -219,19 +207,19 @@ class Header extends HeaderAbstract { return $this->header[strtolower($key)] ?? []; } - + /** * {@inheritdoc} */ public function getReasonPhrase() : string { - return $this->header->getHeader('Status'); + return $this->get('Status'); } /** * Check if header is defined. * - * @param int $key Header key + * @param string $key Header key * * @return bool * diff --git a/Message/Http/Request.php b/Message/Http/Request.php index b4ab48c72..086e2e7e3 100644 --- a/Message/Http/Request.php +++ b/Message/Http/Request.php @@ -74,10 +74,11 @@ class Request extends RequestAbstract */ public function __construct(Localization $l11n = null, UriInterface $uri = null) { - $this->l11n = $l11n; - $this->uri = $uri; - $this->source = RequestSource::WEB; $this->header = new Header(); + $this->header->setL11n($l11n); + + $this->uri = $uri; + $this->source = RequestSource::WEB; $this->init(); } @@ -110,7 +111,7 @@ class Request extends RequestAbstract * * This is used in order to either initialize the current http request or a batch of GET requests * - * @param mixed $uri URL + * @param void * * @return void * @@ -143,7 +144,7 @@ class Request extends RequestAbstract $this->uri = new Http(Http::getCurrent()); $this->data = $_GET ?? []; $this->files = $_FILES ?? []; - $this->language = $this->loadRequestLanguage(); + $this->header->getL11n()->setLanguage($this->loadRequestLanguage()); if (isset($_SERVER['CONTENT_TYPE'])) { if (strpos($_SERVER['CONTENT_TYPE'], 'application/json') !== false) { @@ -204,7 +205,7 @@ class Request extends RequestAbstract */ private function setupUriBuilder() /* : void */ { - UriFactory::setQuery('/lang', $this->l11n->getLanguage()); + UriFactory::setQuery('/lang', $this->header->getL11n()->getLanguage()); // todo: flush previous foreach($this->data as $key => $value) { @@ -212,14 +213,6 @@ class Request extends RequestAbstract } } - /** - * {@inheritdoc} - */ - public function getLanguage() : string - { - return $this->language; - } - /** * Create request hashs of current request * diff --git a/Message/Http/Response.php b/Message/Http/Response.php index 61a895671..426e569c9 100644 --- a/Message/Http/Response.php +++ b/Message/Http/Response.php @@ -50,7 +50,7 @@ class Response extends ResponseAbstract implements RenderableInterface public function __construct(Localization $l11n) { $this->header = new Header(); - $this->l11n = $l11n; + $this->header->setL11n($l11n); } /** diff --git a/Message/ResponseAbstract.php b/Message/ResponseAbstract.php index b1375f5aa..1623b5eb3 100644 --- a/Message/ResponseAbstract.php +++ b/Message/ResponseAbstract.php @@ -15,7 +15,6 @@ declare(strict_types=1); namespace phpOMS\Message; -use phpOMS\Localization\Localization; use phpOMS\Utils\ArrayUtils; /** diff --git a/Module/InstallerAbstract.php b/Module/InstallerAbstract.php index 05678fc14..8dbf6e88b 100644 --- a/Module/InstallerAbstract.php +++ b/Module/InstallerAbstract.php @@ -137,7 +137,7 @@ class InstallerAbstract /** * Init routes. * - * @param string $routePath Route Path + * @param string $modulePath Path to the module * @param InfoManager $info Module info * * @return void diff --git a/Module/ModuleManager.php b/Module/ModuleManager.php index e6235cfb9..fd508980a 100644 --- a/Module/ModuleManager.php +++ b/Module/ModuleManager.php @@ -96,6 +96,7 @@ class ModuleManager * Constructor. * * @param ApplicationAbstract $app Application + * @param string $modulePath Path to modules * * @since 1.0.0 */ diff --git a/Stdlib/Base/Iban.php b/Stdlib/Base/Iban.php index 9fc49b8b8..917cece85 100644 --- a/Stdlib/Base/Iban.php +++ b/Stdlib/Base/Iban.php @@ -25,8 +25,6 @@ use phpOMS\Validation\Finance\IbanEnum; * @license OMS License 1.0 * @link http://orange-management.com * @since 1.0.0 - * - * @todo : there is a bug with Hungary ibans since they have two k (checksums) in their definition */ class Iban implements \Serializable { diff --git a/Stdlib/Base/Location.php b/Stdlib/Base/Location.php index 38d421a78..c26de4f17 100644 --- a/Stdlib/Base/Location.php +++ b/Stdlib/Base/Location.php @@ -101,6 +101,8 @@ class Location implements \JsonSerializable, \Serializable } /** + * Get location id + * * @return int * * @since 1.0.0 @@ -111,6 +113,8 @@ class Location implements \JsonSerializable, \Serializable } /** + * Get location type + * * @return int * * @since 1.0.0 @@ -120,12 +124,23 @@ class Location implements \JsonSerializable, \Serializable return $this->type; } + /** + * Set location type + * + * @param int $type Location type + * + * @return void + * + * @since 1.0.0 + */ public function setType(int $type) /* : void */ { $this->type = $type; } /** + * Get postal or zip code + * * @return string * * @since 1.0.0 @@ -136,6 +151,8 @@ class Location implements \JsonSerializable, \Serializable } /** + * Set postal or zip code + * * @param string $postal * * @return void @@ -148,6 +165,8 @@ class Location implements \JsonSerializable, \Serializable } /** + * Get city name + * * @return string * * @since 1.0.0 @@ -158,6 +177,8 @@ class Location implements \JsonSerializable, \Serializable } /** + * Set city name + * * @param string $city * * @return void @@ -170,6 +191,8 @@ class Location implements \JsonSerializable, \Serializable } /** + * Get country code + * * @return string * * @since 1.0.0 @@ -180,6 +203,8 @@ class Location implements \JsonSerializable, \Serializable } /** + * Set country code + * * @param string $country * * @return void @@ -192,6 +217,8 @@ class Location implements \JsonSerializable, \Serializable } /** + * Get address + * * @return string * * @since 1.0.0 @@ -202,6 +229,8 @@ class Location implements \JsonSerializable, \Serializable } /** + * Set address + * * @param string $address * * @return void @@ -214,6 +243,8 @@ class Location implements \JsonSerializable, \Serializable } /** + * Get state name + * * @return string * * @since 1.0.0 @@ -224,6 +255,8 @@ class Location implements \JsonSerializable, \Serializable } /** + * Set state name + * * @param string $state * * @return void @@ -236,6 +269,8 @@ class Location implements \JsonSerializable, \Serializable } /** + * Get geo location + * * @return float[] * * @since 1.0.0 @@ -246,6 +281,8 @@ class Location implements \JsonSerializable, \Serializable } /** + * Set geo location + * * @param float[] $geo * * @return void diff --git a/Stdlib/Base/SmartDateTime.php b/Stdlib/Base/SmartDateTime.php index d11778478..bcba717e2 100644 --- a/Stdlib/Base/SmartDateTime.php +++ b/Stdlib/Base/SmartDateTime.php @@ -63,7 +63,7 @@ class SmartDateTime extends \DateTime * * @since 1.0.0 */ - public static function createFromDateTime(\Datetime $date) : SmartDateTime + public static function createFromDateTime(\DateTime $date) : SmartDateTime { return new self($date->format('Y-m-d H:i:s'), $date->getTimezone()); } @@ -192,6 +192,8 @@ class SmartDateTime extends \DateTime /** * Test year if leap year in gregorian calendar * + * @param int $year Year to check + * * @return bool * * @since 1.0.0 diff --git a/System/File/FileUtils.php b/System/File/FileUtils.php index 4819bb5b9..97f4df391 100644 --- a/System/File/FileUtils.php +++ b/System/File/FileUtils.php @@ -36,11 +36,25 @@ class FileUtils /* public */ const SPREADSHEET_EXTENSION = ['xls', 'xlsm']; /* public */ const IMAGE_EXTENSION = ['png', 'gif', 'jpg', 'jpeg', 'tiff', 'bmp']; + /** + * Constructor. + * + * @since 1.0.0 + */ private function __construct() { } + /** + * Get file extension type. + * + * @param string $extension Extension string + * + * @return int Extension type + * + * @since 1.0.0 + */ public static function getExtensionType(string $extension) : int { $extension = strtolower($extension); diff --git a/System/File/Storage.php b/System/File/Storage.php index 6807dbd39..17a4f52e8 100644 --- a/System/File/Storage.php +++ b/System/File/Storage.php @@ -73,6 +73,7 @@ final class Storage $env = __NAMESPACE__ . '\\' . $env . '\\' . $env . 'Storage'; try { + /** @var StorageAbstract $env */ $env = $env::getInstance(); self::$registered[$stg] = $env; diff --git a/System/File/StorageAbstract.php b/System/File/StorageAbstract.php index d1fb38838..1445cd7b4 100644 --- a/System/File/StorageAbstract.php +++ b/System/File/StorageAbstract.php @@ -52,7 +52,10 @@ abstract class StorageAbstract implements DirectoryInterface, FileInterface * * @since 1.0.0 */ - abstract public static function getInstance() : StorageAbstract; + public static function getInstance() : StorageAbstract + { + return null; + } /** * Get storage type. * diff --git a/UnhandledHandler.php b/UnhandledHandler.php index 414152c13..3babe913a 100644 --- a/UnhandledHandler.php +++ b/UnhandledHandler.php @@ -60,12 +60,21 @@ final class UnhandledHandler */ public static function errorHandler(int $errno, string $errstr, string $errfile, int $errline) : bool { + $logger = FileLogger::getInstance(__DIR__ . '/../Logs'); + if (!(error_reporting() & $errno)) { - // This error code is not included in error_reporting + $logger->error(FileLogger::MSG_FULL, [ + 'message' => 'Undefined error', + 'line' => $errline, + 'file' => $errfile, + ]); + + error_clear_last(); + return false; } - $logger = FileLogger::getInstance(__DIR__ . '/../Logs'); + $logger->error(FileLogger::MSG_FULL, [ 'message' => 'Unhandled error', 'line' => $errline, diff --git a/Uri/Http.php b/Uri/Http.php index b05155738..bc305030a 100644 --- a/Uri/Http.php +++ b/Uri/Http.php @@ -158,7 +158,7 @@ class Http implements UriInterface $this->path = substr($this->path, 0, -4); } - $this->path = strpos($this->path, $this->rootPath) === 0 ? substr($this->path, strlen($this->rootPath), strlen($this->path)) : $this->path; // TODO: this could cause a bug if the rootpath is the same as a regular path which is usually the language + $this->path = strpos($this->path, $this->rootPath) === 0 ? substr($this->path, strlen($this->rootPath), strlen($this->path)) : $this->path; $this->queryString = $url['query'] ?? ''; if (!empty($this->queryString)) { @@ -286,6 +286,9 @@ class Http implements UriInterface return explode('/', $this->path)[$pos]; } + /** + * {@inheritdoc} + */ public function getPathElements() : array { return explode('/', $this->path); diff --git a/Uri/UriInterface.php b/Uri/UriInterface.php index a1e980979..50617e95c 100644 --- a/Uri/UriInterface.php +++ b/Uri/UriInterface.php @@ -103,6 +103,15 @@ interface UriInterface */ public function getPathElement(int $pos) : string; + /** + * Get path elements. + * + * @return array + * + * @since 1.0.0 + */ + public function getPathElements() : array; + /** * Get query. * diff --git a/Utils/EDI/AnsiX12/FunctionalGroupHeader.php b/Utils/EDI/AnsiX12/FunctionalGroupHeader.php index 283d6405a..d5a2b585a 100644 --- a/Utils/EDI/AnsiX12/FunctionalGroupHeader.php +++ b/Utils/EDI/AnsiX12/FunctionalGroupHeader.php @@ -150,7 +150,7 @@ class FunctionalGroupHedaer public function serialize() { return $this->functionalGroupHeader . '*' - . $this->getfunctionalIdentifierCode() . '*' + . $this->getFunctionalIdentifierCode() . '*' . $this->getApplicationSenderCode() . '*' . $this->getApplicationReceiverCode() . '*' . $this->getDate() . '*' diff --git a/Utils/EDI/AnsiX12/InterchangeControlHeader.php b/Utils/EDI/AnsiX12/InterchangeControlHeader.php index a06f6c69e..fcfd74f95 100644 --- a/Utils/EDI/AnsiX12/InterchangeControlHeader.php +++ b/Utils/EDI/AnsiX12/InterchangeControlHeader.php @@ -417,7 +417,7 @@ class InterchangeControlHeader $this->setInterchangeIdQualifier((int) trim($split[5])); $this->setInterchangeSender(trim($split[6])); $this->setInterchangeReceiver(trim($split[8])); - $this->setInterchangeDateTime(new \DateTime(trim($split[9]) . '-' . trim($split[10]))); + $this->setInterchangeDatetime(new \DateTime(trim($split[9]) . '-' . trim($split[10]))); $this->setInterchangeControlStandardId(trim($split[11])); $this->setInterchangeControlVersionNumber((int) trim($split[12])); $this->setInterchangeControlNumber((int) trim($split[13])); diff --git a/Utils/Encoding/Caesar.php b/Utils/Encoding/Caesar.php index 07457d4e1..bcb44d23b 100644 --- a/Utils/Encoding/Caesar.php +++ b/Utils/Encoding/Caesar.php @@ -37,7 +37,7 @@ class Caesar /** * ASCII upper char limit. * - * @var string + * @var int * @since 1.0.0 */ /* public */ const LIMIT_UPPER = 127; diff --git a/Utils/IO/Zip/Gz.php b/Utils/IO/Zip/Gz.php index b131c0541..8dbc19300 100644 --- a/Utils/IO/Zip/Gz.php +++ b/Utils/IO/Zip/Gz.php @@ -29,7 +29,7 @@ class Gz implements ArchiveInterface /** * {@inheritdoc} */ - public static function pack(string $source, string $destination, bool $overwrite = true) : bool + public static function pack($source, string $destination, bool $overwrite = true) : bool { $destination = str_replace('\\', '/', realpath($destination)); if (!$overwrite && file_exists($destination)) { @@ -56,7 +56,7 @@ class Gz implements ArchiveInterface public static function unpack(string $source, string $destination) : bool { $destination = str_replace('\\', '/', realpath($destination)); - if (!$overwrite && file_exists($destination)) { + if (file_exists($destination)) { return false; } @@ -65,8 +65,8 @@ class Gz implements ArchiveInterface } $dest = fopen($destination, 'w'); - while (!gzeof($handle)) { - fwrite($dest, gzread($handle, 4096)); + while (!gzeof($gz)) { + fwrite($dest, gzread($gz, 4096)); } fclose($dest); diff --git a/Utils/IO/Zip/Tar.php b/Utils/IO/Zip/Tar.php index 9b92b52a4..1bbcf4890 100644 --- a/Utils/IO/Zip/Tar.php +++ b/Utils/IO/Zip/Tar.php @@ -29,7 +29,7 @@ class Tar implements ArchiveInterface /** * {@inheritdoc} */ - public static function pack(array $source, string $destination, bool $overwrite = true) : bool + public static function pack($sources, string $destination, bool $overwrite = true) : bool { $destination = str_replace('\\', '/', realpath($destination)); @@ -37,6 +37,7 @@ class Tar implements ArchiveInterface return false; } + /** @var array $sources */ foreach ($sources as $source) { $source = str_replace('\\', '/', realpath($source)); diff --git a/Utils/IO/Zip/TarGz.php b/Utils/IO/Zip/TarGz.php index 7e90813f6..dc4f2ca88 100644 --- a/Utils/IO/Zip/TarGz.php +++ b/Utils/IO/Zip/TarGz.php @@ -29,7 +29,7 @@ class TarGz implements ArchiveInterface /** * {@inheritdoc} */ - public static function pack(array $source, string $destination, bool $overwrite = true) : bool + public static function pack($source, string $destination, bool $overwrite = true) : bool { if(!Tar::pack($source, $destination . '.tmp', $overwrite)) { return false; diff --git a/Utils/IO/Zip/Zip.php b/Utils/IO/Zip/Zip.php index 17f8cfbb6..e06889b06 100644 --- a/Utils/IO/Zip/Zip.php +++ b/Utils/IO/Zip/Zip.php @@ -32,7 +32,7 @@ class Zip implements ArchiveInterface /** * {@inheritdoc} */ - public static function pack(array $sources, string $destination, bool $overwrite = true) : bool + public static function pack($sources, string $destination, bool $overwrite = true) : bool { $destination = str_replace('\\', '/', realpath($destination)); @@ -45,6 +45,7 @@ class Zip implements ArchiveInterface return false; } + /** @var array $sources */ foreach ($sources as $source) { $source = str_replace('\\', '/', realpath($source)); diff --git a/Utils/JobQueue/JobQueue.php b/Utils/JobQueue/JobQueue.php index c75c88701..0ac7b16d0 100644 --- a/Utils/JobQueue/JobQueue.php +++ b/Utils/JobQueue/JobQueue.php @@ -57,7 +57,7 @@ class JobQueue $this->runAsDeamon(); if (posix_setsid() < 0 || $pid = pcntl_fork()) { - return; + return 0; } } diff --git a/Utils/StringCompare.php b/Utils/StringCompare.php index c78fa86db..810ea64f7 100644 --- a/Utils/StringCompare.php +++ b/Utils/StringCompare.php @@ -62,7 +62,7 @@ class StringCompare $bestScore = PHP_INT_MAX; $bestMatch = ''; - foreach($dictionary as $word) { + foreach($this->dictionary as $word) { $score = self::fuzzyMatch($word, $match); if($score < $bestScore) { @@ -145,7 +145,7 @@ class StringCompare * * @param string $s1 Word 1 * @param string $s2 Word 2 - * @param float $prhaseWeight Weighting for phrase score + * @param float $phraseWeight Weighting for phrase score * @param float $wordWeight Weighting for word score * @param float $minWeight Min weight * @param float $maxWeight Max weight @@ -157,9 +157,9 @@ class StringCompare */ public static function fuzzyMatch(string $s1, string $s2, float $phraseWeight = 0.5, float $wordWeight = 1, float $minWeight = 10, float $maxWeight = 1, float $lengthWeight = -0.3) : float { - $phraseValue = valuePhrase($s1, $s2); - $wordValue = valueWords($s1, $s2); - $lengthValue = valueLength($s1, $s2); + $phraseValue = self::valuePhrase($s1, $s2); + $wordValue = self::valueWords($s1, $s2); + $lengthValue = self::valueLength($s1, $s2); return min($phraseValue * $phraseWeight, $wordValue * $wordWeight) * $minWeight + max($phraseValue * $phraseWeight, $wordValue * $wordWeight) * $maxWeight diff --git a/Utils/StringUtils.php b/Utils/StringUtils.php index dcc3a2ce7..67de10468 100644 --- a/Utils/StringUtils.php +++ b/Utils/StringUtils.php @@ -349,7 +349,7 @@ class StringUtils /** * Calculate string entropy * - * @param string $string String to analyze. + * @param string $value String to analyze. * * @return float * @@ -359,10 +359,10 @@ class StringUtils { $entroy = 0.0; $size = mb_strlen($value); - $countChars = self::mb_count_chars($value, 1); + $countChars = self::mb_count_chars($value); - foreach ($countChars as $v) { - $p = $v / $size; + for ($i = 0; $i < $countChars; $i++) { + $p = $value[$i] / $size; $entroy -= $p * log($p) / log(2); } @@ -372,13 +372,14 @@ class StringUtils /** * Count chars of utf-8 string. * - * @param string $string String to count chars. + * @param string $input String to count chars. * * @return int * * @since 1.0.0 */ - public static function mb_count_chars(string $input) { + public static function mb_count_chars(string $input) : int + { $l = mb_strlen($input, 'UTF-8'); $unique = []; diff --git a/Utils/TestUtils.php b/Utils/TestUtils.php index 2bbb4f7c5..4095bbd37 100644 --- a/Utils/TestUtils.php +++ b/Utils/TestUtils.php @@ -29,7 +29,7 @@ class TestUtils /** * Set private object member * - * @param object $object Object to modify + * @param object $obj Object to modify * @param string $name Member name to modify * @param mixed $value Value to set * @@ -63,7 +63,7 @@ class TestUtils /** * Get private object member * - * @param object $object Object to read + * @param object $obj Object to read * @param string $name Member name to read * * @return mixed Returns the member variable value diff --git a/Validation/Finance/Iban.php b/Validation/Finance/Iban.php index 9095b3b87..a7db7f591 100644 --- a/Validation/Finance/Iban.php +++ b/Validation/Finance/Iban.php @@ -39,11 +39,7 @@ abstract class Iban extends ValidatorAbstract } /** - * @param string $value Iban to validate - * - * @return bool - * - * @since 1.0.0 + * {@inheritdoc} */ public static function isValid($value, array $constraints = null) : bool { diff --git a/Validation/Network/Ip.php b/Validation/Network/Ip.php index 4a1788b9a..67cb3a2e0 100644 --- a/Validation/Network/Ip.php +++ b/Validation/Network/Ip.php @@ -46,11 +46,29 @@ class Ip extends ValidatorAbstract return filter_var($value, FILTER_VALIDATE_IP) !== false; } + /** + * Validate IPv6 + * + * @param mixed $value to validate + * + * @return bool + * + * @since 1.0.0 + */ public static function isValidIpv6($value) : bool { return filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false; } + /** + * Validate IPv4 + * + * @param mixed $value to validate + * + * @return bool + * + * @since 1.0.0 + */ public static function isValidIpv4($value) : bool { return filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false; diff --git a/Validation/ValidatorAbstract.php b/Validation/ValidatorAbstract.php index 4f4ef5d85..2258eca5c 100644 --- a/Validation/ValidatorAbstract.php +++ b/Validation/ValidatorAbstract.php @@ -59,6 +59,13 @@ abstract class ValidatorAbstract implements ValidatorInterface return self::$error; } + /** + * Reset error information + * + * @return bool + * + * @since 1.0.0 + */ public static function resetError() /* : void */ { self::$error = 0; diff --git a/Views/View.php b/Views/View.php index 678ce9b3e..f03449053 100644 --- a/Views/View.php +++ b/Views/View.php @@ -164,7 +164,7 @@ class View extends ViewAbstract * @return string * * @throws InvalidModuleException Throws this exception if no data for the defined module could be found. - * @throws InvalidTemplateException Throws this exception if no data for the defined theme could be found. + * @throws InvalidThemeException Throws this exception if no data for the defined theme could be found. * * @since 1.0.0 */ diff --git a/Views/ViewAbstract.php b/Views/ViewAbstract.php index cf962f605..93005ba94 100644 --- a/Views/ViewAbstract.php +++ b/Views/ViewAbstract.php @@ -171,7 +171,7 @@ abstract class ViewAbstract implements \Serializable * @param int $order Order of view * @param bool $overwrite Overwrite existing view * - * @return void + * @return bool * * @since 1.0.0 */ @@ -231,16 +231,16 @@ abstract class ViewAbstract implements \Serializable /** * Get view/template response. * - * @return string|array + * @param array $data Data to pass to renderer + * + * @return array|string * * @since 1.0.0 */ public function render(...$data) { - $ob = ''; - - - $path = __DIR__ . '/../..' . $this->template . '.tpl.php'; + $ob = ''; + $path = __DIR__ . '/../..' . $this->template . '.tpl.php'; if (!file_exists($path)) { throw new PathException($path); From dd57cf1fbb3936de325169ebc83873ea315cd228 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Thu, 14 Sep 2017 20:39:00 +0200 Subject: [PATCH 18/76] Simplify htmlescape --- Views/View.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Views/View.php b/Views/View.php index f03449053..c177e4308 100644 --- a/Views/View.php +++ b/Views/View.php @@ -213,6 +213,20 @@ class View extends ViewAbstract return htmlspecialchars($this->getText($translation, $module, $theme)); } + /** + * Print html output. + * + * @param string $text Text + * + * @return string + * + * @since 1.0.0 + */ + protected function printHtml(string $text) : string + { + return htmlspecialchars($text); + } + /** * @return RequestAbstract * From 721bb4d92747996bb9693a106d437c970f7394cc Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Thu, 14 Sep 2017 22:15:50 +0200 Subject: [PATCH 19/76] Add permissions to permissions --- Account/Account.php | 28 ++++++++++++++++++++++++++++ Account/PermissionAbstract.php | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Account/Account.php b/Account/Account.php index baed21b9f..97aea5982 100644 --- a/Account/Account.php +++ b/Account/Account.php @@ -221,6 +221,34 @@ class Account implements ArrayableInterface, \JsonSerializable $this->permissions = $permissions; } + /** + * Add permissions. + * + * @param PermissionAbstract[] $permissions + * + * @return void + * + * @since 1.0.0 + */ + public function addPermissions(array $permissions) /* : void */ + { + $this->permissions += $permissions; + } + + /** + * Add permission. + * + * @param PermissionAbstract $permissions + * + * @return void + * + * @since 1.0.0 + */ + public function addPermission(PermissionAbstract $permission) /* : void */ + { + $this->permissions[] = $permission; + } + /** * Has permissions. * diff --git a/Account/PermissionAbstract.php b/Account/PermissionAbstract.php index 3cdc5824d..6605bde9a 100644 --- a/Account/PermissionAbstract.php +++ b/Account/PermissionAbstract.php @@ -13,7 +13,7 @@ */ declare(strict_types=1); namespace phpOMS\Account; -use Modules\Admin\Models\PermissionType; +use phpOMS\Account\PermissionType; /** * InfoManager class. From 254a71ffb77afcf2da17f813e2fc78accf58f86f Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Fri, 15 Sep 2017 12:11:02 +0200 Subject: [PATCH 20/76] normalize permission --- Account/Account.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Account/Account.php b/Account/Account.php index 97aea5982..e5e85b2c0 100644 --- a/Account/Account.php +++ b/Account/Account.php @@ -266,6 +266,8 @@ class Account implements ArrayableInterface, \JsonSerializable */ public function hasPermission(int $permission, int $unit = null, string $app = null, int $module = null, int $type = null, $element = null, $component = null) : bool { + $app = isset($app) ? strtolower($app) : $app; + foreach($this->permissions as $p) { if(($p->getUnit() === $unit || $p->getUnit() === null) && ($p->getApp() === $app || $p->getApp() === null) From 1100e7c532743d4a44dd301196777e69c8091be7 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Fri, 15 Sep 2017 19:09:27 +0200 Subject: [PATCH 21/76] Add module id to abstract --- Module/ModuleAbstract.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Module/ModuleAbstract.php b/Module/ModuleAbstract.php index fe2823a85..787d3ef47 100644 --- a/Module/ModuleAbstract.php +++ b/Module/ModuleAbstract.php @@ -34,6 +34,7 @@ abstract class ModuleAbstract * @since 1.0.0 */ /* public */ const MODULE_NAME = ''; + /** * Module path. * @@ -41,6 +42,7 @@ abstract class ModuleAbstract * @since 1.0.0 */ /* public */ const MODULE_PATH = __DIR__ . '/../../Modules'; + /** * Module version. * @@ -48,6 +50,15 @@ abstract class ModuleAbstract * @since 1.0.0 */ /* public */ const MODULE_VERSION = '1.0.0'; + + /** + * Module id. + * + * @var string + * @since 1.0.0 + */ + /* public */ const MODULE_ID = 0; + /** * Receiving modules from? * From b9d2e9bb56d3057ba7d7a7f1d3c316db679306cd Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Sat, 16 Sep 2017 20:24:39 +0200 Subject: [PATCH 22/76] Fix types --- Utils/StringUtils.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Utils/StringUtils.php b/Utils/StringUtils.php index 67de10468..c9e1cdc6f 100644 --- a/Utils/StringUtils.php +++ b/Utils/StringUtils.php @@ -361,8 +361,8 @@ class StringUtils $size = mb_strlen($value); $countChars = self::mb_count_chars($value); - for ($i = 0; $i < $countChars; $i++) { - $p = $value[$i] / $size; + foreach ($countChars as $v) { + $p = $v / $size; $entroy -= $p * log($p) / log(2); } @@ -374,11 +374,11 @@ class StringUtils * * @param string $input String to count chars. * - * @return int + * @return array * * @since 1.0.0 */ - public static function mb_count_chars(string $input) : int + public static function mb_count_chars(string $input) : array { $l = mb_strlen($input, 'UTF-8'); $unique = []; From b424eb67bf0b93c03e36f01b184c1fe407139bac Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Sat, 16 Sep 2017 20:24:47 +0200 Subject: [PATCH 23/76] fix case --- Localization/Localization.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Localization/Localization.php b/Localization/Localization.php index 4fd894cd3..3982f65a4 100644 --- a/Localization/Localization.php +++ b/Localization/Localization.php @@ -220,6 +220,8 @@ class Localization */ public function setLanguage(string $language) /* : void */ { + $language = strtolower($language); + if (!ISO639x1Enum::isValidValue($language)) { throw new InvalidEnumValue($language); } From d48d65fe86a48ea812394c3d2a683c917d4a97e4 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Mon, 18 Sep 2017 18:36:34 +0200 Subject: [PATCH 24/76] Optimize order --- Account/Group.php | 24 ++--- Account/PermissionAbstract.php | 170 ++++++++++++++++----------------- 2 files changed, 97 insertions(+), 97 deletions(-) diff --git a/Account/Group.php b/Account/Group.php index fde961c6a..46f58c16d 100644 --- a/Account/Group.php +++ b/Account/Group.php @@ -191,18 +191,6 @@ class Group implements ArrayableInterface, \JsonSerializable return json_encode($this->toArray()); } - /** - * Json serialize. - * - * @return string - * - * @since 1.0.0 - */ - public function jsonSerialize() - { - return $this->toArray(); - } - /** * {@inheritdoc} */ @@ -216,4 +204,16 @@ class Group implements ArrayableInterface, \JsonSerializable 'members' => $this->members, ]; } + + /** + * Json serialize. + * + * @return string + * + * @since 1.0.0 + */ + public function jsonSerialize() + { + return $this->toArray(); + } } diff --git a/Account/PermissionAbstract.php b/Account/PermissionAbstract.php index 6605bde9a..e97f54fe4 100644 --- a/Account/PermissionAbstract.php +++ b/Account/PermissionAbstract.php @@ -12,8 +12,8 @@ * @link http://orange-management.com */ declare(strict_types=1); + namespace phpOMS\Account; -use phpOMS\Account\PermissionType; /** * InfoManager class. @@ -124,90 +124,6 @@ abstract class PermissionAbstract return $this->unit; } - /** - * Get app name. - * - * @return string - * - * @since 1.0.0 - */ - public function getApp() /* : ?string */ - { - return $this->app; - } - - /** - * Get module id. - * - * @return int - * - * @since 1.0.0 - */ - public function getModule() /* : ?int */ - { - return $this->module; - } - - /** - * Get providing module id. - * - * @return int - * - * @since 1.0.0 - */ - public function getFrom() /* : ?int */ - { - return $this->from; - } - - /** - * Get type. - * - * @return int - * - * @since 1.0.0 - */ - public function getType() /* : ?int */ - { - return $this->type; - } - - /** - * Get element id. - * - * @return int - * - * @since 1.0.0 - */ - public function getElement() /* : ?int */ - { - return $this->element; - } - - /** - * Get component id. - * - * @return int - * - * @since 1.0.0 - */ - public function getComponent() /* : ?int */ - { - return $this->component; - } - - /** - * Get permission - * - * @return int - * - * @since 1.0.0 - */ - public function getPermission() : int - { - return $this->permission; - } - /** * Set unit id. * @@ -222,6 +138,18 @@ abstract class PermissionAbstract $this->unit = $unit; } + /** + * Get app name. + * + * @return string + * + * @since 1.0.0 + */ + public function getApp() /* : ?string */ + { + return $this->app; + } + /** * Set app name. * @@ -236,6 +164,18 @@ abstract class PermissionAbstract $this->app = $app; } + /** + * Get module id. + * + * @return int + * + * @since 1.0.0 + */ + public function getModule() /* : ?int */ + { + return $this->module; + } + /** * Set module id. * @@ -250,6 +190,18 @@ abstract class PermissionAbstract $this->module = $module; } + /** + * Get providing module id. + * + * @return int + * + * @since 1.0.0 + */ + public function getFrom() /* : ?int */ + { + return $this->from; + } + /** * Set providing module id. * @@ -264,6 +216,18 @@ abstract class PermissionAbstract $this->from = $from; } + /** + * Get type. + * + * @return int + * + * @since 1.0.0 + */ + public function getType() /* : ?int */ + { + return $this->type; + } + /** * Set type. * @@ -278,6 +242,18 @@ abstract class PermissionAbstract $this->type = $type; } + /** + * Get element id. + * + * @return int + * + * @since 1.0.0 + */ + public function getElement() /* : ?int */ + { + return $this->element; + } + /** * Set element id. * @@ -292,6 +268,18 @@ abstract class PermissionAbstract $this->element = $element; } + /** + * Get component id. + * + * @return int + * + * @since 1.0.0 + */ + public function getComponent() /* : ?int */ + { + return $this->component; + } + /** * Set component id. * @@ -306,6 +294,18 @@ abstract class PermissionAbstract $this->component = $component; } + /** + * Get permission + * + * @return int + * + * @since 1.0.0 + */ + public function getPermission() : int + { + return $this->permission; + } + /** * Set permission. * From 16a0b79cc209c518e651e94a6771e71e88ba2fb6 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Mon, 18 Sep 2017 18:36:40 +0200 Subject: [PATCH 25/76] Optimize order --- Account/Account.php | 218 ++++++++++++++++++++++---------------------- 1 file changed, 109 insertions(+), 109 deletions(-) diff --git a/Account/Account.php b/Account/Account.php index e5e85b2c0..d348e4373 100644 --- a/Account/Account.php +++ b/Account/Account.php @@ -238,7 +238,7 @@ class Account implements ArrayableInterface, \JsonSerializable /** * Add permission. * - * @param PermissionAbstract $permissions + * @param PermissionAbstract $permission * * @return void * @@ -307,6 +307,20 @@ class Account implements ArrayableInterface, \JsonSerializable return $this->name1; } + /** + * Set name1. + * + * @param string $name Name + * + * @return void + * + * @since 1.0.0 + */ + public function setName1(string $name) /* : void */ + { + $this->name1 = $name; + } + /** * Get name2. * @@ -319,6 +333,20 @@ class Account implements ArrayableInterface, \JsonSerializable return $this->name2; } + /** + * Set name2. + * + * @param string $name Name + * + * @return void + * + * @since 1.0.0 + */ + public function setName2(string $name) /* : void */ + { + $this->name2 = $name; + } + /** * Get name3. * @@ -331,6 +359,20 @@ class Account implements ArrayableInterface, \JsonSerializable return $this->name3; } + /** + * Set name3. + * + * @param string $name Name + * + * @return void + * + * @since 1.0.0 + */ + public function setName3(string $name) /* : void */ + { + $this->name3 = $name; + } + /** * Get email. * @@ -343,6 +385,24 @@ class Account implements ArrayableInterface, \JsonSerializable return $this->email; } + /** + * Set email. + * + * @param string $email Email + * + * @return void + * + * @since 1.0.0 + */ + public function setEmail(string $email) /* : void */ + { + if (!Email::isValid($email)) { + throw new \InvalidArgumentException(); + } + + $this->email = mb_strtolower($email); + } + /** * Get status. * @@ -357,6 +417,24 @@ class Account implements ArrayableInterface, \JsonSerializable return $this->status; } + /** + * Get status. + * + * @param int $status Status + * + * @return void + * + * @since 1.0.0 + */ + public function setStatus(int $status) /* : void */ + { + if (!AccountStatus::isValidValue($status)) { + throw new \InvalidArgumentException(); + } + + $this->status = $status; + } + /** * Get type. * @@ -371,6 +449,24 @@ class Account implements ArrayableInterface, \JsonSerializable return $this->type; } + /** + * Get type. + * + * @param int $type Type + * + * @return void + * + * @since 1.0.0 + */ + public function setType(int $type) /* : void */ + { + if (!AccountType::isValidValue($type)) { + throw new \InvalidArgumentException(); + } + + $this->type = $type; + } + /** * Get last activity. * @@ -423,102 +519,6 @@ class Account implements ArrayableInterface, \JsonSerializable $this->login = $name; } - /** - * Set name1. - * - * @param string $name Name - * - * @return void - * - * @since 1.0.0 - */ - public function setName1(string $name) /* : void */ - { - $this->name1 = $name; - } - - /** - * Set name2. - * - * @param string $name Name - * - * @return void - * - * @since 1.0.0 - */ - public function setName2(string $name) /* : void */ - { - $this->name2 = $name; - } - - /** - * Set name3. - * - * @param string $name Name - * - * @return void - * - * @since 1.0.0 - */ - public function setName3(string $name) /* : void */ - { - $this->name3 = $name; - } - - /** - * Set email. - * - * @param string $email Email - * - * @return void - * - * @since 1.0.0 - */ - public function setEmail(string $email) /* : void */ - { - if (!Email::isValid($email)) { - throw new \InvalidArgumentException(); - } - - $this->email = mb_strtolower($email); - } - - /** - * Get status. - * - * @param int $status Status - * - * @return void - * - * @since 1.0.0 - */ - public function setStatus(int $status) /* : void */ - { - if (!AccountStatus::isValidValue($status)) { - throw new \InvalidArgumentException(); - } - - $this->status = $status; - } - - /** - * Get type. - * - * @param int $type Type - * - * @return void - * - * @since 1.0.0 - */ - public function setType(int $type) /* : void */ - { - if (!AccountType::isValidValue($type)) { - throw new \InvalidArgumentException(); - } - - $this->type = $type; - } - /** * Update last activity. * @@ -531,6 +531,18 @@ class Account implements ArrayableInterface, \JsonSerializable $this->lastActive = new \DateTime('NOW'); } + /** + * Get string representation. + * + * @return string + * + * @since 1.0.0 + */ + public function __toString() + { + return json_encode($this->toArray()); + } + /** * {@inheritdoc} */ @@ -552,18 +564,6 @@ class Account implements ArrayableInterface, \JsonSerializable ]; } - /** - * Get string representation. - * - * @return string - * - * @since 1.0.0 - */ - public function __toString() - { - return json_encode($this->toArray()); - } - /** * Json serialize. * From 57a93bd60a5b3798d32256ecd93d83346070d35b Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Mon, 18 Sep 2017 18:39:21 +0200 Subject: [PATCH 26/76] Optimize code order --- Module/ModuleFactory.php | 1 - Module/ModuleManager.php | 293 +++++++++++++++++++-------------------- 2 files changed, 146 insertions(+), 148 deletions(-) diff --git a/Module/ModuleFactory.php b/Module/ModuleFactory.php index 9858338db..b1c02902f 100644 --- a/Module/ModuleFactory.php +++ b/Module/ModuleFactory.php @@ -16,7 +16,6 @@ declare(strict_types=1); namespace phpOMS\Module; use phpOMS\ApplicationAbstract; -use phpOMS\Autoloader; /** * ModuleFactory class. diff --git a/Module/ModuleManager.php b/Module/ModuleManager.php index fd508980a..76cfa6700 100644 --- a/Module/ModuleManager.php +++ b/Module/ModuleManager.php @@ -16,7 +16,6 @@ declare(strict_types=1); namespace phpOMS\Module; use phpOMS\ApplicationAbstract; -use phpOMS\Autoloader; use phpOMS\DataStorage\Database\DatabaseType; use phpOMS\Message\Http\Request; use phpOMS\System\File\PathException; @@ -107,7 +106,7 @@ class ModuleManager } /** - * Get modules that run on this page. + * Get language files. * * @param Request $request Request * @@ -115,18 +114,18 @@ class ModuleManager * * @since 1.0.0 */ - public function getRoutedModules(Request $request) : array + public function getLanguageFiles(Request $request) : array { - $files = $this->getUriLoad($request); - $modules = []; + $files = $this->getUriLoad($request); - if (isset($files[4])) { - foreach ($files[4] as $module) { - $modules[] = $module['module_load_file']; + $lang = []; + if (isset($files[5])) { + foreach ($files[5] as $module) { + $lang[] = '/Modules/' . $module['module_load_from'] . '/Theme/' . $this->app->appName . '/Lang/' . $module['module_load_file']; } } - return $modules; + return $lang; } /** @@ -181,29 +180,6 @@ class ModuleManager return $this->uriLoad; } - /** - * Get language files. - * - * @param Request $request Request - * - * @return array - * - * @since 1.0.0 - */ - public function getLanguageFiles(Request $request) : array - { - $files = $this->getUriLoad($request); - - $lang = []; - if (isset($files[5])) { - foreach ($files[5] as $module) { - $lang[] = '/Modules/' . $module['module_load_from'] . '/Theme/' . $this->app->appName . '/Lang/' . $module['module_load_file']; - } - } - - return $lang; - } - /** * Get all installed modules that are active (not just on this uri). * @@ -302,6 +278,74 @@ class ModuleManager } } + /** + * Get all installed modules. + * + * @return array + * + * @since 1.0.0 + */ + public function getInstalledModules() : array + { + if ($this->installed === null) { + switch ($this->app->dbPool->get('core')->getType()) { + case DatabaseType::MYSQL: + $sth = $this->app->dbPool->get('core')->con->prepare('SELECT `module_id`,`module_theme`,`module_version` FROM `' . $this->app->dbPool->get('core')->prefix . 'module`'); + $sth->execute(); + $this->installed = $sth->fetchAll(\PDO::FETCH_GROUP); + break; + } + } + + return $this->installed; + } + + /** + * Load info of module. + * + * @param string $module Module name + * + * @return InfoManager + * + * @since 1.0.0 + */ + private function loadInfo(string $module) : InfoManager + { + $path = realpath($oldPath = $this->modulePath . '/' . $module . '/' . 'info.json'); + + if ($path === false) { + throw new PathException($oldPath); + } + + $info = new InfoManager($path); + $info->load(); + + return $info; + } + + /** + * Deactivate module. + * + * @param InfoManager $info Module info + * + * @return void + * + * @throws InvalidModuleException Throws this exception in case the deactiviation doesn't exist + * + * @since 1.0.0 + */ + private function deactivateModule(InfoManager $info) /* : void */ + { + $class = '\\Modules\\' . $info->getDirectory() . '\\Admin\\Deactivate'; + + if (!Autoloader::exists($class)) { + throw new InvalidModuleException($info->getDirectory()); + } + + /** @var $class DeactivateAbstract */ + $class::deactivate($this->app->dbPool, $info); + } + /** * Deactivate module. * @@ -337,6 +381,29 @@ class ModuleManager } } + /** + * Activate module. + * + * @param InfoManager $info Module info + * + * @return void + * + * @throws InvalidModuleException Throws this exception in case the activation doesn't exist + * + * @since 1.0.0 + */ + private function activateModule(InfoManager $info) /* : void */ + { + $class = '\\Modules\\' . $info->getDirectory() . '\\Admin\\Activate'; + + if (!Autoloader::exists($class)) { + throw new InvalidModuleException($info->getDirectory()); + } + + /** @var $class ActivateAbstract */ + $class::activate($this->app->dbPool, $info); + } + /** * Re-init module. * @@ -453,97 +520,6 @@ class ModuleManager $class::install($this->modulePath, $this->app->dbPool, $info); } - /** - * Deactivate module. - * - * @param InfoManager $info Module info - * - * @return void - * - * @throws InvalidModuleException Throws this exception in case the deactiviation doesn't exist - * - * @since 1.0.0 - */ - private function deactivateModule(InfoManager $info) /* : void */ - { - $class = '\\Modules\\' . $info->getDirectory() . '\\Admin\\Deactivate'; - - if (!Autoloader::exists($class)) { - throw new InvalidModuleException($info->getDirectory()); - } - - /** @var $class DeactivateAbstract */ - $class::deactivate($this->app->dbPool, $info); - } - - /** - * Activate module. - * - * @param InfoManager $info Module info - * - * @return void - * - * @throws InvalidModuleException Throws this exception in case the activation doesn't exist - * - * @since 1.0.0 - */ - private function activateModule(InfoManager $info) /* : void */ - { - $class = '\\Modules\\' . $info->getDirectory() . '\\Admin\\Activate'; - - if (!Autoloader::exists($class)) { - throw new InvalidModuleException($info->getDirectory()); - } - - /** @var $class ActivateAbstract */ - $class::activate($this->app->dbPool, $info); - } - - /** - * Load info of module. - * - * @param string $module Module name - * - * @return InfoManager - * - * @since 1.0.0 - */ - private function loadInfo(string $module) : InfoManager - { - $path = realpath($oldPath = $this->modulePath . '/' . $module . '/' . 'info.json'); - - if ($path === false) { - throw new PathException($oldPath); - } - - $info = new InfoManager($path); - $info->load(); - - return $info; - } - - /** - * Get all installed modules. - * - * @return array - * - * @since 1.0.0 - */ - public function getInstalledModules() : array - { - if ($this->installed === null) { - switch ($this->app->dbPool->get('core')->getType()) { - case DatabaseType::MYSQL: - $sth = $this->app->dbPool->get('core')->con->prepare('SELECT `module_id`,`module_theme`,`module_version` FROM `' . $this->app->dbPool->get('core')->prefix . 'module`'); - $sth->execute(); - $this->installed = $sth->fetchAll(\PDO::FETCH_GROUP); - break; - } - } - - return $this->installed; - } - /** * Install providing. * @@ -565,6 +541,30 @@ class ModuleManager } } + /** + * Get module instance. + * + * @param string $module Module name + * + * @return \phpOMS\Module\ModuleAbstract + * + * @throws \Exception + * + * @since 1.0.0 + */ + public function get(string $module) : ModuleAbstract + { + try { + if (!isset($this->running[$module])) { + $this->initModule($module); + } + + return $this->running[$module]; + } catch (\Exception $e) { + throw $e; + } + } + /** * Initialize module. * @@ -612,30 +612,6 @@ class ModuleManager } } - /** - * Get module instance. - * - * @param string $module Module name - * - * @return \phpOMS\Module\ModuleAbstract - * - * @throws \Exception - * - * @since 1.0.0 - */ - public function get(string $module) : ModuleAbstract - { - try { - if (!isset($this->running[$module])) { - $this->initModule($module); - } - - return $this->running[$module]; - } catch (\Exception $e) { - throw $e; - } - } - /** * Initialize all modules for a request. * @@ -653,4 +629,27 @@ class ModuleManager $this->initModuleController($module); } } + + /** + * Get modules that run on this page. + * + * @param Request $request Request + * + * @return array + * + * @since 1.0.0 + */ + public function getRoutedModules(Request $request) : array + { + $files = $this->getUriLoad($request); + $modules = []; + + if (isset($files[4])) { + foreach ($files[4] as $module) { + $modules[] = $module['module_load_file']; + } + } + + return $modules; + } } From 417a42b455f388fe0ec35835b1d958f86294f317 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Mon, 18 Sep 2017 18:46:23 +0200 Subject: [PATCH 27/76] Optimize code order --- Message/HeaderAbstract.php | 69 +++++++++++++++++++------------------- Message/Http/Header.php | 48 +++++++++++++------------- Message/Http/Request.php | 46 ++++++++++++------------- Uri/Http.php | 28 ++++++++-------- 4 files changed, 95 insertions(+), 96 deletions(-) diff --git a/Message/HeaderAbstract.php b/Message/HeaderAbstract.php index e3ede1c63..dc7881e8b 100644 --- a/Message/HeaderAbstract.php +++ b/Message/HeaderAbstract.php @@ -70,6 +70,29 @@ abstract class HeaderAbstract $this->l11n = new Localization(); } + /** + * Set header locked. + * + * @since 1.0.0 + */ + public static function lock() /* : void */ + { + // todo: maybe pass session as member and make lock not static + self::$isLocked = true; + } + + /** + * Is header locked? + * + * @return bool + * + * @since 1.0.0 + */ + public static function isLocked() : bool + { + return self::$isLocked; + } + /** * Get Localization * @@ -81,7 +104,7 @@ abstract class HeaderAbstract { return $this->l11n; } - + /** * Set localization * @@ -121,7 +144,6 @@ abstract class HeaderAbstract { $this->account = $account; } - /** * Set status code @@ -138,6 +160,15 @@ abstract class HeaderAbstract $this->generate($status); } + /** + * Generate header based on status code. + * + * @param int $statusCode Status code + * + * @since 1.0.0 + */ + abstract public function generate(int $statusCode) /* : void */; + /** * Get status code * @@ -149,7 +180,7 @@ abstract class HeaderAbstract { return $this->status; } - + /** * Get protocol version. * @@ -170,15 +201,6 @@ abstract class HeaderAbstract */ abstract public function set(string $key, string $value, bool $overwrite = false); - /** - * Generate header based on status code. - * - * @param int $statusCode Status code - * - * @since 1.0.0 - */ - abstract public function generate(int $statusCode) /* : void */; - /** * Get header by key. * @@ -200,27 +222,4 @@ abstract class HeaderAbstract * @since 1.0.0 */ abstract public function has(string $key) : bool; - - /** - * Set header locked. - * - * @since 1.0.0 - */ - public static function lock() /* : void */ - { - // todo: maybe pass session as member and make lock not static - self::$isLocked = true; - } - - /** - * Is header locked? - * - * @return bool - * - * @since 1.0.0 - */ - public static function isLocked() : bool - { - return self::$isLocked; - } } diff --git a/Message/Http/Header.php b/Message/Http/Header.php index a8aa9a873..fb71aec8b 100644 --- a/Message/Http/Header.php +++ b/Message/Http/Header.php @@ -92,14 +92,6 @@ class Header extends HeaderAbstract return true; } - /** - * {@inheritdoc} - */ - public function getProtocolVersion() : string - { - return $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.1'; - } - /** * Is security header. * @@ -117,6 +109,14 @@ class Header extends HeaderAbstract || $key === 'x-frame-options'; } + /** + * {@inheritdoc} + */ + public function getProtocolVersion() : string + { + return $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.1'; + } + /** * Get status code. * @@ -194,6 +194,14 @@ class Header extends HeaderAbstract return false; } + /** + * {@inheritdoc} + */ + public function getReasonPhrase() : string + { + return $this->get('Status'); + } + /** * Get header by name. * @@ -208,14 +216,6 @@ class Header extends HeaderAbstract return $this->header[strtolower($key)] ?? []; } - /** - * {@inheritdoc} - */ - public function getReasonPhrase() : string - { - return $this->get('Status'); - } - /** * Check if header is defined. * @@ -339,12 +339,12 @@ class Header extends HeaderAbstract * * @since 1.0.0 */ - private function generate500() /* : void */ + private function generate503() /* : void */ { - $this->set('HTTP', 'HTTP/1.0 500 Internal Server Error'); - $this->set('Status', 'Status: 500 Internal Server Error'); + $this->set('HTTP', 'HTTP/1.0 503 Service Temporarily Unavailable'); + $this->set('Status', 'Status: 503 Service Temporarily Unavailable'); $this->set('Retry-After', 'Retry-After: 300'); - \http_response_code(500); + \http_response_code(503); } /** @@ -354,11 +354,11 @@ class Header extends HeaderAbstract * * @since 1.0.0 */ - private function generate503() /* : void */ + private function generate500() /* : void */ { - $this->set('HTTP', 'HTTP/1.0 503 Service Temporarily Unavailable'); - $this->set('Status', 'Status: 503 Service Temporarily Unavailable'); + $this->set('HTTP', 'HTTP/1.0 500 Internal Server Error'); + $this->set('Status', 'Status: 500 Internal Server Error'); $this->set('Retry-After', 'Retry-After: 300'); - \http_response_code(503); + \http_response_code(500); } } diff --git a/Message/Http/Request.php b/Message/Http/Request.php index 086e2e7e3..a86dd49df 100644 --- a/Message/Http/Request.php +++ b/Message/Http/Request.php @@ -83,29 +83,6 @@ class Request extends RequestAbstract $this->init(); } - /** - * Create request from super globals. - * - * @param Localization $l11n Localization - * - * @return Request - * - * @since 1.0.0 - */ - public static function createFromSuperglobals(Localization $l11n = null) : Request - { - return new self($l11n); - } - - /** - * {@inheritdoc} - */ - public function setUri(UriInterface $uri) /* : void */ - { - $this->uri = $uri; - $this->data += $uri->getQueryArray(); - } - /** * Init request. * @@ -213,6 +190,29 @@ class Request extends RequestAbstract } } + /** + * Create request from super globals. + * + * @param Localization $l11n Localization + * + * @return Request + * + * @since 1.0.0 + */ + public static function createFromSuperglobals(Localization $l11n = null) : Request + { + return new self($l11n); + } + + /** + * {@inheritdoc} + */ + public function setUri(UriInterface $uri) /* : void */ + { + $this->uri = $uri; + $this->data += $uri->getQueryArray(); + } + /** * Create request hashs of current request * diff --git a/Uri/Http.php b/Uri/Http.php index bc305030a..6dfbc0dce 100644 --- a/Uri/Http.php +++ b/Uri/Http.php @@ -278,6 +278,20 @@ class Http implements UriInterface return $this->path . (!empty($query) ? '?' . $this->getQuery() : ''); } + /** + * {@inheritdoc} + */ + public function getQuery(string $key = null) /* : ?string */ + { + if(isset($key)) { + $key = strtolower($key); + + return $this->query[$key] ?? ''; + } + + return $this->queryString; + } + /** * {@inheritdoc} */ @@ -294,20 +308,6 @@ class Http implements UriInterface return explode('/', $this->path); } - /** - * {@inheritdoc} - */ - public function getQuery(string $key = null) /* : ?string */ - { - if(isset($key)) { - $key = strtolower($key); - - return $this->query[$key] ?? ''; - } - - return $this->queryString; - } - /** * {@inheritdoc} */ From 73300428cc95611d64ba2fd671b890763625b61c Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Mon, 18 Sep 2017 19:17:00 +0200 Subject: [PATCH 28/76] Autoloader required --- Module/ModuleFactory.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Module/ModuleFactory.php b/Module/ModuleFactory.php index b1c02902f..ad5ca06ab 100644 --- a/Module/ModuleFactory.php +++ b/Module/ModuleFactory.php @@ -15,6 +15,7 @@ declare(strict_types=1); namespace phpOMS\Module; +use phpOMS\Autoloader; use phpOMS\ApplicationAbstract; /** From 8d7e7da54fd251929b1fe90533ed576311e482c3 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Mon, 18 Sep 2017 20:03:42 +0200 Subject: [PATCH 29/76] Needs autoloader --- Module/ModuleManager.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Module/ModuleManager.php b/Module/ModuleManager.php index 76cfa6700..acf98b986 100644 --- a/Module/ModuleManager.php +++ b/Module/ModuleManager.php @@ -16,6 +16,7 @@ declare(strict_types=1); namespace phpOMS\Module; use phpOMS\ApplicationAbstract; +use phpOMS\Autoloader; use phpOMS\DataStorage\Database\DatabaseType; use phpOMS\Message\Http\Request; use phpOMS\System\File\PathException; From 014c1ec3115f0f07d6d58944d50c4b3b097a39d2 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Wed, 20 Sep 2017 09:48:05 +0200 Subject: [PATCH 30/76] Allow to accept from all (e.g. units etc.) --- Account/Account.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Account/Account.php b/Account/Account.php index d348e4373..b8e0f4e4d 100644 --- a/Account/Account.php +++ b/Account/Account.php @@ -269,12 +269,12 @@ class Account implements ArrayableInterface, \JsonSerializable $app = isset($app) ? strtolower($app) : $app; foreach($this->permissions as $p) { - if(($p->getUnit() === $unit || $p->getUnit() === null) - && ($p->getApp() === $app || $p->getApp() === null) - && ($p->getModule() === $module || $p->getModule() === null) - && ($p->getType() === $type || $p->getType() === null) - && ($p->getElement() === $element || $p->getElement() === null) - && ($p->getComponent() === $component || $p->getComponent() === null) + if(($p->getUnit() === $unit || $p->getUnit() === null || !isset($unit)) + && ($p->getApp() === $app || $p->getApp() === null || !isset($app)) + && ($p->getModule() === $module || $p->getModule() === null || !isset($module)) + && ($p->getType() === $type || $p->getType() === null || !isset($type)) + && ($p->getElement() === $element || $p->getElement() === null || !isset($element)) + && ($p->getComponent() === $component || $p->getComponent() === null || !isset($component)) && ($p->getPermission() | $permission) === $p->getPermission()) { return true; } From a1a7420654e9cd612f25da146f03efcff7c1b7e5 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Fri, 22 Sep 2017 19:12:50 +0200 Subject: [PATCH 31/76] Remove application config from abstract --- ApplicationAbstract.php | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/ApplicationAbstract.php b/ApplicationAbstract.php index 8d47bfbb7..204f80302 100644 --- a/ApplicationAbstract.php +++ b/ApplicationAbstract.php @@ -35,14 +35,6 @@ class ApplicationAbstract */ protected $appName = ''; - /** - * Config. - * - * @var array - * @since 1.0.0 - */ - protected $config = []; - /** * Database object. * @@ -153,7 +145,7 @@ class ApplicationAbstract */ public function __set($name, $value) { - if(!empty($this->$name) || $name === 'config') { + if(!empty($this->$name)) { return; } @@ -173,10 +165,6 @@ class ApplicationAbstract */ public function __get($name) { - if($name === 'config') { - return []; - } - return $this->$name; } } From 684d6369a8997410238a188b0474443cd1719a5b Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Fri, 22 Sep 2017 19:13:02 +0200 Subject: [PATCH 32/76] Better default connection return --- DataStorage/Database/DatabasePool.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/DataStorage/Database/DatabasePool.php b/DataStorage/Database/DatabasePool.php index aaec74103..5f4751454 100644 --- a/DataStorage/Database/DatabasePool.php +++ b/DataStorage/Database/DatabasePool.php @@ -77,10 +77,14 @@ class DatabasePool * * @since 1.0.0 */ - public function get(string $key = 'core') /* : ?ConnectionAbstract */ + public function get(string $key = '') /* : ?ConnectionAbstract */ { - if (!isset($this->pool[$key])) { - return null; /* todo: return nullconnection */ + if((!empty($key) && !isset($this->pool[$key])) || empty($this->pool)) { + return null; + } + + if(empty($key)) { + return reset($this->pool); } return $this->pool[$key]; From 1092e945ea653f2fc5b2f8b1a433f86cba449c98 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Fri, 22 Sep 2017 19:18:18 +0200 Subject: [PATCH 33/76] Use read only database connection --- Module/ModuleManager.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Module/ModuleManager.php b/Module/ModuleManager.php index acf98b986..9f605b25b 100644 --- a/Module/ModuleManager.php +++ b/Module/ModuleManager.php @@ -141,7 +141,7 @@ class ModuleManager public function getUriLoad(Request $request) : array { if (!isset($this->uriLoad)) { - switch ($this->app->dbPool->get('core')->getType()) { + switch ($this->app->dbPool->get('select')->getType()) { case DatabaseType::MYSQL: $uriHash = $request->getHash(); $uriPdo = ''; @@ -157,11 +157,11 @@ class ModuleManager $uriPdo = rtrim($uriPdo, ','); /* TODO: make join in order to see if they are active */ - $sth = $this->app->dbPool->get('core')->con->prepare( + $sth = $this->app->dbPool->get('select')->con->prepare( 'SELECT - `' . $this->app->dbPool->get('core')->prefix . 'module_load`.`module_load_type`, `' . $this->app->dbPool->get('core')->prefix . 'module_load`.* + `' . $this->app->dbPool->get('select')->prefix . 'module_load`.`module_load_type`, `' . $this->app->dbPool->get('select')->prefix . 'module_load`.* FROM - `' . $this->app->dbPool->get('core')->prefix . 'module_load` + `' . $this->app->dbPool->get('select')->prefix . 'module_load` WHERE `module_load_pid` IN(' . $uriPdo . ')' ); @@ -191,9 +191,9 @@ class ModuleManager public function getActiveModules() : array { if ($this->active === null) { - switch ($this->app->dbPool->get('core')->getType()) { + switch ($this->app->dbPool->get('select')->getType()) { case DatabaseType::MYSQL: - $sth = $this->app->dbPool->get('core')->con->prepare('SELECT `module_path` FROM `' . $this->app->dbPool->get('core')->prefix . 'module` WHERE `module_active` = 1'); + $sth = $this->app->dbPool->get('select')->con->prepare('SELECT `module_path` FROM `' . $this->app->dbPool->get('select')->prefix . 'module` WHERE `module_active` = 1'); $sth->execute(); $this->active = $sth->fetchAll(\PDO::FETCH_COLUMN); break; @@ -289,9 +289,9 @@ class ModuleManager public function getInstalledModules() : array { if ($this->installed === null) { - switch ($this->app->dbPool->get('core')->getType()) { + switch ($this->app->dbPool->get('select')->getType()) { case DatabaseType::MYSQL: - $sth = $this->app->dbPool->get('core')->con->prepare('SELECT `module_id`,`module_theme`,`module_version` FROM `' . $this->app->dbPool->get('core')->prefix . 'module`'); + $sth = $this->app->dbPool->get('select')->con->prepare('SELECT `module_id`,`module_theme`,`module_version` FROM `' . $this->app->dbPool->get('select')->prefix . 'module`'); $sth->execute(); $this->installed = $sth->fetchAll(\PDO::FETCH_GROUP); break; From 46645f7f2bfea2034ce098256ce93ee64f5a31b2 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Tue, 26 Sep 2017 14:12:27 +0200 Subject: [PATCH 34/76] Make similar to DatabasePool --- DataStorage/Cache/CachePool.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/DataStorage/Cache/CachePool.php b/DataStorage/Cache/CachePool.php index 8f5de89d0..eef56b141 100644 --- a/DataStorage/Cache/CachePool.php +++ b/DataStorage/Cache/CachePool.php @@ -104,12 +104,16 @@ class CachePool implements OptionsInterface * * @since 1.0.0 */ - public function get(string $key) /* : ?CacheInterface */ + public function get(string $key = '') /* : ?CacheInterface */ { - if (!isset($this->pool[$key])) { + if((!empty($key) && !isset($this->pool[$key])) || empty($this->pool)) { return null; } + if(empty($key)) { + return reset($this->pool); + } + return $this->pool[$key]; } From 0733b0e70507f1b36ad163ab4439277bc2a34e23 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Tue, 26 Sep 2017 14:38:50 +0200 Subject: [PATCH 35/76] Fix uri path bug --- Uri/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Uri/Http.php b/Uri/Http.php index 6dfbc0dce..c410ecbe4 100644 --- a/Uri/Http.php +++ b/Uri/Http.php @@ -297,7 +297,7 @@ class Http implements UriInterface */ public function getPathElement(int $pos = null) : string { - return explode('/', $this->path)[$pos]; + return explode('/', $this->path)[$pos] ?? ''; } /** From 69123a0b24fd61098408b8f04337f7aed37fdb6b Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Thu, 28 Sep 2017 11:00:07 +0200 Subject: [PATCH 36/76] Return null obj in datamapper --- DataStorage/Database/DataMapperAbstract.php | 24 +++++++++++++-------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/DataStorage/Database/DataMapperAbstract.php b/DataStorage/Database/DataMapperAbstract.php index 579820dce..7f934cdf8 100644 --- a/DataStorage/Database/DataMapperAbstract.php +++ b/DataStorage/Database/DataMapperAbstract.php @@ -1878,7 +1878,7 @@ class DataMapperAbstract implements DataMapperInterface $countResulsts = count($obj); if($countResulsts === 0) { - return null; + return self::getNullModelObj(); } elseif($countResulsts === 1) { return reset($obj); } @@ -1886,6 +1886,18 @@ class DataMapperAbstract implements DataMapperInterface return $obj; } + private static function getNullModelObj() + { + $class = static::class; + $class = str_replace('Mapper', '', $class); + $parts = explode('\\', $class); + $name = $parts[$c = (count($parts) - 1)]; + $parts[$c] = 'Null' . $name; + $class = implode('\\', $parts); + + return new $class(); + } + /** * Get object. * @@ -1961,7 +1973,7 @@ class DataMapperAbstract implements DataMapperInterface $countResulsts = count($obj); if($countResulsts === 0) { - return null; + return self::getNullModelObj(); } elseif($countResulsts === 1) { return reset($obj); } @@ -2465,13 +2477,7 @@ class DataMapperAbstract implements DataMapperInterface $result = static::getAllByQuery($query); } } else { - $class = static::class; - $class = str_replace('Mapper', '', $class); - $parts = explode('\\', $class); - $name = $parts[$c = (count($parts) - 1)]; - $parts[$c] = 'Null' . $name; - $class = implode('\\', $parts); - $result = new $class(); + return self::getNullModelObj(); } return $result; From 663dd31ad07be34f135af2e5846ba5bba6527828 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Fri, 29 Sep 2017 17:13:38 +0200 Subject: [PATCH 37/76] Add getters for connection --- .../Connection/ConnectionAbstract.php | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/DataStorage/Database/Connection/ConnectionAbstract.php b/DataStorage/Database/Connection/ConnectionAbstract.php index 1a97a9a1d..7300e3a2b 100644 --- a/DataStorage/Database/Connection/ConnectionAbstract.php +++ b/DataStorage/Database/Connection/ConnectionAbstract.php @@ -110,6 +110,42 @@ abstract class ConnectionAbstract implements ConnectionInterface return $this->status; } + /** + * Get database name. + * + * @return string + * + * @since 1.0.0 + */ + public function getDatabase() : string + { + return $this->dbdata['database']; + } + + /** + * Get database host. + * + * @return string + * + * @since 1.0.0 + */ + public function getHost() : string + { + return $this->dbdata['host']; + } + + /** + * Get database port. + * + * @return int + * + * @since 1.0.0 + */ + public function getPort() : int + { + return (int) $this->dbdata['port']; + } + /** * Get table prefix. * From 1422f2c58758769a062d7a8b4cc33793e4efd782 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Sat, 30 Sep 2017 11:16:51 +0200 Subject: [PATCH 38/76] Added list by extension alternative --- System/File/Local/Directory.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/System/File/Local/Directory.php b/System/File/Local/Directory.php index dd5ee4d7d..76e63b595 100644 --- a/System/File/Local/Directory.php +++ b/System/File/Local/Directory.php @@ -88,6 +88,25 @@ class Directory extends FileAbstract implements DirectoryInterface return $list; } + public static function listByExtension(string $dir, string $extension) : array + { + $files = []; + $ffs = scandir($dir); + foreach ($ffs as $ff) { + if ($ff !== '.' && $ff !== '..') { + if (is_dir($dir . '/' . $ff)) { + $files = array_merge($files, self::listFilesByExtension($dir . '/' . $ff, $extension)); + } else { + if (StringUtils::endsWith($ff, $extension)) { + $files[] = $dir . '/' . $ff; + } + } + } + } + + return $files; + } + /** * {@inheritdoc} */ From b92717a3b63fb4ff0f82feb21fec019ef98d5b6d Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Sat, 30 Sep 2017 12:39:03 +0200 Subject: [PATCH 39/76] Test adjustments --- Html/TagType.php | 40 -------------------------------- Math/Number/NumberType.php | 18 +++++++------- Utils/Converter/AngleType.php | 2 +- Utils/Converter/PressureType.php | 2 +- Utils/RnG/DistributionType.php | 1 - 5 files changed, 11 insertions(+), 52 deletions(-) delete mode 100644 Html/TagType.php diff --git a/Html/TagType.php b/Html/TagType.php deleted file mode 100644 index 9c246f465..000000000 --- a/Html/TagType.php +++ /dev/null @@ -1,40 +0,0 @@ - */ - /* public */ const BUTTON = 1; /*