Skip to content

Commit

Permalink
extract the redis client and inject it into the object manager
Browse files Browse the repository at this point in the history
  • Loading branch information
Marc Lemay committed Aug 30, 2024
1 parent 692e161 commit 7286fdf
Show file tree
Hide file tree
Showing 37 changed files with 463 additions and 304 deletions.
7 changes: 6 additions & 1 deletion src/Client/PredisClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ public function search(string $prefixKey, array $search, array $orderBy, ?string
return [];
}

return $this->extractRedisData($result, $format, $numberOfResults);
return $this->extractRedisData((array)$result, $format, $numberOfResults);
}

/**
Expand Down Expand Up @@ -361,6 +361,11 @@ public function searchLike(string $prefixKey, string $search, ?string $format =
return [];
}

if (!is_array($result)) {
$this->handleError(RedisCommands::SEARCH->value, 'Unexpected result type from Redis: ' . gettype($result));
return [];
}

return $this->extractRedisData($result, $format, $numberOfResults);
}

Expand Down
5 changes: 3 additions & 2 deletions src/Client/RedisClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ public function jsonDel(string $key, ?string $path = '$'): void
/**
* @inheritdoc
*/
public function createIndex(string $prefixKey, ?string $format = RedisFormat::HASH->value, ?array $properties = []): void
public function createIndex(string $prefixKey, string $format = RedisFormat::HASH->value, ?array $properties = []): void
{
if ($properties === []) {
return;
Expand Down Expand Up @@ -188,6 +188,7 @@ public function createIndex(string $prefixKey, ?string $format = RedisFormat::HA
throw new BadPropertyConfigurationException(sprintf('Your class %s does not have any typed property', $prefixKey));
}


if (!call_user_func_array([$this->redis, 'rawCommand'], $arguments)) {
$this->handleError(__METHOD__, $this->redis->getLastError());
}
Expand Down Expand Up @@ -225,7 +226,7 @@ public function count(string $prefixKey, array $criterias = []): int
$this->handleError(__METHOD__, $this->redis->getLastError());
}

return (int) $rawResult[0];
return (int)$rawResult[0];
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Client/RedisClientInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public function jsonDel(string $key, ?string $path = '$'): void;
* Create index for objects by properties.
* @param PropertyToIndex[] $properties
*/
public function createIndex(string $prefixKey, ?string $format = 'HASH', ?array $properties = []): void;
public function createIndex(string $prefixKey, string $format = 'HASH', ?array $properties = []): void;

/**
* Remove all index for given prefix key.
Expand Down
29 changes: 17 additions & 12 deletions src/Command/GenerateSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,25 @@

declare(strict_types=1);

namespace Talleu\RedisOm\Command;
namespace Talleu\RedisOm\Command;

use Talleu\RedisOm\Client\PredisClient;
use Talleu\RedisOm\Client\RedisClient;
use Talleu\RedisOm\Exception\BadIdentifierConfigurationException;
use Talleu\RedisOm\Om\Converters\AbstractDateTimeConverter;
use Talleu\RedisOm\Om\Mapping\Entity;
use Talleu\RedisOm\Om\Mapping\Id;
use Talleu\RedisOm\Om\Mapping\Property;
use Talleu\RedisOm\Om\RedisFormat;
use Talleu\RedisOm\Om\RedisObjectManager;

final class GenerateSchema
{
public static function generateSchema(string $dir): void
{
$redisOm = new RedisObjectManager(
getenv('REDIS_CLIENT') === 'predis' ? new PredisClient() : new RedisClient(),
);
$rii = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir));
$phpFiles = [];

Expand Down Expand Up @@ -46,7 +52,7 @@ public static function generateSchema(string $dir): void

/** @var Entity $entity */
$entity = $attributes[0]->newInstance();
$entity->redisClient->dropIndex($entity->prefix ?? $fqcn);
$redisOm->dropIndex($entity, $fqcn);
$format = $entity->format ?? RedisFormat::HASH->value;

$idExist = false;
Expand Down Expand Up @@ -100,16 +106,16 @@ public static function generateSchema(string $dir): void
if (in_array($propertyType, AbstractDateTimeConverter::DATETYPES_NAMES)) {
if ($format === RedisFormat::HASH->value) {
$propertiesToIndex[] = new PropertyToIndex("$propertyName#timestamp", $propertyName, Property::INDEX_TAG);
$propertiesToIndex[] = new PropertyToIndex("$propertyName#timestamp", $propertyName.'_text', Property::INDEX_TEXT);
$propertiesToIndex[] = new PropertyToIndex("$propertyName#timestamp", $propertyName . '_text', Property::INDEX_TEXT);
} else {
$propertiesToIndex[] = new PropertyToIndex('$.'. "$propertyName.timestamp", $propertyName, Property::INDEX_TAG);
$propertiesToIndex[] = new PropertyToIndex('$.'. "$propertyName.timestamp", $propertyName."_text", Property::INDEX_TEXT);
$propertiesToIndex[] = new PropertyToIndex('$.' . "$propertyName.timestamp", $propertyName, Property::INDEX_TAG);
$propertiesToIndex[] = new PropertyToIndex('$.' . "$propertyName.timestamp", $propertyName . "_text", Property::INDEX_TEXT);
}
} elseif ($propertyType === 'int' || $propertyType === 'float') {
if ($format === RedisFormat::HASH->value) {
$propertiesToIndex[] = new PropertyToIndex($propertyName, $propertyName, Property::INDEX_TAG);
} else {
$propertiesToIndex[] = new PropertyToIndex('$.'.$propertyName, $propertyName, Property::INDEX_TAG);
$propertiesToIndex[] = new PropertyToIndex('$.' . $propertyName, $propertyName, Property::INDEX_TAG);
}
} elseif (class_exists($propertyType)) {
$subReflectionClass = new \ReflectionClass($propertyType);
Expand Down Expand Up @@ -137,20 +143,19 @@ public static function generateSchema(string $dir): void
continue;
}

$propertiesToIndex[] = new PropertyToIndex(($format === RedisFormat::JSON->value ? '$.' : '')."$propertyName.$subPropertyName", $propertyName.'_'.$subPropertyName.'_text', Property::INDEX_TEXT);
$propertiesToIndex[] = new PropertyToIndex(($format === RedisFormat::JSON->value ? '$.' : ''). "$propertyName.$subPropertyName", $propertyName.'_'.$subPropertyName, Property::INDEX_TAG);
$propertiesToIndex[] = new PropertyToIndex(($format === RedisFormat::JSON->value ? '$.' : '') . "$propertyName.$subPropertyName", $propertyName . '_' . $subPropertyName . '_text', Property::INDEX_TEXT);
$propertiesToIndex[] = new PropertyToIndex(($format === RedisFormat::JSON->value ? '$.' : '') . "$propertyName.$subPropertyName", $propertyName . '_' . $subPropertyName, Property::INDEX_TAG);
}
} else {
$propertiesToIndex[] = new PropertyToIndex(($format === RedisFormat::JSON->value ? '$.' : '').$propertyName, $propertyName, Property::INDEX_TAG);
$propertiesToIndex[] = new PropertyToIndex(($format === RedisFormat::JSON->value ? '$.' : '').$propertyName, $propertyName.'_text', Property::INDEX_TEXT);
$propertiesToIndex[] = new PropertyToIndex(($format === RedisFormat::JSON->value ? '$.' : '') . $propertyName, $propertyName, Property::INDEX_TAG);
$propertiesToIndex[] = new PropertyToIndex(($format === RedisFormat::JSON->value ? '$.' : '') . $propertyName, $propertyName . '_text', Property::INDEX_TEXT);
}
}

