Skip to content

Commit

Permalink
Update types
Browse files Browse the repository at this point in the history
  • Loading branch information
timacdonald committed May 18, 2024
1 parent d5c5277 commit 0693dc5
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 25 deletions.
99 changes: 74 additions & 25 deletions src/HasParameters.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
trait HasParameters
{
/**
* @param array $arguments
* @param Collection<string, mixed>|array<string, mixed> $arguments
*/
public static function with($arguments): string
{
Expand All @@ -22,10 +22,7 @@ public static function with($arguments): string

self::validateArgumentMapIsAnAssociativeArray($arguments);

$aliases = new Collection(
/** @phpstan-ignore-next-line */
static::parameterAliasMap()
);
$aliases = new Collection(self::parameterAliasMap());

if ($aliases->isNotEmpty()) {
self::validateAliasesReferenceParameters($parameters, $aliases);
Expand All @@ -39,15 +36,18 @@ public static function with($arguments): string

self::validateNoUnexpectedArguments($parameters, $arguments);

self::validateParametersAreOptional($parameters->diffKeys($arguments));
self::validateParametersAreOptional(
/** @phpstan-ignore argument.type */
$parameters->diffKeys($arguments)
);

$arguments = self::parseArgumentMap($parameters, new Collection($arguments));
$arguments = self::parseArgumentMap($parameters, $arguments);

return self::formatArguments($arguments);
}

/**
* @param array $arguments
* @param Collection<int, mixed>|array<int, mixed> $arguments
*/
public static function in($arguments): string
{
Expand Down Expand Up @@ -76,6 +76,9 @@ protected static function parameterAliasMap(): array
];
}

/**
* @param Collection<array-key, string> $arguments
*/
private static function formatArguments(Collection $arguments): string
{
if ($arguments->isEmpty()) {
Expand All @@ -85,27 +88,32 @@ private static function formatArguments(Collection $arguments): string
return static::class.':'.$arguments->implode(',');
}

/**
* @param Collection<int, mixed> $arguments
* @return Collection<int, string>
*/
private static function parseArgumentList(Collection $arguments): Collection
{
return $arguments->map(
/**
* @param mixed $argument
*/
static function ($argument): string {
return self::castToString($argument);
}
);
return $arguments->map(function ($argument): string {
return self::castToString($argument);
});
}

/**
* @param Collection<string, ReflectionParameter> $parameters
* @param Collection<string, mixed> $arguments
* @return Collection<string, string>
*/
private static function parseArgumentMap(Collection $parameters, Collection $arguments): Collection
{
return $parameters->map(static function (ReflectionParameter $parameter) use ($arguments): ?string {
/** @phpstan-ignore return.type */
return $parameters->map(function (ReflectionParameter $parameter) use ($arguments): ?string {
if ($parameter->isVariadic()) {
return self::parseVariadicArgument($parameter, $arguments);
}

return self::parseStandardArgument($parameter, $arguments);
})->reject(static function (?string $argument): bool {
})->reject(function (?string $argument): bool {
/**
* A null value indicates that the last item in the parameter list
* is a variadic function that is not expecting any values. Because
Expand All @@ -117,12 +125,16 @@ private static function parseArgumentMap(Collection $parameters, Collection $arg
});
}

/**
* @param Collection<string, mixed> $arguments
*/
private static function parseVariadicArgument(ReflectionParameter $parameter, Collection $arguments): ?string
{
if (! $arguments->has($parameter->getName())) {
return null;
}

/** @phpstan-ignore argument.type */
$values = new Collection($arguments->get($parameter->getName()));

if ($values->isEmpty()) {
Expand All @@ -133,12 +145,15 @@ private static function parseVariadicArgument(ReflectionParameter $parameter, Co
/**
* @param mixed $value
*/
static function ($value) {
function ($value) {
return self::castToString($value);
}
)->implode(',');
}

/**
* @param Collection<string, mixed> $arguments
*/
private static function parseStandardArgument(ReflectionParameter $parameter, Collection $arguments): string
{
if ($arguments->has($parameter->getName())) {
Expand All @@ -148,13 +163,16 @@ private static function parseStandardArgument(ReflectionParameter $parameter, Co
return self::castToString($parameter->getDefaultValue());
}

/**
* @return Collection<string, ReflectionParameter>
*/
private static function parameters(): Collection
{
$handle = new ReflectionMethod(static::class, 'handle');

return Collection::make($handle->getParameters())
->slice(2)
->keyBy(static function (ReflectionParameter $parameter): string {
->skip(2)
->keyBy(function (ReflectionParameter $parameter): string {
return $parameter->getName();
});
}
Expand All @@ -169,17 +187,23 @@ private static function castToString($value): string
}

if ($value instanceof BackedEnum) {
return $value->value;
return (string) $value->value;
}

/** @phpstan-ignore cast.string */
return (string) $value;
}

/**
* @param Collection<string, mixed> $arguments
* @param Collection<string, string> $aliases
* @return Collection<string, mixed>
*/
private static function normaliseArguments(Collection $arguments, Collection $aliases): Collection
{
return $arguments->mapWithKeys(
/** @param mixed $value */
static function ($value, string $name) use ($aliases): array {
function ($value, string $name) use ($aliases): array {
if ($aliases->has($name)) {
/** @var string */
$newName = $aliases[$name];
Expand All @@ -192,10 +216,13 @@ static function ($value, string $name) use ($aliases): array {
);
}

/**
* @param Collection<string, ReflectionParameter> $parameters
*/
private static function validateParametersAreOptional(Collection $parameters): void
{
/** @var ?ReflectionParameter */
$missingRequiredParameter = $parameters->reject(static function (ReflectionParameter $parameter): bool {
$missingRequiredParameter = $parameters->reject(function (ReflectionParameter $parameter): bool {
return $parameter->isDefaultValueAvailable() || $parameter->isVariadic();
})->first();

Expand All @@ -206,25 +233,35 @@ private static function validateParametersAreOptional(Collection $parameters): v
throw new TypeError('Missing required argument $'.$missingRequiredParameter->getName().' for middleware '.static::class.'::handle()');
}

/**
* @param Collection<int, mixed> $arguments
*/
private static function validateArgumentListIsNotAnAssociativeArray(Collection $arguments): void
{
if (Arr::isAssoc($arguments->all())) {
throw new TypeError('Expected a non-associative array in HasParameters::in() but received an associative array. You should use the HasParameters::with() method instead.');
}
}

/**
* @param Collection<string, mixed> $arguments
*/
private static function validateArgumentMapIsAnAssociativeArray(Collection $arguments): void
{
if ($arguments->isNotEmpty() && ! Arr::isAssoc($arguments->all())) {
throw new TypeError('Expected an associative array in HasParameters::with() but received a non-associative array. You should use the HasParameters::in() method instead.');
}
}

/**
* @param Collection<string, ReflectionParameter> $parameters
* @param Collection<string, mixed> $arguments
*/
private static function validateNoUnexpectedArguments(Collection $parameters, Collection $arguments): void
{
/** @var ?string */
$unexpectedArgument = $arguments->keys()
->first(static function (string $name) use ($parameters): bool {
->first(function (string $name) use ($parameters): bool {
return ! $parameters->has($name);
});

Expand All @@ -235,22 +272,34 @@ private static function validateNoUnexpectedArguments(Collection $parameters, Co
throw new TypeError('Unknown argument $'.$unexpectedArgument.' passed to middleware '.static::class.'::handle()');
}

/**
* @param Collection<string, mixed> $arguments
* @param Collection<string, string> $aliases
*/
private static function validateOriginalAndAliasHaveNotBeenPassed(Collection $arguments, Collection $aliases): void
{
if ($arguments->intersectByKeys($aliases->flip())->isNotEmpty()) {
throw new TypeError('Cannot pass an original parameter and an aliases parameter name at the same time.');
}
}

/**
* @param Collection<string, string> $aliases
*/
private static function validateAliasesDontPointToSameParameters(Collection $aliases): void
{
if ($aliases->unique()->count() !== $aliases->count()) {
throw new TypeError('Two provided aliases cannot point to the same parameter.');
}
}

/**
* @param Collection<string, ReflectionParameter> $parameters
* @param Collection<string, string> $aliases
*/
private static function validateAliasesReferenceParameters(Collection $parameters, Collection $aliases): void
{
/** @phpstan-ignore argument.type */
if ($aliases->flip()->diffKeys($parameters)->isNotEmpty()) {
throw new TypeError('Aliases must reference existing parameters.');
}
Expand Down
8 changes: 8 additions & 0 deletions tests/HasParametersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ public function testListDoesNotAcceptAssociativeArray(): void
$this->expectException(TypeError::class);
$this->expectExceptionMessage('Expected a non-associative array in HasParameters::in() but received an associative array. You should use the HasParameters::with() method instead.');

/** @phpstan-ignore argument.type */
Basic::in(['framework' => 'laravel']);
}

Expand Down Expand Up @@ -305,6 +306,7 @@ public function testMapDoesNotAcceptANonAssociativeArray(): void
$this->expectException(TypeError::class);
$this->expectExceptionMessage('Expected an associative array in HasParameters::with() but received a non-associative array. You should use the HasParameters::in() method instead.');

/** @phpstan-ignore argument.type */
Basic::with(['framework', 'laravel']);
}

Expand Down Expand Up @@ -362,6 +364,9 @@ public function handle(Request $request, Closure $next, string $original, string
//
}

/**
* @return array<string, string>
*/
private static function parameterAliasMap(): array
{
return [
Expand Down Expand Up @@ -392,6 +397,9 @@ public function handle(Request $request, Closure $next, string $original): void
//
}

/**
* @return array<string, string>
*/
private static function parameterAliasMap(): array
{
return [
Expand Down
3 changes: 3 additions & 0 deletions tests/Middleware/Aliased.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ public function handle(Request $request, Closure $next, string $originalFirst, s
//
}

/**
* @return array<string, string>
*/
private static function parameterAliasMap(): array
{
return [
Expand Down
1 change: 1 addition & 0 deletions tests/Middleware/OptionalRequired.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class OptionalRequired
{
use HasParameters;

/** @phpstan-ignore parameter.requiredAfterOptional */
public function handle(Request $request, Closure $next, string $optional = 'default', string $required): void
{
//
Expand Down

0 comments on commit 0693dc5

Please sign in to comment.