diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..306680ee --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +3.0.0 +===== + +- Add more casting methods on `parameter` +- Update to PSR container ^2.0 diff --git a/composer.json b/composer.json index e13da1f6..32bd8661 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "require": { "php": "^8.1", "phpactor/map-resolver": "^1.4", - "psr/container": "^2.0" + "psr/container": "^1.0||^2.0" }, "require-dev": { "ergebnis/composer-normalize": "^2.0", diff --git a/lib/Parameter.php b/lib/Parameter.php index 59a667d4..bfa89218 100644 --- a/lib/Parameter.php +++ b/lib/Parameter.php @@ -49,4 +49,95 @@ public function float(): float } return $this->value; } + + /** + * @return list + */ + public function listOfString(): array + { + return array_map(function (mixed $value) { + $this->assertScalar($value); + return (string)$value; + }, (array)$this->value); + } + + /** + * @return list + */ + public function listOfInt(): array + { + return array_map(function (mixed $value) { + $this->assertScalar($value); + return (int)$value; + }, (array)$this->value); + } + + /** + * @return list + */ + public function listOfFloat(): array + { + return array_map(function (mixed $value) { + $this->assertScalar($value); + return (float)$value; + }, (array)$this->value); + } + + /** + * @return list + */ + public function listOfBool(): array + { + return array_map(function (mixed $value) { + $this->assertScalar($value); + return (bool)$value; + }, (array)$this->value); + } + + public function intOrNull(): ?int + { + if (null === $this->value) { + return null; + } + + return $this->int(); + } + + public function floatOrNull(): ?float + { + if (null === $this->value) { + return null; + } + + return $this->float(); + } + + public function stringOrNull(): ?string + { + if (null === $this->value) { + return null; + } + + return $this->string(); + } + + public function boolOrNull(): ?bool + { + if (null === $this->value) { + return null; + } + + return $this->bool(); + } + + /** + * @phpstan-assert scalar $value + */ + private function assertScalar(mixed $value): void + { + if (!is_scalar($value)) { + throw new RuntimeException(sprintf('Value in list is not a scalar, it is an "%s"', gettype($this->value))); + } + } + } diff --git a/lib/PhpactorContainer.php b/lib/PhpactorContainer.php index 72a42f9a..11a71bf9 100644 --- a/lib/PhpactorContainer.php +++ b/lib/PhpactorContainer.php @@ -148,9 +148,31 @@ public function getTags(): array return $this->tags; } + /** + * @template TClass of object + * @param class-string $expected + * @return TClass + */ public function expect(string $id, string $expected): object { - return $this->get($id); + $service = $this->get($id); + if (!is_object($service)) { + throw new RuntimeException(sprintf( + 'Expected service `%s` to be an object but got `%s`', + $id, + get_debug_type($service), + )); + } + if (!$service instanceof $expected) { + throw new RuntimeException(sprintf( + 'Expected service `%s` to be an instance of `%s` but got `%s`', + $id, + $expected, + $service::class + )); + } + + return $service; } public function parameter(string $name): Parameter diff --git a/phpstan.neon b/phpstan.neon index 4a0f607e..22254bcd 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,2 @@ parameters: - inferPrivatePropertyTypeFromConstructor: true - paths: - - lib - level: 7 + level: max diff --git a/tests/Unit/ParameterTest.php b/tests/Unit/ParameterTest.php index b8ff4a28..c2b76c56 100644 --- a/tests/Unit/ParameterTest.php +++ b/tests/Unit/ParameterTest.php @@ -19,6 +19,32 @@ public function testCast(): void self::assertSame(true, (new Parameter(true))->bool()); self::assertSame(12.2, (new Parameter(12.2))->float()); self::assertSame(12.0, (new Parameter(12))->float()); + + self::assertSame(null, (new Parameter(null))->intOrNull()); + self::assertSame(null, (new Parameter(null))->floatOrNull()); + self::assertSame(null, (new Parameter(null))->stringOrNull()); + self::assertSame(null, (new Parameter(null))->boolOrNull()); + + self::assertSame(1, (new Parameter(1))->intOrNull()); + self::assertSame(1.1, (new Parameter(1.1))->floatOrNull()); + self::assertSame('one', (new Parameter('one'))->stringOrNull()); + self::assertSame(true, (new Parameter(true))->boolOrNull()); + + self::assertSame(['foo'], (new Parameter(['foo']))->listOfString()); + self::assertSame(['foo'], (new Parameter('foo'))->listOfString()); + self::assertSame(['1'], (new Parameter(1))->listOfString()); + + self::assertSame([1.2], (new Parameter(['1.2']))->listOfFloat()); + self::assertSame([1.4], (new Parameter(1.4))->listOfFloat()); + self::assertSame([1.2], (new Parameter([1.2]))->listOfFloat()); + + self::assertSame([1], (new Parameter(['1']))->listOfInt()); + self::assertSame([2], (new Parameter(2))->listOfInt()); + self::assertSame([2], (new Parameter([2]))->listOfInt()); + + self::assertSame([true], (new Parameter(['1']))->listOfBool()); + self::assertSame([false], (new Parameter(false))->listOfBool()); + self::assertSame([true], (new Parameter([true]))->listOfBool()); } /** @@ -58,5 +84,11 @@ public static function provideCastException(): Generator fn (Parameter $p) => $p->bool(), 'Value is not a bool, it is "string"' ]; + + yield 'list of string with list of string' => [ + [[]], + fn (Parameter $p) => $p->listOfString(), + 'Value in list is not a scalar, it is an "array"' + ]; } }