Merge pull request #329 from Karaka-Management/feature-mapper-reflectionless

Feature mapper reflectionless
This commit is contained in:
Dennis Eichhorn 2023-10-04 17:27:13 +02:00 committed by GitHub
commit a3f4d61b6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 337 additions and 216 deletions

View File

@ -8,3 +8,4 @@ jobs:
secrets:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_PAT: ${{ secrets.GH_PAT }}
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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});

View File

@ -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<DataMapperFactory> $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;

View File

@ -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<DataMapperFactory> $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<DataMapperFactory> $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);

View File

@ -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;

View File

@ -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',
],

View File

@ -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);

View File

@ -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);

View File

@ -1,17 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="Bootstrap.php" colors="true" columns="120" stopOnError="true" stopOnFailure="false" stopOnIncomplete="false" stopOnSkipped="false" beStrictAboutTestsThatDoNotTestAnything="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage includeUncoveredFiles="true" processUncoveredFiles="false">
<include>
<directory suffix=".php">../</directory>
</include>
<exclude>
<directory>../vendor*</directory>
<directory>../MainRepository*</directory>
<directory>../Karaka*</directory>
<directory>../Admin/Install/Application*</directory>
<directory>../phpOMS*</directory>
<directory>../tests*</directory>
<directory>../*/tests*</directory>
<directory>../**/tests*</directory>
<directory>*/tests*</directory>
<directory suffix="tpl.php">../*</directory>
<directory suffix="lang.php">../*</directory>
<directory suffix="Test.php">../*</directory>
<directory>./Build</directory>
<directory>./Resources</directory>
<directory>*vendor*</directory>
<directory>*Testapp*</directory>
<directory>./vendor</directory>
<directory>../vendor</directory>
<directory suffix="Routes.php">../*</directory>
<directory suffix="Hooks.php">../*</directory>
<directory>../**/test*</directory>
<directory>../**/Theme*</directory>
<directory>../**/Admin/Routes*</directory>
<directory>../**/Admin/Hooks*</directory>
<directory>../**/Admin/Install*</directory>
<directory>../Media/Files*</directory>
<directory>../Localization/LanguageDetection/resources</directory>
</exclude>
<report>