Skip to content
This repository has been archived by the owner on Oct 28, 2022. It is now read-only.

WIP: Adding mapping for relationships & support for advanced design patterns #2

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
},
"require-dev": {
"phpunit/phpunit": "^8.0",
"mnapoli/hard-mode": "^0.1.1"
"mnapoli/hard-mode": "^0.1.1",
"ramsey/uuid": "^3.8"
}
}
38 changes: 38 additions & 0 deletions src/EntityManager/EntityManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php declare(strict_types=1);

namespace Dynamap\EntityManager;

use Aws\DynamoDb\DynamoDbClient;
use Dynamap\Serializer\EntitySerializer;

final class EntityManager
{
/** @var DynamoDbClient */
private $client;
/** @var EntitySerializer */
private $serializer;

public function __construct(DynamoDbClient $client, EntitySerializer $serializer)
{
$this->client = $client;

$this->serializer = $serializer;
}

public function persist($entity): void
{
}

public function fetch($entity): object
{
}

public function delete($entity): void
{
}

// create
// read
// update
// delete
}
103 changes: 103 additions & 0 deletions src/Mapping/ClassMapping.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php declare(strict_types=1);

namespace Dynamap\Mapping;

use Dynamap\Mapping\Exception\CannotMapNonExistentFieldException;
use Dynamap\Mapping\Exception\ClassNameInvalidException;
use Dynamap\Mapping\Exception\MappingNotFoundException;
use Dynamap\Mapping\Exception\NoFieldsMappedForClassException;
use Dynamap\Mapping\Field\DynamoDBField;

class ClassMapping
{
/** @var string */
private $tableName;
/** @var string */
private $className;
/** @var array */
private $mapping;

private function __construct(string $tableName, string $className, array $config)
{
$this->className = $className;
$this->mapping = $config;
$this->tableName = $tableName;
}

public static function fromArray(string $tableName, string $className, array $config): ClassMapping
{
if (\class_exists($className) === false) {
throw new ClassNameInvalidException('Could not map ' . $className . ' as the class was not found');
}

if (empty($config['fields']) === false) {
$fields = self::mapProperties($className, $config['fields']);

$config['fields'] = $fields;
}

return new static($tableName, $className, $config);
}

public function getClassName(): string
{
return $this->className;
}

public function getTableName(): string
{
return $this->tableName;
}

public function getMappedProperty(string $propertyName): DynamoDBField
{
if (empty($this->mapping['fields']) === true) { // todo: add a test for this
throw new NoFieldsMappedForClassException('You have tried to access mapping for a class which has no mapped properties');
}

if ($this->hasMappedProperty($propertyName) === false) {
throw new MappingNotFoundException('Mapping for ' . $propertyName . ' could not be found');
}

return $this->mapping['fields'][$propertyName];
}

public function hasMappedProperty(string $propertyName): bool
{
// todo: add a test for this
if (\array_key_exists('fields', $this->mapping) === false) {
return false;
}

return \array_key_exists($propertyName, $this->mapping['fields']);
}

/**
* @param array $fields
* @return array
* @throws CannotMapNonExistentFieldException
* @throws \ReflectionException
*/
private static function mapProperties(string $className, array $fields): array
{
$reflection = new \ReflectionClass($className);

$classProperties = array_reduce($reflection->getProperties(), static function ($carry, $item) {
$carry[] = $item->getName();
return $carry;
}, []);

$mappedFields = [];
$factory = new FieldMappingFactory;

foreach ($fields as $classField => $type) {
if (\in_array($classField, $classProperties, false) === false) {
throw new CannotMapNonExistentFieldException('The field ' . $classField . ' does not exist in ' . $className);
}

$mappedFields[$classField] = $factory->getDynamoDbType($type);
}

return $mappedFields;
}
}
7 changes: 7 additions & 0 deletions src/Mapping/Exception/CannotMapNonExistentFieldException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php declare(strict_types=1);

namespace Dynamap\Mapping\Exception;

class CannotMapNonExistentFieldException extends \Exception
{
}
7 changes: 7 additions & 0 deletions src/Mapping/Exception/ClassNameInvalidException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php declare(strict_types=1);

namespace Dynamap\Mapping\Exception;

class ClassNameInvalidException extends \Exception
{
}
7 changes: 7 additions & 0 deletions src/Mapping/Exception/MappingNotFoundException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php declare(strict_types=1);

namespace Dynamap\Mapping\Exception;

class MappingNotFoundException extends \Exception
{
}
7 changes: 7 additions & 0 deletions src/Mapping/Exception/MappingNotSpecifiedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php declare(strict_types=1);

namespace Dynamap\Mapping\Exception;

