diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 41075f01b..aaf12c14e 100755 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,4 +7,5 @@ jobs: uses: Karaka-Management/Karaka/.github/workflows/php_template.yml@develop secrets: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_PAT: ${{ secrets.GH_PAT }} \ No newline at end of file + GH_PAT: ${{ secrets.GH_PAT }} + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/DataStorage/Database/Mapper/DataMapperAbstract.php b/DataStorage/Database/Mapper/DataMapperAbstract.php index fdef771e7..ef2e963db 100755 --- a/DataStorage/Database/Mapper/DataMapperAbstract.php +++ b/DataStorage/Database/Mapper/DataMapperAbstract.php @@ -548,8 +548,8 @@ abstract class DataMapperAbstract return (string) \gzdeflate($value); } elseif ($type === 'Serializable') { return $value->serialize(); - } elseif (\is_object($value) && \method_exists($value, 'getId')) { - return $value->getId(); + } elseif (\is_object($value) && isset($value->id)) { + return $value->id; } return $value; diff --git a/DataStorage/Database/Mapper/DataMapperFactory.php b/DataStorage/Database/Mapper/DataMapperFactory.php index 07fe92c79..18988b8bd 100755 --- a/DataStorage/Database/Mapper/DataMapperFactory.php +++ b/DataStorage/Database/Mapper/DataMapperFactory.php @@ -426,38 +426,53 @@ class DataMapperFactory /** * Get id of object * - * @param object $obj Model to create - * @param string $member Member name for the id, if it is not the primary key + * @param object $obj Model to create + * @param string $member Member name for the id, if it is not the primary key + * @param null|\ReflectionClass $refClass Reflection class * * @return mixed * * @since 1.0.0 */ - public static function getObjectId(object $obj, string $member = null) : mixed + public static function getObjectId(object $obj, string $member = null, \ReflectionClass &$refClass = null) : mixed { $propertyName = $member ?? static::COLUMNS[static::PRIMARYFIELD]['internal']; - return $obj->{$propertyName}; + if (static::COLUMNS[static::PRIMARYFIELD]['private'] ?? false) { + if ($refClass === null) { + $refClass = new \ReflectionClass($obj); + } + + $refProp = $refClass->getProperty($propertyName); + + return $refProp->getValue($obj); + } else { + return $obj->{$propertyName}; + } } /** * Set id to model * - * @param \ReflectionClass $refClass Reflection class - * @param object $obj Object to create - * @param mixed $objId Id to set + * @param object $obj Object to create + * @param mixed $objId Id to set + * @param null|\ReflectionClass $refClass Reflection class * * @return void * * @since 1.0.0 */ - public static function setObjectId(\ReflectionClass $refClass, object $obj, mixed $objId) : void + public static function setObjectId(object $obj, mixed $objId, \ReflectionClass &$refClass = null) : void { $propertyName = static::COLUMNS[static::PRIMARYFIELD]['internal']; - $refProp = $refClass->getProperty($propertyName); - \settype($objId, static::COLUMNS[static::PRIMARYFIELD]['type']); - if (!$refProp->isPublic()) { + + if (static::COLUMNS[static::PRIMARYFIELD]['private'] ?? false) { + if ($refClass === null) { + $refClass = new \ReflectionClass($obj); + } + + $refProp = $refClass->getProperty($propertyName); $refProp->setValue($obj, $objId); } else { $obj->{$propertyName} = $objId; diff --git a/DataStorage/Database/Mapper/DeleteMapper.php b/DataStorage/Database/Mapper/DeleteMapper.php index d155406ce..c68ab7877 100755 --- a/DataStorage/Database/Mapper/DeleteMapper.php +++ b/DataStorage/Database/Mapper/DeleteMapper.php @@ -71,17 +71,17 @@ final class DeleteMapper extends DataMapperAbstract */ public function executeDelete(object $obj) : mixed { - $refClass = new \ReflectionClass($obj); + $refClass = null; $objId = $this->mapper::getObjectId($obj); if (empty($objId)) { return null; } - $this->deleteSingleRelation($obj, $refClass, $this->mapper::BELONGS_TO); - $this->deleteHasMany($refClass, $obj, $objId); + $this->deleteSingleRelation($obj, $this->mapper::BELONGS_TO, $refClass); + $this->deleteHasMany($obj, $objId, $refClass); $this->deleteModel($objId); - $this->deleteSingleRelation($obj, $refClass, $this->mapper::OWNS_ONE); + $this->deleteSingleRelation($obj, $this->mapper::OWNS_ONE, $refClass); return $objId; } @@ -111,15 +111,15 @@ final class DeleteMapper extends DataMapperAbstract /** * Delete ownsOne, belongsTo relations * - * @param object $obj Object to delete - * @param \ReflectionClass $refClass Reflection of object to delete - * @param array $relation Relation data (e.g. ::BELONGS_TO, ::OWNS_ONE) + * @param object $obj Object to delete + * @param array $relation Relation data (e.g. ::BELONGS_TO, ::OWNS_ONE) + * @param null|\ReflectionClass $refClass Reflection of object to delete * * @return void * * @since 1.0.0 */ - private function deleteSingleRelation(object $obj, \ReflectionClass $refClass, array $relation) : void + private function deleteSingleRelation(object $obj, array $relation, \ReflectionClass &$refClass = null) : void { if (empty($relation)) { return; @@ -137,27 +137,36 @@ final class DeleteMapper extends DataMapperAbstract $relMapper = $this->createRelationMapper($mapper::delete(db: $this->db), $member); $relMapper->depth = $this->depth + 1; - $refProp = $refClass->getProperty($member); - if (!$refProp->isPublic()) { - $relMapper->execute($refProp->getValue($obj)); + $isPrivate = $relData['private'] ?? false; + + $value = null; + if ($isPrivate) { + if ($refClass === null) { + $refClass = new \ReflectionClass($obj); + } + + $refProp = $refClass->getProperty($member); + $value = $refProp->getValue($obj); } else { - $relMapper->execute($obj->{$member}); + $value = $obj->{$member}; } + + $relMapper->execute($value); } } /** * Delete hasMany * - * @param \ReflectionClass $refClass Reflection of object to delete - * @param object $obj Object to delete - * @param mixed $objId Object id to delete + * @param object $obj Object to delete + * @param mixed $objId Object id to delete + * @param null|\ReflectionClass $refClass Reflection of object to delete * * @return void * * @since 1.0.0 */ - private function deleteHasMany(\ReflectionClass $refClass, object $obj, mixed $objId) : void + private function deleteHasMany(object $obj, mixed $objId, \ReflectionClass &$refClass = null) : void { if (empty($this->mapper::HAS_MANY)) { return; @@ -169,9 +178,20 @@ final class DeleteMapper extends DataMapperAbstract continue; } - $objIds = []; - $refProp = $refClass->getProperty($member); - $values = $refProp->isPublic() ? $obj->{$member} : $refProp->getValue($obj); + $objIds = []; + $isPrivate = $rel['private'] ?? false; + + $values = null; + if ($isPrivate) { + if ($refClass === null) { + $refClass = new \ReflectionClass($obj); + } + + $refProp = $refClass->getProperty($member); + $values = $refProp->getValue($obj); + } else { + $values = $obj->{$member}; + } if (!\is_array($values)) { // conditionals diff --git a/DataStorage/Database/Mapper/ReadMapper.php b/DataStorage/Database/Mapper/ReadMapper.php index a5bb79a0d..e67844987 100755 --- a/DataStorage/Database/Mapper/ReadMapper.php +++ b/DataStorage/Database/Mapper/ReadMapper.php @@ -555,7 +555,7 @@ final class ReadMapper extends DataMapperAbstract */ public function populateAbstract(array $result, object $obj) : object { - $refClass = new \ReflectionClass($obj); + $refClass = null; foreach ($this->mapper::COLUMNS as $column => $def) { $alias = $column . '_d' . $this->depth; @@ -569,28 +569,42 @@ final class ReadMapper extends DataMapperAbstract $hasPath = false; $aValue = []; $arrayPath = ''; + $refProp = null; + $isPrivate = $def['private'] ?? false; + $member = ''; + + if ($isPrivate && $refClass === null) { + $refClass = new \ReflectionClass($obj); + } if (\stripos($def['internal'], '/') !== false) { $hasPath = true; $path = \explode('/', \ltrim($def['internal'], '/')); $member = $path[0]; - $refProp = $refClass->getProperty($path[0]); - $isPublic = $refProp->isPublic(); - $aValue = $isPublic ? $obj->{$path[0]} : $refProp->getValue($obj); + if ($isPrivate) { + $refProp = $refClass->getProperty($path[0]); + $aValue = $refProp->getValue($obj); + } else { + $aValue = $obj->{$path[0]}; + } \array_shift($path); $arrayPath = \implode('/', $path); } else { - $refProp = $refClass->getProperty($def['internal']); - $isPublic = $refProp->isPublic(); - $member = $def['internal']; + if ($isPrivate) { + $refProp = $refClass->getProperty($def['internal']); + } + + $member = $def['internal']; } if (isset($this->mapper::OWNS_ONE[$def['internal']])) { $default = null; - if (!isset($this->with[$member]) && $refProp->isInitialized($obj)) { - $default = $isPublic ? $obj->{$def['internal']} : $refProp->getValue($obj); + if (!isset($this->with[$member]) + && ($isPrivate ? $refProp->isInitialized($obj) : isset($obj->{$member})) + ) { + $default = $isPrivate ? $refProp->getValue($obj) : $obj->{$member}; } $value = $this->populateOwnsOne($def['internal'], $result, $default); @@ -600,14 +614,16 @@ final class ReadMapper extends DataMapperAbstract $this->mapper::OWNS_ONE[$def['internal']]['mapper']::reader(db: $this->db)->loadHasManyRelations($value); } - if (!empty($value)) { + if (empty($value)) { // @todo: find better solution. this was because of a bug with the sales billing list query depth = 4. The address was set (from the client, referral or creator) but then somehow there was a second address element which was all null and null cannot be asigned to a string variable (e.g. country). The problem with this solution is that if the model expects an initialization (e.g. at lest set the elements to null, '', 0 etc.) this is now not done. - $refProp->setValue($obj, $value); + $value = $isPrivate ? $refProp->getValue($obj) : $obj->{$member}; } } elseif (isset($this->mapper::BELONGS_TO[$def['internal']])) { $default = null; - if (!isset($this->with[$member]) && $refProp->isInitialized($obj)) { - $default = $isPublic ? $obj->{$def['internal']} : $refProp->getValue($obj); + if (!isset($this->with[$member]) + && ($isPrivate ? $refProp->isInitialized($obj) : isset($obj->{$member})) + ) { + $default = $isPrivate ? $refProp->getValue($obj) : $obj->{$member}; } $value = $this->populateBelongsTo($def['internal'], $result, $default); @@ -616,8 +632,6 @@ final class ReadMapper extends DataMapperAbstract if (\is_object($value) && isset($this->mapper::BELONGS_TO[$def['internal']]['mapper'])) { $this->mapper::BELONGS_TO[$def['internal']]['mapper']::reader(db: $this->db)->loadHasManyRelations($value); } - - $refProp->setValue($obj, $value); } elseif (\in_array($def['type'], ['string', 'compress', 'int', 'float', 'bool'])) { if ($value !== null && $def['type'] === 'compress') { $def['type'] = 'string'; @@ -625,44 +639,44 @@ final class ReadMapper extends DataMapperAbstract $value = \gzinflate($value); } - if ($value !== null || $refProp->getValue($obj) !== null) { + $mValue = $isPrivate ? $refProp->getValue($obj) : $obj->{$member}; + if ($value !== null || $mValue !== null) { \settype($value, $def['type']); } if ($hasPath) { $value = ArrayUtils::setArray($arrayPath, $aValue, $value, '/', true); } - - $refProp->setValue($obj, $value); } elseif ($def['type'] === 'DateTime') { $value = $value === null ? null : new \DateTime($value); if ($hasPath) { $value = ArrayUtils::setArray($arrayPath, $aValue, $value, '/', true); } - - $refProp->setValue($obj, $value); } elseif ($def['type'] === 'DateTimeImmutable') { $value = $value === null ? null : new \DateTimeImmutable($value); if ($hasPath) { $value = ArrayUtils::setArray($arrayPath, $aValue, $value, '/', true); } - - $refProp->setValue($obj, $value); } elseif ($def['type'] === 'Json') { if ($hasPath) { $value = ArrayUtils::setArray($arrayPath, $aValue, $value, '/', true); } - $refProp->setValue($obj, \json_decode($value, true)); + $value = \json_decode($value, true); } elseif ($def['type'] === 'Serializable') { - $member = $isPublic ? $obj->{$def['internal']} : $refProp->getValue($obj); + $mObj = $isPrivate ? $refProp->getValue($obj) : $obj->{$member}; - if ($member === null || $value === null) { - $obj->{$def['internal']} = $value; - } else { - $member->unserialize($value); + if ($mObj !== null && $value !== null) { + $mObj->unserialize($value); + $value = $mObj; } } + + if ($isPrivate) { + $refProp->setValue($obj, $value); + } else { + $obj->{$member} = $value; + } } foreach ($this->mapper::HAS_MANY as $member => $def) { @@ -677,54 +691,68 @@ final class ReadMapper extends DataMapperAbstract $hasPath = false; $aValue = null; $arrayPath = '/'; + $refProp = null; + $isPrivate = $def['private'] ?? false; + + if ($isPrivate && $refClass === null) { + $refClass = new \ReflectionClass($obj); + } if (\stripos($member, '/') !== false) { - $hasPath = true; - $path = \explode('/', $member); - $refProp = $refClass->getProperty($path[0]); - $isPublic = $refProp->isPublic(); + $hasPath = true; + $path = \explode('/', $member); + $member = $path[0]; + + if ($isPrivate) { + $refProp = $refClass->getProperty($path[0]); + } \array_shift($path); $arrayPath = \implode('/', $path); - $aValue = $isPublic ? $obj->{$path[0]} : $refProp->getValue($obj); - } else { - $refProp = $refClass->getProperty($member); - $isPublic = $refProp->isPublic(); + $aValue = $isPrivate ? $refProp->getValue($obj) : $obj->{$path[0]}; + } elseif ($isPrivate) { + $refProp = $refClass->getProperty($member); } if (\in_array($def['mapper']::COLUMNS[$column]['type'], ['string', 'int', 'float', 'bool'])) { - if ($value !== null || $refProp->getValue($obj) !== null) { + if ($value !== null + || ($isPrivate ? $refProp->getValue($obj) !== null : $obj->{$member} !== null) + ) { \settype($value, $def['mapper']::COLUMNS[$column]['type']); } if ($hasPath) { $value = ArrayUtils::setArray($arrayPath, $aValue, $value, '/', true); } - - $refProp->setValue($obj, $value); } elseif ($def['mapper']::COLUMNS[$column]['type'] === 'DateTime') { - $value = $value === null ? null : new \DateTime($value); + $value ??= new \DateTime($value); if ($hasPath) { $value = ArrayUtils::setArray($arrayPath, $aValue, $value, '/', true); } - - $refProp->setValue($obj, $value); } elseif ($def['mapper']::COLUMNS[$column]['type'] === 'DateTimeImmutable') { - $value = $value === null ? null : new \DateTimeImmutable($value); + $value ??= new \DateTimeImmutable($value); if ($hasPath) { $value = ArrayUtils::setArray($arrayPath, $aValue, $value, '/', true); } - - $refProp->setValue($obj, $value); } elseif ($def['mapper']::COLUMNS[$column]['type'] === 'Json') { if ($hasPath) { $value = ArrayUtils::setArray($arrayPath, $aValue, $value, '/', true); } - $refProp->setValue($obj, \json_decode($value, true)); + $value = \json_decode($value, true); } elseif ($def['mapper']::COLUMNS[$column]['type'] === 'Serializable') { - $member = $isPublic ? $obj->{$member} : $refProp->getValue($obj); - $member->unserialize($value); + $mObj = $isPrivate ? $refProp->getValue($obj) : $obj->{$member}; + + if ($mObj !== null && $value !== null) { + $mObj->unserialize($value); + $value = $mObj; + } + } + + if ($isPrivate) { + $refProp->setValue($obj, $value); + } else { + $obj->{$member} = $value; } } @@ -867,6 +895,8 @@ final class ReadMapper extends DataMapperAbstract continue; } + $isPrivate = $withData['private'] ?? false; + $objectMapper = $this->createRelationMapper($many['mapper']::get(db: $this->db), $member); if ($many['external'] === null/* same as $many['table'] !== $many['mapper']::TABLE */) { $objectMapper->where($many['mapper']::COLUMNS[$many['self']]['internal'], $primaryKey); @@ -886,12 +916,12 @@ final class ReadMapper extends DataMapperAbstract continue; } - if ($refClass === null) { - $refClass = new \ReflectionClass($obj); - } + if ($isPrivate) { + if ($refClass === null) { + $refClass = new \ReflectionClass($obj); + } - $refProp = $refClass->getProperty($member); - if (!$refProp->isPublic()) { + $refProp = $refClass->getProperty($member); $refProp->setValue($obj, !\is_array($objects) && ($many['conditional'] ?? false) === false ? [$many['mapper']::getObjectId($objects) => $objects] : $objects // if conditional === true the obj will be asigned (e.g. has many localizations but only one is loaded for the model) @@ -914,15 +944,16 @@ final class ReadMapper extends DataMapperAbstract continue; } - if ($refClass === null) { - $refClass = new \ReflectionClass($obj); - } - /** @var ReadMapper $relMapper */ $relMapper = $this->createRelationMapper($relation['mapper']::reader($this->db), $member); - $refProp = $refClass->getProperty($member); - if (!$refProp->isPublic()) { + $isPrivate = $withData['private'] ?? false; + if ($isPrivate) { + if ($refClass === null) { + $refClass = new \ReflectionClass($obj); + } + + $refProp = $refClass->getProperty($member); $relMapper->loadHasManyRelations($refProp->getValue($obj)); } else { $relMapper->loadHasManyRelations($obj->{$member}); diff --git a/DataStorage/Database/Mapper/UpdateMapper.php b/DataStorage/Database/Mapper/UpdateMapper.php index b6f52e776..881281cc8 100755 --- a/DataStorage/Database/Mapper/UpdateMapper.php +++ b/DataStorage/Database/Mapper/UpdateMapper.php @@ -73,14 +73,14 @@ final class UpdateMapper extends DataMapperAbstract */ public function executeUpdate(object $obj) : mixed { - $refClass = new \ReflectionClass($obj); + $refClass = null; $objId = $this->mapper::getObjectId($obj); if ($this->mapper::isNullModel($obj)) { return $objId === 0 ? null : $objId; } - $this->updateHasMany($refClass, $obj, $objId); + $this->updateHasMany($obj, $objId, $refClass); if (empty($objId)) { return $this->mapper::create(db: $this->db)->execute($obj); @@ -102,7 +102,7 @@ final class UpdateMapper extends DataMapperAbstract * * @since 1.0.0 */ - private function updateModel(object $obj, mixed $objId, \ReflectionClass $refClass = null) : void + private function updateModel(object $obj, mixed $objId, \ReflectionClass &$refClass = null) : void { try { // Model doesn't have anything to update @@ -124,10 +124,20 @@ final class UpdateMapper extends DataMapperAbstract continue; } - $refClass = $refClass ?? new \ReflectionClass($obj); - $property = $refClass->getProperty($propertyName); + $isPrivate = $column['private'] ?? false; + $property = null; + $tValue = null; - $tValue = $property->isPublic() ? $obj->{$propertyName} : $property->getValue($obj); + if ($isPrivate) { + if ($refClass === null) { + $refClass = new \ReflectionClass($obj); + } + + $property = $refClass->getProperty($propertyName); + $tValue = $property->getValue($obj); + } else { + $tValue = $obj->{$propertyName}; + } if (isset($this->mapper::OWNS_ONE[$propertyName])) { $id = \is_object($tValue) ? $this->updateOwnsOne($propertyName, $tValue) : $tValue; @@ -218,9 +228,9 @@ final class UpdateMapper extends DataMapperAbstract /** * Update has many relations * - * @param \ReflectionClass $refClass Reflection of the object containing the relations - * @param object $obj Object which contains the relations - * @param mixed $objId Object id which contains the relations + * @param object $obj Object which contains the relations + * @param mixed $objId Object id which contains the relations + * @param null|\ReflectionClass $refClass Reflection of the object containing the relations * * @return void * @@ -228,7 +238,7 @@ final class UpdateMapper extends DataMapperAbstract * * @since 1.0.0 */ - private function updateHasMany(\ReflectionClass $refClass, object $obj, mixed $objId) : void + private function updateHasMany(object $obj, mixed $objId, \ReflectionClass &$refClass = null) : void { if (empty($this->with) || empty($this->mapper::HAS_MANY)) { return; @@ -245,17 +255,33 @@ final class UpdateMapper extends DataMapperAbstract throw new InvalidMapperException(); } - $property = $refClass->getProperty($propertyName); + $isPrivate = $rel['private'] ?? false; + $property = null; + $values = null; - $values = ($isPublic = $property->isPublic()) ? $obj->{$propertyName} : $property->getValue($obj); + if ($isPrivate) { + if ($refClass === null) { + $refClass = new \ReflectionClass($obj); + } + + $property = $refClass->getProperty($propertyName); + $values = $property->getValue($obj); + } else { + $values = $obj->{$propertyName}; + } if (!\is_array($values) || empty($values)) { continue; } /** @var class-string $mapper */ - $mapper = $this->mapper::HAS_MANY[$propertyName]['mapper']; - $relReflectionClass = new \ReflectionClass(\reset($values)); + $mapper = $this->mapper::HAS_MANY[$propertyName]['mapper']; + $isPrivateRel = $this->mapper::HAS_MANY[$propertyName]['private'] ?? false; + + if ($isPrivateRel) { + $relReflectionClass = new \ReflectionClass(\reset($values)); + } + $objsIds[$propertyName] = []; foreach ($values as $key => &$value) { @@ -285,9 +311,8 @@ final class UpdateMapper extends DataMapperAbstract if ($this->mapper::HAS_MANY[$propertyName]['table'] === $this->mapper::HAS_MANY[$propertyName]['mapper']::TABLE && isset($mapper::COLUMNS[$this->mapper::HAS_MANY[$propertyName]['self']]) ) { - $relProperty = $relReflectionClass->getProperty($mapper::COLUMNS[$this->mapper::HAS_MANY[$propertyName]['self']]['internal']); - - if (!$isPublic) { + if ($isPrivateRel) { + $relProperty = $relReflectionClass->getProperty($mapper::COLUMNS[$this->mapper::HAS_MANY[$propertyName]['self']]['internal']); $relProperty->setValue($value, $objId); } else { $value->{$mapper::COLUMNS[$this->mapper::HAS_MANY[$propertyName]['self']]['internal']} = $objId; diff --git a/DataStorage/Database/Mapper/WriteMapper.php b/DataStorage/Database/Mapper/WriteMapper.php index 1ba0cf92a..eacf8ca49 100755 --- a/DataStorage/Database/Mapper/WriteMapper.php +++ b/DataStorage/Database/Mapper/WriteMapper.php @@ -74,7 +74,7 @@ final class WriteMapper extends DataMapperAbstract */ public function executeCreate(object $obj) : mixed { - $refClass = new \ReflectionClass($obj); + $refClass = null; if ($this->mapper::isNullModel($obj)) { $objId = $this->mapper::getObjectId($obj); @@ -86,10 +86,10 @@ final class WriteMapper extends DataMapperAbstract $objId = $id; } else { $objId = $this->createModel($obj, $refClass); - $this->mapper::setObjectId($refClass, $obj, $objId); + $this->mapper::setObjectId($obj, $objId, $refClass); } - $this->createHasMany($refClass, $obj, $objId); + $this->createHasMany($obj, $objId, $refClass); return $objId; } @@ -97,21 +97,19 @@ final class WriteMapper extends DataMapperAbstract /** * Create model * - * @param object $obj Object to create - * @param \ReflectionClass $refClass Reflection of the object to create + * @param object $obj Object to create + * @param null|\ReflectionClass $refClass Reflection of the object to create * * @return mixed * * @since 1.0.0 */ - private function createModel(object $obj, \ReflectionClass $refClass) : mixed + private function createModel(object $obj, \ReflectionClass &$refClass = null) : mixed { try { $query = new Builder($this->db); $query->into($this->mapper::TABLE); - $publicProperties = \get_object_vars($obj); - foreach ($this->mapper::COLUMNS as $column) { $propertyName = \stripos($column['internal'], '/') !== false ? \explode('/', $column['internal'])[0] @@ -123,13 +121,16 @@ final class WriteMapper extends DataMapperAbstract continue; } - if (!isset($publicProperties[$propertyName])) { + $tValue = null; + if ($column['private'] ?? false) { + if ($refClass === null) { + $refClass = new \ReflectionClass($obj); + } + $property = $refClass->getProperty($propertyName); - $property->setAccessible(true); - $tValue = $property->getValue($obj); - $property->setAccessible(false); + $tValue = $property->getValue($obj); } else { - $tValue = $publicProperties[$propertyName]; + $tValue = $obj->{$propertyName}; } if (isset($this->mapper::OWNS_ONE[$propertyName])) { @@ -231,10 +232,13 @@ final class WriteMapper extends DataMapperAbstract if (isset($this->mapper::BELONGS_TO[$propertyName]['by'])) { // has by (obj is stored as a different model e.g. model = profile but reference/db is account) - $refClass = new \ReflectionClass($obj); - $refProp = $refClass->getProperty($this->mapper::BELONGS_TO[$propertyName]['by']); - - $obj = $refProp->isPublic() ? $obj->{$this->mapper::BELONGS_TO[$propertyName]['by']} : $refProp->getValue($obj); + if ($this->mapper::BELONGS_TO[$propertyName]['private']) { + $refClass = new \ReflectionClass($obj); + $refProp = $refClass->getProperty($this->mapper::BELONGS_TO[$propertyName]['by']); + $obj = $refProp->getValue($obj); + } else { + $obj = $obj->{$this->mapper::BELONGS_TO[$propertyName]['by']}; + } } /** @var class-string $mapper */ @@ -248,9 +252,9 @@ final class WriteMapper extends DataMapperAbstract /** * Create has many models * - * @param \ReflectionClass $refClass Reflection of the object to create - * @param object $obj Object to create - * @param mixed $objId Id of the parent object + * @param object $obj Object to create + * @param mixed $objId Id of the parent object + * @param null|\ReflectionClass $refClass Reflection of the object to create * * @return void * @@ -258,15 +262,27 @@ final class WriteMapper extends DataMapperAbstract * * @since 1.0.0 */ - private function createHasMany(\ReflectionClass $refClass, object $obj, mixed $objId) : void + private function createHasMany(object $obj, mixed $objId, \ReflectionClass &$refClass = null) : void { - foreach ($this->mapper::HAS_MANY as $propertyName => $_) { + foreach ($this->mapper::HAS_MANY as $propertyName => $rel) { if (!isset($this->mapper::HAS_MANY[$propertyName]['mapper'])) { throw new InvalidMapperException(); // @codeCoverageIgnore } - $property = $refClass->getProperty($propertyName); - $values = $property->isPublic() ? $obj->{$propertyName} : $property->getValue($obj); + $isPrivate = $rel['private'] ?? false; + $property = null; + $values = null; + + if ($isPrivate) { + if ($refClass === null) { + $refClass = new \ReflectionClass($obj); + } + + $property = $refClass->getProperty($propertyName); + $values = $property->getValue($obj); + } else { + $values = $obj->{$propertyName}; + } /** @var class-string $mapper */ $mapper = $this->mapper::HAS_MANY[$propertyName]['mapper']; @@ -274,17 +290,16 @@ final class WriteMapper extends DataMapperAbstract ? $mapper::COLUMNS[$this->mapper::HAS_MANY[$propertyName]['self']]['internal'] : 'ERROR'; + // @todo: this or $isRelPrivate is wrong, don't know which one. + $isInternalPrivate =$mapper::COLUMNS[$this->mapper::HAS_MANY[$propertyName]['self']]['private'] ?? false; + if (\is_object($values)) { // conditionals - $publicProperties = \get_object_vars($values); - - if (!isset($publicProperties[$internalName])) { + if ($isInternalPrivate) { $relReflectionClass = new \ReflectionClass($values); $relProperty = $relReflectionClass->getProperty($internalName); - $relProperty->setAccessible(true); $relProperty->setValue($values, $objId); - $relProperty->setAccessible(false); } else { $values->{$internalName} = $objId; } @@ -297,7 +312,8 @@ final class WriteMapper extends DataMapperAbstract } $objsIds = []; - $relReflectionClass = empty($values) ? null : new \ReflectionClass(\reset($values)); + $isRelPrivate = $mapper::COLUMNS[$this->mapper::HAS_MANY[$propertyName]['self']]['private'] ?? false; + $relReflectionClass = $isRelPrivate && !empty($values) ? new \ReflectionClass(\reset($values)) : null; foreach ($values as $key => $value) { if (!\is_object($value)) { @@ -307,7 +323,6 @@ final class WriteMapper extends DataMapperAbstract continue; } - /** @var \ReflectionClass $relReflectionClass */ $primaryKey = $mapper::getObjectId($value); // already in db @@ -319,26 +334,24 @@ final class WriteMapper extends DataMapperAbstract // Setting relation value (id) for relation (since the relation is not stored in an extra relation table) if (!isset($this->mapper::HAS_MANY[$propertyName]['external'])) { - $relProperty = $relReflectionClass->getProperty($internalName); - $isRelPublic = $relProperty->isPublic(); + $relProperty = null; + if ($isRelPrivate) { + $relProperty = $relReflectionClass->getProperty($internalName); + } // todo maybe consider to just set the column type to object, and then check for that (might be faster) if (isset($mapper::BELONGS_TO[$internalName]) || isset($mapper::OWNS_ONE[$internalName])) { - if (!$isRelPublic) { + if ($isRelPrivate) { $relProperty->setValue($value, $this->mapper::createNullModel($objId)); } else { $value->{$internalName} = $this->mapper::createNullModel($objId); } - } elseif (!$isRelPublic) { + } elseif ($isRelPrivate) { $relProperty->setValue($value, $objId); } else { $value->{$internalName} = $objId; } - - if (!$isRelPublic) { - $relProperty->setAccessible(false); - } } $objsIds[$key] = $mapper::create(db: $this->db)->execute($value); diff --git a/tests/Autoloader.php b/tests/Autoloader.php index 58a7cc660..6e249662d 100755 --- a/tests/Autoloader.php +++ b/tests/Autoloader.php @@ -79,7 +79,7 @@ class Autoloader $class = \strtr($class, '_\\', '//'); if (\stripos($class, 'Web/Backend') !== false || \stripos($class, 'Web/Api') !== false) { - $class = \is_dir(__DIR__ . '/Web') ? $class : \str_replace('Web/', 'Karaka/Web/', $class); + $class = \is_dir(__DIR__ . '/Web') ? $class : \str_replace('Web/', 'MainRepository/Web/', $class); } $class2 = $class; diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php index 88872816d..1b48ed57b 100755 --- a/tests/Bootstrap.php +++ b/tests/Bootstrap.php @@ -7,7 +7,10 @@ declare(strict_types=1); \error_reporting(\E_ALL); \setlocale(\LC_ALL, 'en_US.UTF-8'); -require_once __DIR__ . '/../vendor/autoload.php'; +if (\is_file(__DIR__ . '/../vendor/autoload.php')) { + require_once __DIR__ . '/../vendor/autoload.php'; +} + require_once __DIR__ . '/Autoloader.php'; use phpOMS\DataStorage\Database\DatabasePool; @@ -19,7 +22,7 @@ $IS_GITHUB = false; $temp = \array_keys($_SERVER); foreach ($temp as $key) { - if (\stripos(\strtolower($key), 'github') !== false) { + if (\is_string($key) && \stripos(\strtolower($key), 'github') !== false) { $IS_GITHUB = true; break; @@ -28,7 +31,7 @@ foreach ($temp as $key) { if (!$IS_GITHUB) { foreach ($_SERVER as $value) { - if (\stripos(\strtolower($value), 'github') !== false) { + if (\is_string($value) && \stripos(\strtolower($value), 'github') !== false) { $IS_GITHUB = true; break; @@ -39,7 +42,7 @@ if (!$IS_GITHUB) { $temp = \array_keys(\getenv()); if (!$IS_GITHUB) { foreach ($temp as $key) { - if (\stripos(\strtolower($key), 'github') !== false) { + if (\is_string($key) && \stripos(\strtolower($key), 'github') !== false) { $IS_GITHUB = true; break; @@ -50,7 +53,7 @@ if (!$IS_GITHUB) { $temp = \array_values(\getenv()); if (!$IS_GITHUB) { foreach ($temp as $value) { - if (\stripos(\strtolower($value), 'github') !== false) { + if (\is_string($value) && \stripos(\strtolower($value), 'github') !== false) { $IS_GITHUB = true; break; @@ -71,9 +74,9 @@ $CONFIG = [ 'db' => 'mysql', /* db type */ 'host' => '127.0.0.1', /* db host address */ 'port' => '3306', /* db host port */ - 'login' => 'root', /* db login name */ - 'password' => 'root', /* db login password */ - 'database' => 'oms', /* db name */ + 'login' => 'test', /* db login name */ + 'password' => 'orange', /* db login password */ + 'database' => 'omt', /* db name */ 'weight' => 1000, /* db table prefix */ 'datetimeformat' => 'Y-m-d H:i:s', ], @@ -81,9 +84,9 @@ $CONFIG = [ 'db' => 'mysql', /* db type */ 'host' => '127.0.0.1', /* db host address */ 'port' => '3306', /* db host port */ - 'login' => 'root', /* db login name */ - 'password' => 'root', /* db login password */ - 'database' => 'oms', /* db name */ + 'login' => 'test', /* db login name */ + 'password' => 'orange', /* db login password */ + 'database' => 'omt', /* db name */ 'weight' => 1000, /* db table prefix */ 'datetimeformat' => 'Y-m-d H:i:s', ], @@ -91,9 +94,9 @@ $CONFIG = [ 'db' => 'mysql', /* db type */ 'host' => '127.0.0.1', /* db host address */ 'port' => '3306', /* db host port */ - 'login' => 'root', /* db login name */ - 'password' => 'root', /* db login password */ - 'database' => 'oms', /* db name */ + 'login' => 'test', /* db login name */ + 'password' => 'orange', /* db login password */ + 'database' => 'omt', /* db name */ 'weight' => 1000, /* db table prefix */ 'datetimeformat' => 'Y-m-d H:i:s', ], @@ -101,9 +104,9 @@ $CONFIG = [ 'db' => 'mysql', /* db type */ 'host' => '127.0.0.1', /* db host address */ 'port' => '3306', /* db host port */ - 'login' => 'root', /* db login name */ - 'password' => 'root', /* db login password */ - 'database' => 'oms', /* db name */ + 'login' => 'test', /* db login name */ + 'password' => 'orange', /* db login password */ + 'database' => 'omt', /* db name */ 'weight' => 1000, /* db table prefix */ 'datetimeformat' => 'Y-m-d H:i:s', ], @@ -111,9 +114,9 @@ $CONFIG = [ 'db' => 'mysql', /* db type */ 'host' => '127.0.0.1', /* db host address */ 'port' => '3306', /* db host port */ - 'login' => 'root', /* db login name */ - 'password' => 'root', /* db login password */ - 'database' => 'oms', /* db name */ + 'login' => 'test', /* db login name */ + 'password' => 'orange', /* db login password */ + 'database' => 'omt', /* db name */ 'weight' => 1000, /* db table prefix */ 'datetimeformat' => 'Y-m-d H:i:s', ], @@ -121,9 +124,9 @@ $CONFIG = [ 'db' => 'mysql', /* db type */ 'host' => '127.0.0.1', /* db host address */ 'port' => '3306', /* db host port */ - 'login' => 'root', /* db login name */ - 'password' => 'root', /* db login password */ - 'database' => 'oms', /* db name */ + 'login' => 'test', /* db login name */ + 'password' => 'orange', /* db login password */ + 'database' => 'omt', /* db name */ 'weight' => 1000, /* db table prefix */ 'datetimeformat' => 'Y-m-d H:i:s', ], @@ -133,9 +136,9 @@ $CONFIG = [ 'db' => 'pgsql', /* db type */ 'host' => '127.0.0.1', /* db host address */ 'port' => '5432', /* db host port */ - 'login' => 'postgres', /* db login name */ - 'password' => 'root', /* db login password */ - 'database' => 'oms', /* db name */ + 'login' => 'test', /* db login name */ + 'password' => 'orange', /* db login password */ + 'database' => 'omt', /* db name */ 'weight' => 1000, /* db table prefix */ 'datetimeformat' => 'Y-m-d H:i:s', ], @@ -143,9 +146,9 @@ $CONFIG = [ 'db' => 'pgsql', /* db type */ 'host' => '127.0.0.1', /* db host address */ 'port' => '5432', /* db host port */ - 'login' => 'postgres', /* db login name */ - 'password' => 'root', /* db login password */ - 'database' => 'oms', /* db name */ + 'login' => 'test', /* db login name */ + 'password' => 'orange', /* db login password */ + 'database' => 'omt', /* db name */ 'weight' => 1000, /* db table prefix */ 'datetimeformat' => 'Y-m-d H:i:s', ], @@ -153,9 +156,9 @@ $CONFIG = [ 'db' => 'pgsql', /* db type */ 'host' => '127.0.0.1', /* db host address */ 'port' => '5432', /* db host port */ - 'login' => 'postgres', /* db login name */ - 'password' => 'root', /* db login password */ - 'database' => 'oms', /* db name */ + 'login' => 'test', /* db login name */ + 'password' => 'orange', /* db login password */ + 'database' => 'omt', /* db name */ 'weight' => 1000, /* db table prefix */ 'datetimeformat' => 'Y-m-d H:i:s', ], @@ -163,9 +166,9 @@ $CONFIG = [ 'db' => 'pgsql', /* db type */ 'host' => '127.0.0.1', /* db host address */ 'port' => '5432', /* db host port */ - 'login' => 'postgres', /* db login name */ - 'password' => 'root', /* db login password */ - 'database' => 'oms', /* db name */ + 'login' => 'test', /* db login name */ + 'password' => 'orange', /* db login password */ + 'database' => 'omt', /* db name */ 'weight' => 1000, /* db table prefix */ 'datetimeformat' => 'Y-m-d H:i:s', ], @@ -173,9 +176,9 @@ $CONFIG = [ 'db' => 'pgsql', /* db type */ 'host' => '127.0.0.1', /* db host address */ 'port' => '5432', /* db host port */ - 'login' => 'postgres', /* db login name */ - 'password' => 'root', /* db login password */ - 'database' => 'oms', /* db name */ + 'login' => 'test', /* db login name */ + 'password' => 'orange', /* db login password */ + 'database' => 'omt', /* db name */ 'weight' => 1000, /* db table prefix */ 'datetimeformat' => 'Y-m-d H:i:s', ], @@ -183,9 +186,9 @@ $CONFIG = [ 'db' => 'pgsql', /* db type */ 'host' => '127.0.0.1', /* db host address */ 'port' => '5432', /* db host port */ - 'login' => 'postgres', /* db login name */ - 'password' => 'root', /* db login password */ - 'database' => 'oms', /* db name */ + 'login' => 'test', /* db login name */ + 'password' => 'orange', /* db login password */ + 'database' => 'omt', /* db name */ 'weight' => 1000, /* db table prefix */ 'datetimeformat' => 'Y-m-d H:i:s', ], @@ -233,9 +236,9 @@ $CONFIG = [ 'db' => 'mssql', /* db type */ 'host' => 'localhost', /* db host address */ 'port' => '1433', /* db host port */ - 'login' => 'sa', /* db login name */ - 'password' => 'c0MplicatedP@ssword', /* db login password */ - 'database' => 'oms', /* db name */ + 'login' => 'test', /* db login name */ + 'password' => 'orange', /* db login password */ + 'database' => 'omt', /* db name */ 'weight' => 1000, /* db table prefix */ 'datetimeformat' => 'Y-m-d H:i:s', ], @@ -243,9 +246,9 @@ $CONFIG = [ 'db' => 'mssql', /* db type */ 'host' => 'localhost', /* db host address */ 'port' => '1433', /* db host port */ - 'login' => 'sa', /* db login name */ - 'password' => 'c0MplicatedP@ssword', /* db login password */ - 'database' => 'oms', /* db name */ + 'login' => 'test', /* db login name */ + 'password' => 'orange', /* db login password */ + 'database' => 'omt', /* db name */ 'weight' => 1000, /* db table prefix */ 'datetimeformat' => 'Y-m-d H:i:s', ], @@ -253,9 +256,9 @@ $CONFIG = [ 'db' => 'mssql', /* db type */ 'host' => 'localhost', /* db host address */ 'port' => '1433', /* db host port */ - 'login' => 'sa', /* db login name */ - 'password' => 'c0MplicatedP@ssword', /* db login password */ - 'database' => 'oms', /* db name */ + 'login' => 'test', /* db login name */ + 'password' => 'orange', /* db login password */ + 'database' => 'omt', /* db name */ 'weight' => 1000, /* db table prefix */ 'datetimeformat' => 'Y-m-d H:i:s', ], @@ -263,9 +266,9 @@ $CONFIG = [ 'db' => 'mssql', /* db type */ 'host' => 'localhost', /* db host address */ 'port' => '1433', /* db host port */ - 'login' => 'sa', /* db login name */ - 'password' => 'c0MplicatedP@ssword', /* db login password */ - 'database' => 'oms', /* db name */ + 'login' => 'test', /* db login name */ + 'password' => 'orange', /* db login password */ + 'database' => 'omt', /* db name */ 'weight' => 1000, /* db table prefix */ 'datetimeformat' => 'Y-m-d H:i:s', ], @@ -273,9 +276,9 @@ $CONFIG = [ 'db' => 'mssql', /* db type */ 'host' => 'localhost', /* db host address */ 'port' => '1433', /* db host port */ - 'login' => 'sa', /* db login name */ - 'password' => 'c0MplicatedP@ssword', /* db login password */ - 'database' => 'oms', /* db name */ + 'login' => 'test', /* db login name */ + 'password' => 'orange', /* db login password */ + 'database' => 'omt', /* db name */ 'weight' => 1000, /* db table prefix */ 'datetimeformat' => 'Y-m-d H:i:s', ], @@ -283,9 +286,9 @@ $CONFIG = [ 'db' => 'mssql', /* db type */ 'host' => 'localhost', /* db host address */ 'port' => '1433', /* db host port */ - 'login' => 'sa', /* db login name */ - 'password' => 'c0MplicatedP@ssword', /* db login password */ - 'database' => 'oms', /* db name */ + 'login' => 'test', /* db login name */ + 'password' => 'orange', /* db login password */ + 'database' => 'omt', /* db name */ 'weight' => 1000, /* db table prefix */ 'datetimeformat' => 'Y-m-d H:i:s', ], diff --git a/tests/Socket/Client/ClientTestHelper.php b/tests/Socket/Client/ClientTestHelper.php index 7a7dfe45c..84700ab90 100755 --- a/tests/Socket/Client/ClientTestHelper.php +++ b/tests/Socket/Client/ClientTestHelper.php @@ -8,7 +8,7 @@ * @copyright Dennis Eichhorn * @license OMS License 2.0 * @version 1.0.0 - * @link http://karaka.com + * @link https://jingga.app */ declare(strict_types=1); diff --git a/tests/Socket/Server/ServerTestHelper.php b/tests/Socket/Server/ServerTestHelper.php index 69e36e4a7..0245e7148 100755 --- a/tests/Socket/Server/ServerTestHelper.php +++ b/tests/Socket/Server/ServerTestHelper.php @@ -8,7 +8,7 @@ * @copyright Dennis Eichhorn * @license OMS License 2.0 * @version 1.0.0 - * @link http://karaka.com + * @link https://jingga.app */ declare(strict_types=1); diff --git a/tests/phpunit_default.xml b/tests/phpunit_default.xml index 9399ff8ae..9a4659aba 100644 --- a/tests/phpunit_default.xml +++ b/tests/phpunit_default.xml @@ -1,17 +1,30 @@ + + ../ + + ../vendor* + ../MainRepository* + ../Karaka* + ../Admin/Install/Application* + ../phpOMS* + ../tests* ../*/tests* + ../**/tests* + */tests* ../* ../* ../* - ./Build - ./Resources - *vendor* - *Testapp* - ./vendor - ../vendor + ../* + ../* + ../**/test* + ../**/Theme* + ../**/Admin/Routes* + ../**/Admin/Hooks* + ../**/Admin/Install* + ../Media/Files* ../Localization/LanguageDetection/resources