Skip to content

Commit

Permalink
add SafePageableCollection and SafeReadablePageableCollection (#19)
Browse files Browse the repository at this point in the history
  • Loading branch information
priyadi authored Jun 19, 2024
1 parent afddfc0 commit 96da67b
Show file tree
Hide file tree
Showing 8 changed files with 481 additions and 10 deletions.
12 changes: 2 additions & 10 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
# Changelog

## 0.1.1
## 0.3.0

* feat(Recollection): add `getDefaultOrderBy()`

## 0.1.0

* build: initial commit
* fix: rename `matching()` to `withCriteria()` to avoid conflict with PHPStan
`allCollectionsSelectable`
* refactor: split common code to `rekalogika/collections-common`
* feat: new package `rekalogika/collections-orm`
* feat: add `SafePageableCollection` and `SafeReadablePageableCollection`
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

/*
* This file is part of rekalogika/collections package.
*
* (c) Priyadi Iman Nurcahyo <https://rekalogika.dev>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/

namespace Rekalogika\Domain\Collections\Common\Trait;

/**
* @template TKey of array-key
* @template T
*/
trait SafeReadableCollectionTrait
{
/**
* @template TMaybeContained
* @param TMaybeContained $element
* @return (TMaybeContained is T ? bool : false)
*/
final public function contains(mixed $element): bool
{
return $this->collection->contains($element);
}

/**
* @param TKey $key
*/
final public function containsKey(string|int $key): bool
{
return $this->collection->containsKey($key);
}

/**
* @param TKey $key
* @return T|null
*/
final public function get(string|int $key): mixed
{
return $this->collection->get($key);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

/*
* This file is part of rekalogika/collections package.
*
* (c) Priyadi Iman Nurcahyo <https://rekalogika.dev>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/

namespace Rekalogika\Domain\Collections\Common\Trait;

/**
* @template TKey of array-key
* @template T
*/
trait SafeWritableCollectionTrait
{
/**
* @param T $element
*/
final public function add(mixed $element): void
{
$this->collection->add($element);
}
}
27 changes: 27 additions & 0 deletions packages/collections-contracts/src/SafePageableCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

/*
* This file is part of rekalogika/collections package.
*
* (c) Priyadi Iman Nurcahyo <https://rekalogika.dev>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/

namespace Rekalogika\Contracts\Collections;

/**
* @template TKey of array-key
* @template T
* @extends SafeReadablePageableCollection<TKey,T>
*/
interface SafePageableCollection extends SafeReadablePageableCollection
{
/**
* @param T $element
*/
public function add(mixed $element): void;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

/*
* This file is part of rekalogika/collections package.
*
* (c) Priyadi Iman Nurcahyo <https://rekalogika.dev>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/

namespace Rekalogika\Contracts\Collections;

use Rekalogika\Contracts\Rekapager\PageableInterface;

/**
* @template TKey of array-key
* @template T
* @extends PageableInterface<TKey,T>
*/
interface SafeReadablePageableCollection extends PageableInterface
{
/**
* @template TMaybeContained
* @param TMaybeContained $element
* @return (TMaybeContained is T ? bool : false)
*/
public function contains(mixed $element): bool;

/**
* @param TKey $key
*/
public function containsKey(string|int $key): bool;

/**
* @param TKey $key
* @return T|null
*/
public function get(string|int $key): mixed;
}
139 changes: 139 additions & 0 deletions packages/collections-domain/src/SafeCriteriaRecollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<?php

declare(strict_types=1);

/*
* This file is part of rekalogika/collections package.
*
* (c) Priyadi Iman Nurcahyo <https://rekalogika.dev>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/

namespace Rekalogika\Domain\Collections;

use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\Common\Collections\Order;
use Doctrine\Common\Collections\ReadableCollection;
use Doctrine\Common\Collections\Selectable;
use Rekalogika\Contracts\Collections\SafeReadablePageableCollection;
use Rekalogika\Domain\Collections\Common\CountStrategy;
use Rekalogika\Domain\Collections\Common\Exception\UnexpectedValueException;
use Rekalogika\Domain\Collections\Common\Trait\CountableTrait;
use Rekalogika\Domain\Collections\Common\Trait\ItemsWithSafeguardTrait;
use Rekalogika\Domain\Collections\Common\Trait\PageableTrait;
use Rekalogika\Domain\Collections\Common\Trait\SafeReadableCollectionTrait;
use Rekalogika\Domain\Collections\Trait\RecollectionTrait;

/**
* @template TKey of array-key
* @template T
* @implements SafeReadablePageableCollection<TKey,T>
*/
class SafeCriteriaRecollection implements SafeReadablePageableCollection, \Countable
{
/** @use RecollectionTrait<TKey,T> */
use RecollectionTrait;

/** @use PageableTrait<TKey,T> */
use PageableTrait;

/** @use ItemsWithSafeguardTrait<TKey,T> */
use ItemsWithSafeguardTrait;

/** @use SafeReadableCollectionTrait<TKey,T> */
use SafeReadableCollectionTrait;

use CountableTrait;

/**
* @var ReadableCollection<TKey,T>&Selectable<TKey,T>
*/
private readonly ReadableCollection&Selectable $collection;

private readonly Criteria $criteria;

/**
* @param ReadableCollection<TKey,T> $collection
* @param int<1,max> $itemsPerPage
* @param null|int<0,max> $count
* @param null|int<1,max> $softLimit
* @param null|int<1,max> $hardLimit
*/
public function __construct(
ReadableCollection $collection,
?Criteria $criteria = null,
private readonly int $itemsPerPage = 50,
private readonly CountStrategy $countStrategy = CountStrategy::Restrict,
private ?int &$count = null,
private readonly ?int $softLimit = null,
private readonly ?int $hardLimit = null,
private readonly ?bool $strict = null,
) {
// save collection

if (!$collection instanceof Selectable) {
throw new UnexpectedValueException('The wrapped collection must implement the Selectable interface.');
}

$this->collection = $collection;

// save criteria

$criteria = clone ($criteria ?? Criteria::create());

if (\count($criteria->orderings()) === 0) {
$criteria->orderBy(['id' => Order::Descending]);
}

$this->criteria = $criteria;
}

/**
* @param null|Collection<TKey,T> $collection
* @param null|int<1,max> $itemsPerPage
* @param null|int<0,max> $count
* @param null|int<1,max> $softLimit
* @param null|int<1,max> $hardLimit
*/
protected function createFrom(
?ReadableCollection $collection = null,
?Criteria $criteria = null,
?int $itemsPerPage = 50,
?CountStrategy $countStrategy = CountStrategy::Restrict,
?int &$count = null,
?int $softLimit = null,
?int $hardLimit = null,
?bool $strict = null,
): static {
$count = $count ?? $this->count;

// @phpstan-ignore-next-line
return new static(
collection: $collection ?? $this->collection,
criteria: $criteria ?? $this->criteria,
itemsPerPage: $itemsPerPage ?? $this->itemsPerPage,
countStrategy: $countStrategy ?? $this->countStrategy,
count: $count,
softLimit: $softLimit ?? $this->softLimit,
hardLimit: $hardLimit ?? $this->hardLimit,
strict: $strict ?? $this->strict,
);
}

/**
* @return int<0,max>
*/
private function getRealCount(): int
{
$count = $this->collection->matching($this->criteria)->count();

if ($count > 0) {
return $count;
}

return 0;
}
}
Loading

0 comments on commit 96da67b

Please sign in to comment.