class MappingNotSpecifiedException extends \Exception
{
}
7 changes: 7 additions & 0 deletions src/Mapping/Exception/NoFieldsMappedForClassException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php declare(strict_types=1);

namespace Dynamap\Mapping\Exception;

class NoFieldsMappedForClassException extends \Exception
{
}
7 changes: 7 additions & 0 deletions src/Mapping/Exception/NoTableSpeficiedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php declare(strict_types=1);

namespace Dynamap\Mapping\Exception;

class NoTableSpeficiedException extends \Exception
{
}
7 changes: 7 additions & 0 deletions src/Mapping/Exception/TableNameNotSpecifiedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php declare(strict_types=1);

namespace Dynamap\Mapping\Exception;

class TableNameNotSpecifiedException extends \Exception
{
}
26 changes: 26 additions & 0 deletions src/Mapping/Field/BooleanField.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php declare(strict_types=1);

namespace Dynamap\Mapping\Field;

class BooleanField implements DynamoDBField
{
public function getDynamoDBFieldType(): string
{
return 'BOOL';
}

public function getOriginalFieldType(): string
{
return 'boolean';
}

public function castToDynamoDBType($value): bool
{
return $value;
}

public function restoreFromDynamoDBType($value): bool
{
return (bool) $value;
}
}
34 changes: 34 additions & 0 deletions src/Mapping/Field/DateTimeField.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php declare(strict_types=1);

namespace Dynamap\Mapping\Field;

class DateTimeField implements DynamoDBField
{
/** @var string */
private $originalFieldType;

public function __construct(string $originalFieldType)
{
$this->originalFieldType = $originalFieldType;
}

public function getDynamoDBFieldType(): string
{
return 'S';
}

public function getOriginalFieldType(): string
{
return $this->originalFieldType;
}

public function castToDynamoDBType($value)
{
return $value->format(\DateTime::ATOM);
}

public function restoreFromDynamoDBType($value): \DateTimeInterface
{
return \DateTime::createFromFormat(\DateTime::ATOM, $value);
}
}
14 changes: 14 additions & 0 deletions src/Mapping/Field/DynamoDBField.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php declare(strict_types=1);

namespace Dynamap\Mapping\Field;

interface DynamoDBField
{
public function getOriginalFieldType(): string;

public function getDynamoDBFieldType(): string;

public function castToDynamoDBType($value);

public function restoreFromDynamoDBType($value);
}
34 changes: 34 additions & 0 deletions src/Mapping/Field/NumberField.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php declare(strict_types=1);

namespace Dynamap\Mapping\Field;

class NumberField implements DynamoDBField
{
/** @var string */
private $originalFieldType;

public function __construct(string $originalFieldType)
{
$this->originalFieldType = $originalFieldType;
}

public function getDynamoDBFieldType(): string
{
return 'N';
}

public function getOriginalFieldType(): string
{
return $this->originalFieldType;
}

public function castToDynamoDBType($value)
{
return $value;
}

public function restoreFromDynamoDBType($value)
{
return $value;
}
}
40 changes: 40 additions & 0 deletions src/Mapping/Field/StringField.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php declare(strict_types=1);

namespace Dynamap\Mapping\Field;

use Ramsey\Uuid\Uuid;

class StringField implements DynamoDBField
{
/** @var string */
private $originalFieldType;

public function __construct(string $originalFieldType)
{
$this->originalFieldType = $originalFieldType;
}

public function getDynamoDBFieldType(): string
{
return 'S';
}

public function getOriginalFieldType(): string
{
return $this->originalFieldType;
}

public function castToDynamoDBType($value): string
{
return (string)$value;
}

public function restoreFromDynamoDBType($value)
{
if ('uuid' === $this->originalFieldType) {
return Uuid::fromString($value);
}

return (string)$value;
}
}
34 changes: 34 additions & 0 deletions src/Mapping/FieldMappingFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php declare(strict_types=1);

namespace Dynamap\Mapping;

use Dynamap\Mapping\Field\BooleanField;
use Dynamap\Mapping\Field\DateTimeField;
use Dynamap\Mapping\Field\DynamoDBField;
use Dynamap\Mapping\Field\NumberField;
use Dynamap\Mapping\Field\StringField;

class FieldMappingFactory
{
public function getDynamoDBType(string $propertyType): DynamoDBField
{
switch (strtolower($propertyType)) {
case 'uuid':
case 'string':
return new StringField($propertyType);
break;
case 'float':
case 'integer':
return new NumberField($propertyType);
break;
case 'boolean':
return new BooleanField;
break;
case 'datetime':
return new DateTimeField($propertyType);
break;
default: // todo: add a test for this
throw new InvalidMappingTypeException;
}
}
}
Loading