diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..712d96fc0 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,5 @@ + diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..196ba118e --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,88 @@ +name: CI + +on: + push: + branches: ['master'] + pull_request: + branches: ['*'] + schedule: + - cron: '0 0 * * *' + +jobs: + + tests: + name: Tests - PHP ${{ matrix.php }} ${{ matrix.dependency-version }} + runs-on: ubuntu-latest + timeout-minutes: 15 + strategy: + matrix: + php: [ '7.2', '7.3', '7.4', '8.0' ] + dependency-version: [ '' ] + include: + - php: '7.2' + dependency-version: '--prefer-lowest' + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + tools: composer + coverage: none + - name: Cache Composer dependencies + uses: actions/cache@v2 + with: + path: ~/.composer/cache + key: php-${{ matrix.php }}-composer-locked-${{ hashFiles('composer.lock') }} + restore-keys: php-${{ matrix.php }}-composer-locked- + - name: Install PHP dependencies + run: composer update ${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-progress --no-suggest + - name: PHPUnit + run: vendor/bin/phpunit + + cs: + name: Coding standards + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 7.4 + tools: composer, cs2pr + coverage: none + - name: Cache Composer dependencies + uses: actions/cache@v2 + with: + path: ~/.composer/cache + key: php-composer-locked-${{ hashFiles('composer.lock') }} + restore-keys: php-composer-locked- + - name: Install PHP dependencies + run: composer install --no-interaction --no-progress --no-suggest + - name: PHP CS Fixer + run: vendor/bin/php-cs-fixer --format=checkstyle | cs2pr + + phpstan: + name: PHPStan + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 7.4 + tools: composer, cs2pr + coverage: none + - name: Cache Composer dependencies + uses: actions/cache@v2 + with: + path: ~/.composer/cache + key: php-composer-locked-${{ hashFiles('composer.lock') }} + restore-keys: php-composer-locked- + - name: Install PHP dependencies + run: composer install --no-interaction --no-progress --no-suggest + - name: PHPStan + run: vendor/bin/phpstan analyse --error-format=checkstyle | cs2pr diff --git a/composer.json b/composer.json index 693d3ff50..b92ebaa90 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ "opis/closure": "^3.5.5" }, "require-dev": { - "phpunit/phpunit": "^8.5", + "phpunit/phpunit": "^8.5|^9.0", "mnapoli/phpunit-easymock": "^1.2", "doctrine/annotations": "~1.2", "ocramius/proxy-manager": "~2.0.2", diff --git a/src/Definition/Source/AnnotationBasedAutowiring.php b/src/Definition/Source/AnnotationBasedAutowiring.php index e576734c5..508e00745 100644 --- a/src/Definition/Source/AnnotationBasedAutowiring.php +++ b/src/Definition/Source/AnnotationBasedAutowiring.php @@ -237,9 +237,9 @@ private function getMethodParameter($parameterIndex, ReflectionParameter $parame } // Try to use the type-hinting - $parameterClass = $parameter->getClass(); - if ($parameterClass) { - return $parameterClass->getName(); + $parameterType = $parameter->getType(); + if ($parameterType && !$parameterType->isBuiltin() && $parameterType instanceof ReflectionNamedType) { + return $parameterType->getName(); } // Last resort, look for @param tag diff --git a/src/Definition/Source/ReflectionBasedAutowiring.php b/src/Definition/Source/ReflectionBasedAutowiring.php index 04a3e41ba..0ad4cf71f 100644 --- a/src/Definition/Source/ReflectionBasedAutowiring.php +++ b/src/Definition/Source/ReflectionBasedAutowiring.php @@ -7,6 +7,7 @@ use DI\Definition\ObjectDefinition; use DI\Definition\ObjectDefinition\MethodInjection; use DI\Definition\Reference; +use ReflectionNamedType; /** * Reads DI class definitions using reflection. @@ -62,11 +63,21 @@ private function getParametersDefinition(\ReflectionFunctionAbstract $constructo continue; } - $parameterClass = $parameter->getClass(); - - if ($parameterClass) { - $parameters[$index] = new Reference($parameterClass->getName()); + $parameterType = $parameter->getType(); + if (!$parameterType) { + // No type + continue; + } + if ($parameterType->isBuiltin()) { + // Primitive types are not supported + continue; } + if (!$parameterType instanceof ReflectionNamedType) { + // Union types are not supported + continue; + } + + $parameters[$index] = new Reference($parameterType->getName()); } return $parameters; diff --git a/src/Invoker/FactoryParameterResolver.php b/src/Invoker/FactoryParameterResolver.php index da4eff91e..ee87e28df 100644 --- a/src/Invoker/FactoryParameterResolver.php +++ b/src/Invoker/FactoryParameterResolver.php @@ -7,6 +7,7 @@ use Invoker\ParameterResolver\ParameterResolver; use Psr\Container\ContainerInterface; use ReflectionFunctionAbstract; +use ReflectionNamedType; /** * Inject the container, the definition or any other service using type-hints. @@ -42,19 +43,29 @@ public function getParameters( } foreach ($parameters as $index => $parameter) { - $parameterClass = $parameter->getClass(); - - if (!$parameterClass) { + $parameterType = $parameter->getType(); + if (!$parameterType) { + // No type + continue; + } + if ($parameterType->isBuiltin()) { + // Primitive types are not supported continue; } + if (!$parameterType instanceof ReflectionNamedType) { + // Union types are not supported + continue; + } + + $parameterClass = $parameterType->getName(); - if ($parameterClass->name === 'Psr\Container\ContainerInterface') { + if ($parameterClass === 'Psr\Container\ContainerInterface') { $resolvedParameters[$index] = $this->container; - } elseif ($parameterClass->name === 'DI\Factory\RequestedEntry') { + } elseif ($parameterClass === 'DI\Factory\RequestedEntry') { // By convention the second parameter is the definition $resolvedParameters[$index] = $providedParameters[1]; - } elseif ($this->container->has($parameterClass->name)) { - $resolvedParameters[$index] = $this->container->get($parameterClass->name); + } elseif ($this->container->has($parameterClass)) { + $resolvedParameters[$index] = $this->container->get($parameterClass); } } diff --git a/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php b/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php index 99e817a5e..ef95bef9d 100644 --- a/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php +++ b/tests/IntegrationTest/Definitions/AutowireDefinitionTest.php @@ -317,6 +317,7 @@ public function test_autowire_lazy_object(ContainerBuilder $builder) /** * @dataProvider provideContainer + * @requires PHP < 8 */ public function test_optional_parameter_followed_by_required_parameters(ContainerBuilder $builder) { @@ -333,10 +334,6 @@ public function test_optional_parameter_followed_by_required_parameters(Containe */ public function test_php71_nullable_typehint(ContainerBuilder $builder) { - if (PHP_VERSION_ID < 70100) { - $this->markTestSkipped('This test cannot run on PHP 7'); - } - $container = $builder->build(); $object = $container->get(Php71::class); diff --git a/tests/IntegrationTest/ErrorMessages/ErrorMessagesTest.php b/tests/IntegrationTest/ErrorMessages/ErrorMessagesTest.php index b10b40d6c..ab73e8e35 100644 --- a/tests/IntegrationTest/ErrorMessages/ErrorMessagesTest.php +++ b/tests/IntegrationTest/ErrorMessages/ErrorMessagesTest.php @@ -167,6 +167,7 @@ public function test_factory_not_callable(ContainerBuilder $builder) /** * @dataProvider provideContainer + * @requires PHP < 8 */ public function test_internal_class_default_parameter_value(ContainerBuilder $builder) { diff --git a/tests/UnitTest/Definition/Source/AnnotationBasedAutowiringTest.php b/tests/UnitTest/Definition/Source/AnnotationBasedAutowiringTest.php index 00af08b19..f42fe98a1 100644 --- a/tests/UnitTest/Definition/Source/AnnotationBasedAutowiringTest.php +++ b/tests/UnitTest/Definition/Source/AnnotationBasedAutowiringTest.php @@ -65,12 +65,12 @@ public function testUnguessableProperty() (new AnnotationBasedAutowiring)->autowire(AnnotationFixture4::class); } + /** + * Typed properties support requires PHP 7.4 + * @requires PHP 7.4 + */ public function testTypedProperty() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Typed properties support requires PHP7.4'); - } - $definition = (new AnnotationBasedAutowiring)->autowire(AnnotationFixtureTypedProperties::class); $this->assertNotHasPropertyInjection($definition, 'typeAndNoInject'); @@ -79,12 +79,12 @@ public function testTypedProperty() $this->assertHasPropertyInjection($definition, 'typedAndNamed', 'name'); } + /** + * Typed properties support requires PHP 7.4 + * @requires PHP 7.4 + */ public function testScalarTypedPropertiesFail() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Typed properties support requires PHP7.4'); - } - $this->expectException(\DI\Definition\Exception\InvalidAnnotation::class); (new AnnotationBasedAutowiring)->autowire(AnnotationFixtureScalarTypedProperty::class); }