if (!$idExist) {
throw new BadIdentifierConfigurationException("No identifier found for $fqcn, or identifier is not mapped by RedisOm");
}

$entity->redisClient->createIndex($entity->prefix ?? $fqcn, $format, $propertiesToIndex);
$redisOm->createIndex($entity, $fqcn, $propertiesToIndex);
}
}

Expand Down
1 change: 1 addition & 0 deletions src/Om/Key/KeyGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public function generateKey(Entity $redisEntity, object &$object): string
$identifierProperty = $this->getIdentifier(new \ReflectionClass($object));

$identifierValue = $object->{$identifierProperty->getName()};

if (!$identifierValue) {
$identifierValue = uniqid();
/** @var \ReflectionNamedType|null $propertyType */
Expand Down
18 changes: 4 additions & 14 deletions src/Om/Mapping/Entity.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,9 @@
namespace Talleu\RedisOm\Om\Mapping;

use Attribute;
use Talleu\RedisOm\Client\RedisClient;
use Talleu\RedisOm\Client\RedisClientInterface;
use Talleu\RedisOm\Om\Converters\ConverterInterface;
use Talleu\RedisOm\Om\Converters\HashModel\HashObjectConverter;
use Talleu\RedisOm\Om\Converters\JsonModel\JsonObjectConverter;
use Talleu\RedisOm\Om\Persister\HashModel\HashPersister;
use Talleu\RedisOm\Om\Persister\JsonModel\JsonPersister;
use Talleu\RedisOm\Om\Persister\PersisterInterface;
use Talleu\RedisOm\Om\RedisFormat;
use Talleu\RedisOm\Om\Repository\HashModel\HashRepository;
use Talleu\RedisOm\Om\Repository\JsonModel\JsonRepository;
Expand All @@ -22,17 +17,12 @@
final class Entity
{
public function __construct(
public ?string $prefix = null,
public ?string $format = null,
public ?PersisterInterface $persister = null,
public ?ConverterInterface $converter = null,
public ?RepositoryInterface $repository = null,
public ?RedisClientInterface $redisClient = null,
public ?string $prefix = null,
public ?string $format = null,
public ?ConverterInterface $converter = null,
public ?RepositoryInterface $repository = null,
) {
$this->persister = $persister ?? ($format === RedisFormat::JSON->value ? new JsonPersister(redis: $this->redisClient) : new HashPersister(redis: $this->redisClient));
$this->converter = $converter ?? ($format === RedisFormat::JSON->value ? new JsonObjectConverter() : new HashObjectConverter());
$this->repository = $repository ?? ($format === RedisFormat::JSON->value ? new JsonRepository() : new HashRepository());
$this->redisClient !== null ?? $this->repository->setRedisClient($this->redisClient);
$this->redisClient = $redisClient ?? (new RedisClient());
}
}
5 changes: 2 additions & 3 deletions src/Om/Persister/AbstractPersister.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public function persist(Entity $objectMapper, $object): ObjectToPersist
$key = $this->keyGenerator->generateKey($objectMapper, $object);

return new ObjectToPersist(
persisterClass: get_class($objectMapper->persister),
persisterClass: get_class($this),
operation: PersisterOperations::OPERATION_PERSIST->value,
redisKey: $key,
converter: $objectMapper->converter,
Expand All @@ -37,9 +37,8 @@ public function delete(Entity $objectMapper, $object): ObjectToPersist
{
$identifier = $this->keyGenerator->getIdentifier(new \ReflectionClass($object));
$key = sprintf('%s:%s', $objectMapper->prefix ?: get_class($object), $object->{$identifier->getName()});

return new ObjectToPersist(
persisterClass: get_class($objectMapper->persister),
persisterClass: get_class($this),
operation: PersisterOperations::OPERATION_DELETE->value,
redisKey: $key,
);
Expand Down
51 changes: 30 additions & 21 deletions src/Om/RedisObjectManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@

namespace Talleu\RedisOm\Om;

use Talleu\RedisOm\Client\RedisClient;
use Talleu\RedisOm\Exception\RedisOmInvalidArgumentException;
use Talleu\RedisOm\Client\RedisClientInterface;
use Talleu\RedisOm\Om\Converters\HashModel\HashObjectConverter;
use Talleu\RedisOm\Om\Converters\JsonModel\JsonObjectConverter;
use Talleu\RedisOm\Om\Key\KeyGenerator;
use Talleu\RedisOm\Om\Mapping\Entity;
use Talleu\RedisOm\Om\Metadata\ClassMetadata;
use Talleu\RedisOm\Om\Metadata\MetadataFactory;
use Talleu\RedisOm\Om\Persister\HashModel\HashPersister;
use Talleu\RedisOm\Om\Persister\JsonModel\JsonPersister;
use Talleu\RedisOm\Om\Persister\ObjectToPersist;
use Talleu\RedisOm\Om\Persister\PersisterInterface;
use Talleu\RedisOm\Om\Repository\RepositoryInterface;
Expand All @@ -25,8 +26,10 @@ final class RedisObjectManager implements RedisObjectManagerInterface
protected array $objectsToFlush = [];
protected ?KeyGenerator $keyGenerator = null;

public function __construct(private readonly ?bool $createPersistentConnection = null)
{
public function __construct(
private readonly ?RedisClientInterface $redisClient,
private readonly ?PersisterInterface $persister = null,
) {
$this->keyGenerator = new KeyGenerator();
}

Expand All @@ -36,7 +39,7 @@ public function __construct(private readonly ?bool $createPersistentConnection =
public function persist(object $object): void
{
$objectMapper = $this->getEntityMapper($object);
$persister = $this->registerPersister($objectMapper, $object);
$persister = $this->registerPersister($objectMapper);

$objectToPersist = $persister->persist($objectMapper, $object);
$this->objectsToFlush[$objectToPersist->persisterClass][$objectToPersist->operation][$objectToPersist->redisKey] = $objectToPersist;
Expand All @@ -48,7 +51,7 @@ public function persist(object $object): void
public function remove(object $object): void
{
$objectMapper = $this->getEntityMapper($object);
$persister = $this->registerPersister($objectMapper, $object);
$persister = $this->registerPersister($objectMapper);

$objectToRemove = $persister->delete($objectMapper, $object);
$this->objectsToFlush[$objectToRemove->persisterClass][$objectToRemove->operation][$objectToRemove->redisKey] = $objectToRemove;
Expand All @@ -74,7 +77,7 @@ public function find(string $className, $id): ?object
{
$objectMapper = $this->getEntityMapper($className);

return $objectMapper->repository->find((string) $id);
return $objectMapper->repository->find((string)$id);
}

/**
Expand All @@ -94,7 +97,7 @@ public function detach(object $object): void
$objectMapper = $this->getEntityMapper($object);
$key = sprintf('%s:%s', $objectMapper->prefix ?: get_class($object), $object->{$identifier->getName()});

$persisterClassName = get_class($objectMapper->persister);
$persisterClassName = get_class($this->registerPersister($object));
foreach ($this->objectsToFlush[$persisterClassName] as $operation => $objectsToFlush) {
foreach ($objectsToFlush as $redisKey => $objectToFlush) {
if ($redisKey === $key) {
Expand All @@ -112,7 +115,7 @@ public function refresh(object $object): object
$objectMapper = $this->getEntityMapper($object);
$identifierProperty = $this->keyGenerator->getIdentifier(new \ReflectionClass($object));

return $objectMapper->repository->find($objectMapper->prefix.':'.$object->{$identifierProperty->getName()});
return $objectMapper->repository->find($objectMapper->prefix . ':' . $object->{$identifierProperty->getName()});
}

/**
Expand Down Expand Up @@ -157,7 +160,7 @@ public function contains(object $object): bool
$identifier = $this->keyGenerator->getIdentifier(new \ReflectionClass($object));
$objectMapper = $this->getEntityMapper($object);
$key = sprintf('%s:%s', $objectMapper->prefix ?: get_class($object), $object->{$identifier->getName()});
$persisterClassName = get_class($objectMapper->persister);
$persisterClassName = get_class($this->registerPersister($object));
foreach ($this->objectsToFlush[$persisterClassName] as $operation => $objectsToFlush) {
foreach ($objectsToFlush as $redisKey => $objectToFlush) {
if ($redisKey === $key) {
Expand All @@ -184,27 +187,33 @@ protected function getEntityMapper(string|object $object): Entity
$redisEntity->repository->setClassName($reflectionClass->getName());
$redisEntity->repository->setConverter($redisEntity->converter ?? ($redisEntity->format === RedisFormat::HASH->value ? new HashObjectConverter() : new JsonObjectConverter()));

$redisClient = $redisEntity->redisClient ?? new RedisClient();
if ($this->createPersistentConnection === true) {
$redisClient->createPersistentConnection();
}
$redisEntity->repository->setRedisClient($redisClient);
$redisEntity->repository->setRedisClient($this->redisClient);
$redisEntity->repository->setFormat($redisEntity->format);

return $redisEntity;
}

protected function registerPersister(Entity $redisEntity, object $object): PersisterInterface
protected function registerPersister(object $object): PersisterInterface
{
if (is_null($persister = $redisEntity->persister)) {
throw new RedisOmInvalidArgumentException(sprintf('No persister found for %s object.', get_class($object)));
}
$persister = ($object->format === RedisFormat::JSON->value ? new JsonPersister(redis: $this->redisClient) : new HashPersister(redis: $this->redisClient));


$persisterClass = get_class($persister);
$persisterClass = $persister::class;
if (!array_key_exists($persisterClass, $this->persisters)) {
$this->persisters[$persisterClass] = $persister;
}

return $persister;
}

public function createIndex(object $object, string $fqcn = null, array $propertiesToIndex = []): void
{
$this->redisClient->createIndex($object->prefix ?? $fqcn, $object->format ?? RedisFormat::HASH->value, $propertiesToIndex);
}

public function dropIndex(object $object, string $fqcn = null): void
{
$this->redisClient->dropIndex($object->prefix ?? $fqcn);
}


}
4 changes: 4 additions & 0 deletions src/Om/RedisObjectManagerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,8 @@ public function initializeObject(object $obj);
* Check if the object is managed by the current unit of work.
*/
public function contains(object $object): bool;

public function createIndex(object $object): void;

public function dropIndex(object $object): void;
}
3 changes: 2 additions & 1 deletion tests/Fixtures/Bar.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

namespace Talleu\RedisOm\Tests\Fixtures;

use Talleu\RedisOm\Client\PredisClient;
use Talleu\RedisOm\Om\Mapping as RedisOm;

#[RedisOm\Entity]
#[RedisOm\Entity()]
class Bar
{
#[RedisOm\Property]
Expand Down
22 changes: 14 additions & 8 deletions tests/Functionnal/DataConsistency/ArrayConsistencyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@

class ArrayConsistencyTest extends RedisAbstractTestCase
{
private RedisObjectManager $objectManager;
protected function setUp(): void
{
$this->objectManager = new RedisObjectManager(RedisAbstractTestCase::createClient());
parent::setUp();
}

public function testArrayHash(): void
{
self::emptyRedis();
Expand All @@ -32,11 +39,11 @@ public function testArrayHash(): void
]
];

$objectManager = new RedisObjectManager();
$objectManager->persist($arrayHash);
$objectManager->flush();

$this->assertEquals($arrayHash, $objectManager->find(ArrayHash::class, 1));
$this->objectManager->persist($arrayHash);
$this->objectManager->flush();

$this->assertEquals($arrayHash, $this->objectManager->find(ArrayHash::class, 1));
}

public function testArrayJson(): void
Expand All @@ -60,11 +67,10 @@ public function testArrayJson(): void
]
];

$objectManager = new RedisObjectManager();
$objectManager->persist($arrayJson);
$objectManager->flush();
$this->objectManager->persist($arrayJson);
$this->objectManager->flush();

$this->assertEquals($arrayJson, $objectManager->find(ArrayJson::class, 1));
$this->assertEquals($arrayJson, $this->objectManager->find(ArrayJson::class, 1));
}

public function createBar(int $id, string $title): Bar
Expand Down
Loading

0 comments on commit 7286fdf

Please sign in to comment.