Skip to content

Commit

Permalink
feat: TraversableToTraversableTransformer now gives a Countable r…
Browse files Browse the repository at this point in the history
…esult if the source is `Countable`.
  • Loading branch information
priyadi committed Jan 12, 2024
1 parent d7813f4 commit 6735dc2
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 3 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
mixed type.
* refactor: Remove deprecated facade.
* feat: Add `CopyTransformer` to handle mixed to mixed mapping.
* feat: `TraversableToTraversableTransformer` now gives a `Countable` result
if the source is `Countable`.
* revert: Revert support for `Generator` target type. Impossible to have a
`Countable` result.

## 0.5.3

Expand Down
45 changes: 45 additions & 0 deletions src/Model/TraversableCountableWrapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

/*
* This file is part of rekalogika/mapper 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\Mapper\Model;

/**
* @template TKey
* @template TValue
* @implements \IteratorAggregate<TKey,TValue>
*/
final class TraversableCountableWrapper implements \IteratorAggregate, \Countable
{
/**
* @param \Traversable<TKey,TValue> $traversable
*/
public function __construct(
private \Traversable $traversable,
private \Countable|int $countable,
) {
}

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

public function count(): int
{
if (is_int($this->countable)) {
return $this->countable;
}

return $this->countable->count();
}
}
8 changes: 7 additions & 1 deletion src/Transformer/TraversableToTraversableTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use Rekalogika\Mapper\Exception\MissingMemberKeyTypeException;
use Rekalogika\Mapper\Exception\MissingMemberValueTypeException;
use Rekalogika\Mapper\MainTransformer;
use Rekalogika\Mapper\Model\TraversableCountableWrapper;
use Rekalogika\Mapper\ObjectCache\ObjectCache;
use Rekalogika\Mapper\ObjectCache\ObjectCacheFactoryInterface;
use Rekalogika\Mapper\Util\TypeCheck;
Expand Down Expand Up @@ -158,6 +159,12 @@ public function transform(
}
})();

if ($source instanceof \Countable) {
$target = new TraversableCountableWrapper($target, $source);
} elseif (is_array($source)) {
$target = new TraversableCountableWrapper($target, count($source));
}

$objectCache->saveTarget($source, $targetType, $target);

return $target;
Expand All @@ -171,7 +178,6 @@ public function getSupportedTransformation(): iterable
];

$targetTypes = [
TypeFactory::objectOfClass(\Generator::class),
TypeFactory::objectOfClass(\Traversable::class),
];

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

/*
* This file is part of rekalogika/mapper 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\Mapper\Tests\Fixtures\ArrayLike;

use Doctrine\Common\Collections\AbstractLazyCollection;

/**
* @extends AbstractLazyCollection<array-key,mixed>
*/
class LazyDoctrineCollectionWithPresetCountable extends AbstractLazyCollection
{
protected function doInitialize()
{
throw new \LogicException("Not expected to be initialized");
}

public function count(): int
{
return 31337;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

/*
* This file is part of rekalogika/mapper 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\Mapper\Tests\Fixtures\ArrayLike;

class ObjectWithLazyDoctrineCollectionWithPresetCountableProperty
{
public LazyDoctrineCollectionWithPresetCountable $property;

public function __construct()
{
$this->property = new LazyDoctrineCollectionWithPresetCountable();
}
}
22 changes: 20 additions & 2 deletions tests/IntegrationTest/TraversableToTraversableMappingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@

namespace Rekalogika\Mapper\Tests\IntegrationTest;

use Rekalogika\Mapper\Model\TraversableCountableWrapper;
use Rekalogika\Mapper\Tests\Common\AbstractIntegrationTest;
use Rekalogika\Mapper\Tests\Fixtures\ArrayLike\ObjectWithArrayProperty;
use Rekalogika\Mapper\Tests\Fixtures\ArrayLike\ObjectWithLazyDoctrineCollectionProperty;
use Rekalogika\Mapper\Tests\Fixtures\ArrayLike\ObjectWithLazyDoctrineCollectionWithPresetCountableProperty;
use Rekalogika\Mapper\Tests\Fixtures\ArrayLike\ObjectWithTraversableProperties;
use Rekalogika\Mapper\Tests\Fixtures\ArrayLikeDto\ObjectWithTraversablePropertyDto;
use Rekalogika\Mapper\Tests\Fixtures\Scalar\ObjectWithScalarPropertiesDto;
Expand Down Expand Up @@ -54,7 +56,7 @@ public function testArrayToTraversableDto(): void

$this->assertInstanceOf(ObjectWithTraversablePropertyDto::class, $result);
$this->assertNotNull($result->property);
$this->assertInstanceOf(\Generator::class, $result->property);
$this->assertInstanceOf(TraversableCountableWrapper::class, $result->property);

foreach ($result->property as $item) {
$this->assertInstanceOf(ObjectWithScalarPropertiesDto::class, $item);
Expand All @@ -74,7 +76,23 @@ public function testLazy(): void

$this->assertInstanceOf(ObjectWithTraversablePropertyDto::class, $result);
$this->assertNotNull($result->property);
$this->assertInstanceOf(\Generator::class, $result->property);
$this->assertInstanceOf(TraversableCountableWrapper::class, $result->property);

$this->expectException(\LogicException::class);
foreach ($result->property as $item);
}

public function testExtraLazy(): void
{
$source = new ObjectWithLazyDoctrineCollectionWithPresetCountableProperty();

$result = $this->mapper->map($source, ObjectWithTraversablePropertyDto::class);

$this->assertInstanceOf(ObjectWithTraversablePropertyDto::class, $result);
$this->assertNotNull($result->property);
$this->assertInstanceOf(TraversableCountableWrapper::class, $result->property);

$this->assertEquals(31337, $result->property->count());

$this->expectException(\LogicException::class);
foreach ($result->property as $item);
Expand Down

0 comments on commit 6735dc2

Please sign in to comment.