Skip to content

Commit

Permalink
make Inject attribute optional
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidBadura committed Dec 12, 2024
1 parent 6d2faa1 commit 429a950
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 26 deletions.
2 changes: 1 addition & 1 deletion src/Attribute/Inject.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
final class Inject
{
public function __construct(
public readonly string|null $service = null,
public readonly string $service,
) {
}
}
43 changes: 21 additions & 22 deletions src/CommandBus/Handler/ParameterResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Patchlevel\EventSourcing\Attribute\Inject;
use Psr\Container\ContainerInterface;
use ReflectionMethod;
use RuntimeException;
use ReflectionParameter;
use Symfony\Component\TypeInfo\Type\ObjectType;
use Symfony\Component\TypeInfo\TypeResolver\TypeResolver;

Expand All @@ -22,35 +22,34 @@ public static function resolve(ReflectionMethod $method, ContainerInterface|null
continue; // skip first parameter (command)
}

$attributes = $parameter->getAttributes(Inject::class);

if ($attributes === []) {
throw new RuntimeException('missing inject attribute');
if (!$container) {
throw ServiceNotResolvable::missingContainer();
}

$serviceName = $attributes[0]->newInstance()->service;

if ($serviceName === null) {
$reflectionType = $parameter->getType();
yield $container->get(self::serviceName($method, $parameter));
}
}

if ($reflectionType === null) {
throw new RuntimeException('missing type hint');
}
private static function serviceName(ReflectionMethod $method, ReflectionParameter $parameter): string
{
$attributes = $parameter->getAttributes(Inject::class);

$type = TypeResolver::create()->resolve($reflectionType);
if ($attributes !== []) {
return $attributes[0]->newInstance()->service;
}

if (!$type instanceof ObjectType) {
throw new RuntimeException('type hint must be object');
}
$reflectionType = $parameter->getType();

$serviceName = $type->getClassName();
}
if ($reflectionType === null) {
throw ServiceNotResolvable::missingType($method->getDeclaringClass()->getName(), $parameter->getName());
}

if (!$container) {
throw new RuntimeException('missing inject attribute');
}
$type = TypeResolver::create()->resolve($reflectionType);

yield $container->get($serviceName);
if (!$type instanceof ObjectType) {
throw ServiceNotResolvable::typeNotObject($method->getDeclaringClass()->getName(), $parameter->getName());
}

return $type->getClassName();
}
}
23 changes: 23 additions & 0 deletions src/CommandBus/Handler/ServiceNotResolvable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace Patchlevel\EventSourcing\CommandBus\Handler;

use RuntimeException;

final class ServiceNotResolvable extends RuntimeException
{
public static function missingType(string $class, $propertyName): self

Check failure on line 9 in src/CommandBus/Handler/ServiceNotResolvable.php

View workflow job for this annotation

GitHub Actions / Static Analysis by Psalm (locked, 8.3, ubuntu-latest)

MissingParamType

src/CommandBus/Handler/ServiceNotResolvable.php:9:55: MissingParamType: Parameter $propertyName has no provided type (see https://psalm.dev/154)

Check failure on line 9 in src/CommandBus/Handler/ServiceNotResolvable.php

View workflow job for this annotation

GitHub Actions / Static Analysis by PHPStan (locked, 8.3, ubuntu-latest)

Method Patchlevel\EventSourcing\CommandBus\Handler\ServiceNotResolvable::missingType() has parameter $propertyName with no type specified.
{
return new self(sprintf('Missing type for property "%s" in class "%s"', $propertyName, $class));

Check failure on line 11 in src/CommandBus/Handler/ServiceNotResolvable.php

View workflow job for this annotation

GitHub Actions / Static Analysis by Psalm (locked, 8.3, ubuntu-latest)

MixedArgument

src/CommandBus/Handler/ServiceNotResolvable.php:11:81: MixedArgument: Argument 2 of sprintf cannot be mixed, expecting float|int|object{__tostring()}|string (see https://psalm.dev/030)
}

public static function typeNotObject(string $class, $propertyName): self

Check failure on line 14 in src/CommandBus/Handler/ServiceNotResolvable.php

View workflow job for this annotation

GitHub Actions / Static Analysis by Psalm (locked, 8.3, ubuntu-latest)

MissingParamType

src/CommandBus/Handler/ServiceNotResolvable.php:14:57: MissingParamType: Parameter $propertyName has no provided type (see https://psalm.dev/154)

Check failure on line 14 in src/CommandBus/Handler/ServiceNotResolvable.php

View workflow job for this annotation

GitHub Actions / Static Analysis by PHPStan (locked, 8.3, ubuntu-latest)

Method Patchlevel\EventSourcing\CommandBus\Handler\ServiceNotResolvable::typeNotObject() has parameter $propertyName with no type specified.
{
return new self(sprintf('Type for property "%s" in class "%s" must be object', $propertyName, $class));

Check failure on line 16 in src/CommandBus/Handler/ServiceNotResolvable.php

View workflow job for this annotation

GitHub Actions / Static Analysis by Psalm (locked, 8.3, ubuntu-latest)

MixedArgument

src/CommandBus/Handler/ServiceNotResolvable.php:16:88: MixedArgument: Argument 2 of sprintf cannot be mixed, expecting float|int|object{__tostring()}|string (see https://psalm.dev/030)
}

public static function missingContainer(): self
{
return new self('Container is not configured');
}
}
2 changes: 1 addition & 1 deletion src/CommandBus/ServiceNotFound.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ final class ServiceNotFound extends RuntimeException implements NotFoundExceptio
{
public function __construct(string $id)
{
parent::__construct(sprintf('service %s not found', $id));
parent::__construct(sprintf('service "%s" not found', $id));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ public function testCommandBus(): void
$manager,
new ServiceLocator([
ClockInterface::class => new SystemClock(),
'env' => 'test',
]),
);

Expand Down
4 changes: 2 additions & 2 deletions tests/Integration/BasicImplementation/ProfileWithCommands.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ final class ProfileWithCommands extends BasicAggregateRoot
#[Handle]
public static function create(
CreateProfile $command,
#[Inject]
ClockInterface $clock,
#[Inject('env')] string $env,
): self {
$self = new self();
$self->recordThat(new ProfileCreated($command->id, $command->name));
Expand All @@ -40,8 +40,8 @@ public static function create(
#[Handle]
public function changeName(
ChangeProfileName $command,
#[Inject]
ClockInterface $clock,
#[Inject('env')] string $env,
): void {
$this->recordThat(new NameChanged($command->name));
}
Expand Down

0 comments on commit 429a950

Please sign in to comment.