Skip to content

Commit

Permalink
B#188652 AccessorPair accept all array notations (#62)
Browse files Browse the repository at this point in the history
* B#188652 AccessorPair accept all array notations
  • Loading branch information
anne-gaelle123inkt authored Nov 8, 2024
1 parent 973706c commit 82cc2fc
Show file tree
Hide file tree
Showing 10 changed files with 188 additions and 13 deletions.
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@
"sort-packages": true,
"allow-plugins": {
"phpstan/extension-installer": true
}
},
"lock": false
},
"require": {
"php": ">=8.1",
"doctrine/inflector": "^2.0",
"phpdocumentor/type-resolver": "^1.7",
"phpdocumentor/type-resolver": "^1.9",
"phpunit/phpunit": "^10.0 || ^11.0"
},
"require-dev": {
Expand Down
12 changes: 5 additions & 7 deletions src/Constraint/Typehint/PhpDocParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ public function getParamTypehint(string $parameterName, string $docComment): ?st

preg_match('/\*\s*@(?:phpstan|psalm)-param\s+(.*?)\s*(?:\.\.\.)?' . preg_quote('$' . $parameterName, '/') . '\W/i', $docComment, $matches);
if (isset($matches[1])) {
return $this->normalizeDocblock((string)$matches[1]);
return $this->normalizeDocblock($matches[1]);
}

preg_match('/\*\s*@param\s+(.*?)\s*(?:\.\.\.)?' . preg_quote('$' . $parameterName, '/') . '\W/i', $docComment, $matches);
if (isset($matches[1])) {
return $this->normalizeDocblock((string)$matches[1]);
return $this->normalizeDocblock($matches[1]);
}

return null;
Expand All @@ -36,6 +36,7 @@ public function getParamTypehint(string $parameterName, string $docComment): ?st
public function getReturnTypehint(string $originalDocComment): ?string
{
$docComment = trim($originalDocComment);
$docComment = str_replace([', ', ': '], [',', ':'], $docComment);
// empty docblock provided, no typehint found
if ($docComment === '') {
return null;
Expand All @@ -49,12 +50,12 @@ public function getReturnTypehint(string $originalDocComment): ?string

preg_match('/\*\s*@(?:phpstan|psalm)-return\s+(.*?)(?:\s+|\*)/', $docComment, $matches);
if (isset($matches[1])) {
return $this->normalizeDocblock((string)$matches[1]);
return $this->normalizeDocblock($matches[1]);
}

preg_match('/\*\s*@return\s+(.*?)(?:\s+|\*)/', $docComment, $matches);
if (isset($matches[1])) {
return $this->normalizeDocblock((string)$matches[1]);
return $this->normalizeDocblock($matches[1]);
}

return null;
Expand All @@ -74,9 +75,6 @@ public function getTemplateTypehints(string $originalDocComment): array
}

preg_match_all('/\*\s*@template\s+(.*?)\sof\s(.*?)(?:\s+|\*)/', $docComment, $matches);
if (isset($matches[1], $matches[2]) === false) {
return []; // @codeCoverageIgnore
}

return array_combine($matches[1], $matches[2]);
}
Expand Down
6 changes: 3 additions & 3 deletions src/Constraint/Typehint/TypehintResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
*/
class TypehintResolver
{
protected PhpDocParser $phpDocParser;
protected PhpDocParser $phpDocParser;
protected ReflectionMethod $method;
protected TypeResolver $resolver;
protected Context $resolverContext;
protected TypeResolver $resolver;
protected Context $resolverContext;

public function __construct(ReflectionMethod $method)
{
Expand Down
47 changes: 47 additions & 0 deletions src/Constraint/ValueProvider/Compound/ArrayShapeProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php
declare(strict_types=1);

namespace DigitalRevolution\AccessorPairConstraint\Constraint\ValueProvider\Compound;

use DigitalRevolution\AccessorPairConstraint\Constraint\ValueProvider\ValueProvider;

class ArrayShapeProvider implements ValueProvider
{
/**
* @param array<string, ValueProvider> $items
*/
public function __construct(protected array $items)
{
}

/**
* @return array<array<int|string, mixed>>
* @inheritDoc
*/
public function getValues(): array
{
$testArray = [];
$keyValues = [];

$minValues = null;
foreach ($this->items as $key => $item) {
$values = $item->getValues();
if ($minValues === null || count($values) < $minValues) {
$minValues = count($values);
}
$keyValues[$key] = $item->getValues();
}

foreach ($keyValues as $key => $values) {
$keyValues[$key] = array_slice($values, 0, $minValues);
}

foreach ($keyValues as $key => $values) {
foreach ($values as $index => $value) {
$testArray[$index][$key] = $value;
}
}

return $testArray;
}
}
9 changes: 9 additions & 0 deletions src/Constraint/ValueProvider/NativeValueProviderFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
namespace DigitalRevolution\AccessorPairConstraint\Constraint\ValueProvider;

use DigitalRevolution\AccessorPairConstraint\Constraint\ValueProvider\Compound\ArrayProvider;
use DigitalRevolution\AccessorPairConstraint\Constraint\ValueProvider\Compound\ArrayShapeProvider;
use DigitalRevolution\AccessorPairConstraint\Constraint\ValueProvider\Compound\CallableProvider;
use DigitalRevolution\AccessorPairConstraint\Constraint\ValueProvider\Compound\IterableProvider;
use DigitalRevolution\AccessorPairConstraint\Constraint\ValueProvider\Compound\ObjectProvider;
Expand All @@ -16,6 +17,7 @@
use DigitalRevolution\AccessorPairConstraint\Constraint\ValueProvider\Special\NullProvider;
use DigitalRevolution\AccessorPairConstraint\Constraint\ValueProvider\Special\ResourceProvider;
use LogicException;
use phpDocumentor\Reflection\PseudoTypes\ArrayShape;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Array_;
use phpDocumentor\Reflection\Types\Boolean;
Expand Down Expand Up @@ -79,6 +81,13 @@ protected function getCompoundProvider(Type $typehint): ?ValueProvider
$this->valueProviderFactory->getProvider($typehint->getValueType()),
$this->valueProviderFactory->getProvider($typehint->getKeyType())
);
case ArrayShape::class:
$items = $typehint->getItems();
$itemProviders = [];
foreach ($items as $item) {
$itemProviders[$item->getKey()] = $this->valueProviderFactory->getProvider($item->getValue());
}
return new ArrayShapeProvider($itemProviders);
case Callable_::class:
return new CallableProvider();
case Iterable_::class:
Expand Down
1 change: 1 addition & 0 deletions tests/Integration/AccessorPairAsserterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
* @uses \DigitalRevolution\AccessorPairConstraint\Constraint\Typehint\PhpDocParser
* @uses \DigitalRevolution\AccessorPairConstraint\Constraint\Typehint\TypehintResolver
* @uses \DigitalRevolution\AccessorPairConstraint\Constraint\ValueProvider\Compound\ArrayProvider
* @uses \DigitalRevolution\AccessorPairConstraint\Constraint\ValueProvider\Compound\ArrayShapeProvider
* @uses \DigitalRevolution\AccessorPairConstraint\Constraint\ValueProvider\Compound\CallableProvider
* @uses \DigitalRevolution\AccessorPairConstraint\Constraint\ValueProvider\Compound\InstanceProvider
* @uses \DigitalRevolution\AccessorPairConstraint\Constraint\ValueProvider\Compound\IntersectionProvider
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);

namespace DigitalRevolution\AccessorPairConstraint\Tests\Integration\data\success\Regular\Types\CompoundTypes;

class ArrayShapeProperty
{
/** @var array{foo: int, bar: string}[] */
private array $items;

/**
* @param array{foo: int, bar: string}[] $items
*/
public function __construct(array $items)
{
$this->items = $items;
}

/**
* @param array{foo: int, bar: string}[] $items
*/
public function setItems(array $items): void
{
$this->items = $items;
}

/**
* @return array{foo: int, bar: string}[]
*/
public function getItems(): array
{
return $this->items;
}
}
2 changes: 1 addition & 1 deletion tests/Unit/Constraint/ConstraintConfigTest.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php
declare(strict_types=1);

namespace Constraint;
namespace DigitalRevolution\AccessorPairConstraint\Tests\Unit\Constraint;

use DigitalRevolution\AccessorPairConstraint\Constraint\ConstraintConfig;
use DigitalRevolution\AccessorPairConstraint\Tests\TestCase;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);

