use Elrise\Bundle\DoctrineShardManager\Attribute\Sharding;
#[Sharding(
strategy: 'hash',
key: 'userId',
shardCount: 4,
)]
class User
{
// ...
}
#[Sharding(
strategy: 'hash',
key: ['tenantId', 'userId'],
shardCount: 4,
)]
class User
{
// ...
}
use Elrise\Bundle\DoctrineShardManager\Context\ShardContext;
final class UserService
{
public function __construct(private ShardContext $shardContext) {}
public function loadFromShard(int $userId): ?User
{
return $this->shardContext->withEntity(
$this->buildStubUser($userId),
function (EntityManagerInterface $em, string $shardId) use ($userId): ?User {
return $em->getRepository(User::class)->find($userId);
},
);
}
}
use Elrise\Bundle\DoctrineShardManager\Repository\ShardedRepository;
final class UserController
{
public function __construct(private ShardedRepository $userRepo) {}
public function show(int $userId): Response
{
$user = $this->userRepo->findOneById($userId, User::class);
if (null === $user) {
throw new NotFoundHttpException();
}
return new Response(sprintf('Hello, %s!', $user->getDisplayName()));
}
}
use Elrise\Bundle\DoctrineShardManager\Finder\ShardedFinder;
final class ReportingService
{
public function __construct(private ShardedFinder $finder) {}
public function streamAllActiveUsers(): \Generator
{
$shardIds = ['shard_0', 'shard_1', 'shard_2', 'shard_3'];
return $this->finder->find(
static fn (Connection $c) => $c->iterateAssociative(
'SELECT * FROM users WHERE active = 1 ORDER BY id',
),
$shardIds,
);
}
}
use Elrise\Bundle\DoctrineShardManager\Strategy\AbstractShardStrategy;
final class TenantPrefixedStrategy extends AbstractShardStrategy
{
#[\Override]
public function resolveShardId(mixed $key, array $options = []): ?string
{
$tenantId = $this->normalizeKey($key);
return 'tenant_'.$tenantId;
}
}