Skip to content

Commit

Permalink
Init repository pack
Browse files Browse the repository at this point in the history
  • Loading branch information
loic425 committed Jan 13, 2025
1 parent 60375a8 commit f925705
Show file tree
Hide file tree
Showing 29 changed files with 431 additions and 4 deletions.
61 changes: 61 additions & 0 deletions .github/workflows/repository_pack.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: Repository Pack

on:
push:
branches-ignore:
- main
release:
types: [ created ]
schedule:
-
cron: "0 1 * * 6" # Run at 1am every Saturday
workflow_dispatch:

permissions:
actions: write
contents: write
pull-requests: write

jobs:
cqrs-pack:
runs-on: ubuntu-latest

name: "Tests (PHP ${{ matrix.php }})"

strategy:
fail-fast: false
matrix:
php: ["8.3"]

steps:
- uses: actions/checkout@v4

- name: "Setup PHP"
uses: shivammathur/setup-php@v2
with:
php-version: "${{ matrix.php }}"
ini-values: date.timezone=Europe/Warsaw
extensions: intl, gd, mysql, pdo_mysql, :xdebug
tools: symfony
coverage: none

- name: "Get Composer cache directory"
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT

- name: "Setup cache"
uses: actions/cache@v3
with:
path: |
${{ steps.composer-cache.outputs.dir }}
key: ${{ github.run_id }}-${{ runner.os }}-${{ hashFiles('composer.json') }}-symfony-${{ matrix.symfony }}

- name: "Create test application"
run: |
git config --global user.email "[email protected]"
git config --global user.name "Your Name"
(cd tests/Cqrs && make create-test-application)
id: end-of-setup

