kaskadia/doctrine-repository-wrapper-uuid

Provides an abstraction layer above the Doctrine Repository in Laravel which enables better type safety when interacting with entities. This package uses UUID as the primary identifier.

Maintainers

Package info

gitlab.com/kaskadia/doctrine-repository-wrapper-uuid

Issues

pkg:composer/kaskadia/doctrine-repository-wrapper-uuid

Transparency log

Statistics

Installs: 170

Dependents: 0

Suggesters: 0

Stars: 0

v0.7.2 2026-07-12 20:18 UTC

README

Provides an abstraction layer above the Doctrine Repository in Laravel which enables better type safety when interacting with entities. This package uses UUID (v7) as the primary identifier.

Requirements

  • PHP ^8.1
  • laravel-doctrine/orm 1.6–1.8 or ^2.0/^2.1/^3
  • ramsey/uuid ^3.9 or ^4.0
  • ramsey/uuid-doctrine ^1.6 or ^2.1

Installation

composer require kaskadia/doctrine-repository-wrapper-uuid

The package's service provider (DoctrineRepositoryWrapperProvider) is auto-discovered by Laravel and binds IDoctrineWrapperRepository to DoctrineWrapperRepository in the container.

Entities

Extend EntityBase to get a UUIDv7 primary key generated automatically on construction (and left alone on hydration, since Doctrine sets $id directly when loading from the database):

use Doctrine\ORM\Mapping\{Column, Entity, Table};
use Kaskadia\Lib\DoctrineRepositoryWrapperUuid\Entities\EntityBase;
use Kaskadia\Lib\DoctrineRepositoryWrapperUuid\Entities\Interfaces\IEntity;
use Kaskadia\Lib\DoctrineRepositoryWrapperUuid\Traits\Entities\Types;

#[Entity]
#[Table(name: 'products')]
class Product extends EntityBase implements IEntity {
    use Types; // optional: adds mapped `name` and `slug` columns + accessors

    #[Column]
    protected bool $active = true;

    public function isActive(): bool {
        return $this->active;
    }
}

getId(): string returns the UUID. setId() only takes effect if the id isn't already set, so entities are effectively immutable after creation/hydration.

Repositories

Build your own repository classes on top of IDoctrineWrapperRepository (which wraps a Doctrine EntityRepository) and the BaseRepository trait, which adds delegation plus pagination helpers:

use Kaskadia\Lib\DoctrineRepositoryWrapperUuid\Repositories\Interfaces\IDoctrineWrapperRepository;
use Kaskadia\Lib\DoctrineRepositoryWrapperUuid\Traits\Repositories\BaseRepository;

class ProductRepository {
    use BaseRepository;

    protected IDoctrineWrapperRepository $repository;

    public function __construct(IDoctrineWrapperRepository $repository) {
        $repository->initializeRepository(Product::class);
        $this->repository = $repository;
    }
}

Resolve it through the container (or construct it directly) and call:

$repo = app(ProductRepository::class);

$repo->findAll();                       // Collection<Product>
$repo->findBy(['active' => true]);      // Collection<Product>

$product = new Product();
$repo->saveAndFlush($product);          // persist + flush, returns $this
$repo->deleteAndFlush($product);        // remove + flush, returns $this

Pagination

Three methods bridge Doctrine queries into Laravel's native LengthAwarePaginator:

// 1. Paginate a query/query builder you built yourself
$repo->paginate($queryBuilder, perPage: 15, page: $request->integer('page', 1));

// 2. Paginate by exact-match criteria, mirroring findBy()
$repo->paginateBy(
    criteria: ['active' => true, 'status' => ['draft', 'published']],
    orderBy: ['name' => 'ASC'],
    perPage: 15,
    page: $request->integer('page', 1),
);

// 3. Paginate with full control over the QueryBuilder (joins, LIKE, ranges, etc.)
$repo->paginateWith(function (QueryBuilder $qb) use ($search) {
    $qb->andWhere('e.name LIKE :search')->setParameter('search', "%{$search}%");
}, perPage: 15, page: $request->integer('page', 1));

paginateBy() criteria rules: scalar values match with =, arrays match with IN (...), and null matches with IS NULL. Dotted field names (association paths like category.slug) are supported; the . is replaced with _ when naming the bound parameter.

Testing

composer install
vendor/bin/phpunit                          # full suite
vendor/bin/phpunit --filter testMethodName  # single test
XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-text  # coverage (requires xdebug)

License

MIT