namespace DigitalRevolution\AccessorPairConstraint\Tests\Unit\Constraint\MethodPair\AccessorPair\data\success;

use DigitalRevolution\AccessorPairConstraint\Tests\Unit\Constraint\MethodPair\AbstractDataClass;

class TypedArrayShapeSetGet extends AbstractDataClass
{
/** @var array{foo: int, bar: string}[] */
private $items;

/**
* @param array{foo: int, bar: string}[] $items
*/
public function __construct(array $items)
{
$this->items = $items;
}

/**
* @param array{foo: int, bar: string} $item
*/
public function addItem(array $item): void
{
$this->items[] = $item;
}

/**
* @param array{foo: int, bar: string}[] $items
*/
public function setItems(array $items): void
{
$this->items = $items;
}

/**
* @return array{foo: int, bar: string}[]
*/
public function getItems(): array
{
return $this->items;
}

public function getExpectedPairs(): array
{
return [['getItems', 'setItems', false], ['getItems', 'addItem', true]];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);

namespace Constraint\ValueProvider\Compound;

use DigitalRevolution\AccessorPairConstraint\Constraint\ValueProvider\Compound\ArrayShapeProvider;
use DigitalRevolution\AccessorPairConstraint\Constraint\ValueProvider\Scalar\IntProvider;
use DigitalRevolution\AccessorPairConstraint\Constraint\ValueProvider\Scalar\StringProvider;
use DigitalRevolution\AccessorPairConstraint\Tests\Unit\Constraint\ValueProvider\AbstractValueProviderTestCase;
use Exception;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\UsesClass;

#[CoversClass(ArrayShapeProvider::class)]
#[UsesClass(IntProvider::class)]
#[UsesClass(StringProvider::class)]
class ArrayShapeProviderTest extends AbstractValueProviderTestCase
{
/**
* @throws Exception
*/
public function testGetValues(): void
{
$valueProvider = new ArrayShapeProvider(['foo' => new IntProvider(), 'bar' => new StringProvider()]);
$values = $valueProvider->getValues();

static::assertNotCount(0, $values);
foreach ($values as $value) {
static::assertCount(2, $value);
static::assertArrayHasKey('foo', $value);
static::assertIsInt($value['foo']);
static::assertArrayHasKey('bar', $value);
static::assertIsString($value['bar']);
}
}
}

0 comments on commit 82cc2fc

Please sign in to comment.