- name: "Lint container"
run: (cd tests/Cqrs/app && bin/console lint:container)
6 changes: 5 additions & 1 deletion .github/workflows/split_packages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ jobs:
fail-fast: false
matrix:
package:
- { path: 'meta/cqrs-meta', name: 'cqrs-meta' }
- { path: 'meta/cqrs-application-meta', name: 'cqrs-application-meta' }
- { path: 'meta/cqrs-infrastructure-meta', name: 'cqrs-infrastructure-meta' }
- { path: 'pack/cqrs-pack', name: 'cqrs-pack' }
- { path: 'meta/repository-domain-meta', name: 'repository-domain-meta' }
- { path: 'meta/repository-infrastructure-meta', name: 'repository-infrastructure-meta' }
- { path: 'pack/repository-pack', name: 'repository-pack' }
steps:
- uses: actions/checkout@v3
with:
Expand Down
5 changes: 5 additions & 0 deletions monofony/cqrs-application-meta/0.1/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"copy-from-recipe": {
"src/": "%SRC_DIR%/"
}
}
File renamed without changes.
5 changes: 5 additions & 0 deletions monofony/repository-domain-meta/0.1/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"copy-from-recipe": {
"src/": "%SRC_DIR%/"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace App\Shared\Domain\Repository;

/**
* @template T of object
*
* @extends \IteratorAggregate<array-key, T>
*/
interface PaginatorInterface extends \IteratorAggregate, \Countable
{
public function getCurrentPage(): int;

public function getItemsPerPage(): int;

public function getLastPage(): int;

public function getTotalItems(): int;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace App\Shared\Domain\Repository;

/**
* @template T of object
*
* @extends \IteratorAggregate<array-key, T>
*/
interface RepositoryInterface extends \IteratorAggregate, \Countable
{
/**
* @return \Iterator<T>
*/
public function getIterator(): \Iterator;

public function count(): int;

/**
* @return PaginatorInterface<T>|null
*/
public function paginator(): PaginatorInterface|null;

/**
* @return static<T>
*
* @phpstan-ignore-next-line
*/
public function withPagination(int $page, int $itemsPerPage): static;
}
5 changes: 5 additions & 0 deletions monofony/repository-infrastructure-meta/0.1/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"copy-from-recipe": {
"src/": "%SRC_DIR%/"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php

declare(strict_types=1);

namespace App\Shared\Infrastructure\Doctrine;

use App\Shared\Domain\Repository\PaginatorInterface;
use Doctrine\ORM\Tools\Pagination\Paginator;

/**
* @template T of object
*
* @implements PaginatorInterface<T>
*/
final readonly class DoctrinePaginator implements PaginatorInterface
{
private int $firstResult;
private int $maxResults;

/**
* @param Paginator<T> $paginator
*/
public function __construct(
private Paginator $paginator,
) {
$firstResult = $paginator->getQuery()->getFirstResult();
$maxResults = $paginator->getQuery()->getMaxResults();

if (null === $maxResults) {
throw new \InvalidArgumentException('Missing maxResults from the query.');
}

$this->firstResult = $firstResult;
$this->maxResults = $maxResults;
}

public function getItemsPerPage(): int
{
return $this->maxResults;
}

public function getCurrentPage(): int
{
if (0 >= $this->maxResults) {
return 1;
}

return (int) (1 + floor($this->firstResult / $this->maxResults));
}

public function getLastPage(): int
{
if (0 >= $this->maxResults) {
return 1;
}

return (int) (ceil($this->getTotalItems() / $this->maxResults) ?: 1);
}

public function getTotalItems(): int
{
return count($this->paginator);
}

public function count(): int
{
return iterator_count($this->getIterator());
}

public function getIterator(): \Traversable
{
return $this->paginator->getIterator();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?php

declare(strict_types=1);

namespace App\Shared\Infrastructure\Doctrine;

use App\Shared\Domain\Repository\PaginatorInterface;
use App\Shared\Domain\Repository\RepositoryInterface;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\Tools\Pagination\Paginator;
use Webmozart\Assert\Assert;

/**
* @template T of object
*
* @implements RepositoryInterface<T>
*/
abstract class DoctrineRepository implements RepositoryInterface
{
private int|null $page = null;
private int|null $itemsPerPage = null;

private QueryBuilder $queryBuilder;

public function __construct(
protected EntityManagerInterface $em,
string $entityClass,
string $alias,
) {
$this->queryBuilder = $this->em->createQueryBuilder()
->select($alias)
->from($entityClass, $alias);
}

public function getIterator(): \Iterator
{
if (null !== $paginator = $this->paginator()) {
yield from $paginator;

return;
}

yield from $this->queryBuilder->getQuery()->getResult();
}

public function count(): int
{
$paginator = $this->paginator() ?? new Paginator(clone $this->queryBuilder);

return $paginator->count();
}

public function paginator(): PaginatorInterface|null
{
if (null === $this->page || null === $this->itemsPerPage) {
return null;
}

$firstResult = ($this->page - 1) * $this->itemsPerPage;
$maxResults = $this->itemsPerPage;

$repository = $this->filter(static function (QueryBuilder $qb) use ($firstResult, $maxResults) {
$qb->setFirstResult($firstResult)->setMaxResults($maxResults);
});

/** @var Paginator<T> $paginator */
$paginator = new Paginator($repository->queryBuilder->getQuery());

return new DoctrinePaginator($paginator);
}

public function withoutPagination(): static
{
$cloned = clone $this;
$cloned->page = null;
$cloned->itemsPerPage = null;

return $cloned;
}

public function withPagination(int $page, int $itemsPerPage): static
{
Assert::positiveInteger($page);
Assert::positiveInteger($itemsPerPage);

$cloned = clone $this;
$cloned->page = $page;
$cloned->itemsPerPage = $itemsPerPage;

return $cloned;
}

/**
* @return static<T>
*
* @phpstan-ignore-next-line
*/
protected function filter(callable $filter): static
{
$cloned = clone $this;
$filter($cloned->queryBuilder);

return $cloned;
}

protected function query(): QueryBuilder
{
return clone $this->queryBuilder;
}

protected function __clone()
{
$this->queryBuilder = clone $this->queryBuilder;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

declare(strict_types=1);

namespace App\Shared\Infrastructure\Pagerfanta;

use App\Shared\Domain\Repository\PaginatorInterface;
use Pagerfanta\PagerfantaInterface;

final class PagerfantaPaginator implements PaginatorInterface
{
public function __construct(
private PagerfantaInterface $pagerfanta,
) {
}

public function getIterator(): \Traversable
{
return $this->pagerfanta->getIterator();
}

public function count(): int
{
return iterator_count($this->pagerfanta->getIterator());
}

public function getCurrentPage(): int
{
return $this->pagerfanta->getCurrentPage();
}

public function getItemsPerPage(): int
{
return $this->pagerfanta->getMaxPerPage();
}

public function getLastPage(): int
{
return $this->pagerfanta->getNbPages();
}

public function getTotalItems(): int
{
return $this->pagerfanta->getNbResults();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "monofony/cqrs-meta",
"name": "monofony/cqrs-application-meta",
"type": "metapackage",
"license": "MIT",
"description": "A meta package providing recipes for CQRS"
Expand Down
Loading

0 comments on commit f925705

Please sign in to comment.