Skip to content

Commit ec20a71

Browse files
authored
Merge pull request #59 from Howriq/issue-#58
Issue #58: Replace Psalm with PHPStan
2 parents c93fe44 + 19c478f commit ec20a71

10 files changed

Lines changed: 176 additions & 45 deletions

File tree

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
on:
2+
- push
3+
4+
name: Run PHPStan checks
5+
6+
jobs:
7+
mutation:
8+
name: PHPStan ${{ matrix.php }}-${{ matrix.os }}
9+
10+
runs-on: ${{ matrix.os }}
11+
12+
strategy:
13+
matrix:
14+
os:
15+
- ubuntu-latest
16+
17+
php:
18+
- "8.2"
19+
- "8.3"
20+
- "8.4"
21+
22+
steps:
23+
- name: Checkout
24+
uses: actions/checkout@v4
25+
26+
- name: Install PHP
27+
uses: shivammathur/setup-php@v2
28+
with:
29+
php-version: "${{ matrix.php }}"
30+
coverage: pcov
31+
ini-values: assert.exception=1, zend.assertions=1, error_reporting=-1, log_errors_max_len=0, display_errors=On
32+
tools: composer:v2, cs2pr
33+
34+
- name: Determine composer cache directory
35+
run: echo "COMPOSER_CACHE_DIR=$(composer config cache-dir)" >> $GITHUB_ENV
36+
37+
- name: Cache dependencies installed with composer
38+
uses: actions/cache@v4
39+
with:
40+
path: ${{ env.COMPOSER_CACHE_DIR }}
41+
key: php${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}
42+
restore-keys: |
43+
php${{ matrix.php }}-composer-
44+
45+
- name: Install dependencies with composer
46+
run: composer install --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi
47+
48+
- name: Run static analysis with PHPStan
49+
run: vendor/bin/phpstan analyse

README.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
# dot-annotated-services
22

3-
Dotkernel component used to create services through [Laminas Service Manager](https://github.com/laminas/laminas-servicemanager) and inject them with dependencies just using method annotations. It can also create services without the need to write factories. Annotation parsing can be cached, to improve performance.
3+
Dotkernel component used to create services through [Laminas Service Manager](https://github.com/laminas/laminas-servicemanager) and inject them with dependencies just using method annotations.
4+
It can also create services without the need to write factories.
5+
Annotation parsing can be cached, to improve performance.
46

57
This package can clean up your code, by getting rid of all the factories you write, sometimes just to inject a dependency or two.
68

9+
## Documentation
10+
11+
Documentation is available at: https://docs.dotkernel.org/dot-annotated-services/.
12+
13+
## Badges
14+
715
![OSS Lifecycle](https://img.shields.io/osslifecycle?file_url=https%3A%2F%2Fgithub.com%2Fdotkernel%2Fdot-annotated-services%2Fblob%2F4.0%2FOSSMETADATA)
8-
![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-annotated-services/4.2.1)
16+
![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-annotated-services/4.3.0)
917

1018
[![GitHub issues](https://img.shields.io/github/issues/dotkernel/dot-annotated-services)](https://github.com/dotkernel/dot-annotated-services/issues)
1119
[![GitHub forks](https://img.shields.io/github/forks/dotkernel/dot-annotated-services)](https://github.com/dotkernel/dot-annotated-services/network)
@@ -14,6 +22,7 @@ This package can clean up your code, by getting rid of all the factories you wri
1422

1523
[![Build Static](https://github.com/dotkernel/dot-annotated-services/actions/workflows/continuous-integration.yml/badge.svg?branch=4.0)](https://github.com/dotkernel/dot-annotated-services/actions/workflows/continuous-integration.yml)
1624
[![codecov](https://codecov.io/gh/dotkernel/dot-annotated-services/graph/badge.svg?token=ZBZDEA3LY8)](https://codecov.io/gh/dotkernel/dot-annotated-services)
25+
[![PHPStan](https://github.com/dotkernel/dot-annotated-services/actions/workflows/static-analysis.yml/badge.svg?branch=4.0)](https://github.com/dotkernel/dot-annotated-services/actions/workflows/static-analysis.yml)
1726

1827
## Installation
1928

composer.json

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
{
22
"name": "dotkernel/dot-annotated-services",
33
"type": "library",
4-
"description": "DotKernel service creation component through laminas-servicemanager and annotations",
4+
"description": "Dotkernel service creation component through laminas-servicemanager and annotations",
55
"license": "MIT",
66
"homepage": "https://github.com/dotkernel/dot-annotated-services",
77
"authors": [
88
{
9-
"name": "DotKernel Team",
9+
"name": "Dotkernel Team",
1010
"email": "team@dotkernel.com"
1111
}
1212
],
@@ -28,8 +28,9 @@
2828
},
2929
"require-dev": {
3030
"laminas/laminas-coding-standard": "^3.0",
31-
"phpunit/phpunit": "^10.5.9",
32-
"vimeo/psalm": "^6.0"
31+
"phpstan/phpstan": "^2.1",
32+
"phpstan/phpstan-phpunit": "^2.0",
33+
"phpunit/phpunit": "^10.5.9"
3334
},
3435
"autoload": {
3536
"psr-4": {
@@ -44,13 +45,13 @@
4445
"scripts": {
4546
"check": [
4647
"@cs-check",
47-
"@test"
48+
"@test",
49+
"@static-analysis"
4850
],
4951
"cs-check": "phpcs",
5052
"cs-fix": "phpcbf",
5153
"test": "phpunit --colors=always",
52-
"test-coverage": "phpunit --colors=always --coverage-clover clover.xml",
53-
"static-analysis": "psalm --shepherd --stats"
54+
"static-analysis": "phpstan analyse --memory-limit 1G"
5455
},
5556
"config": {
5657
"sort-packages": true,

docs/book/v4/overview.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
# Overview
22

3-
`dot-annotated-services` is Dotkernel's dependency injection service.
3+
`dot-annotated-services` is Dotkernel's dependency injection service using annotations.
44

55
By providing reusable factories for service and repository injection, it reduces code complexity in projects.
6+
7+
## Badges
8+
9+
![OSS Lifecycle](https://img.shields.io/osslifecycle?file_url=https%3A%2F%2Fgithub.com%2Fdotkernel%2Fdot-annotated-services%2Fblob%2F4.0%2FOSSMETADATA)
10+
![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-annotated-services/4.3.0)
11+
12+
[![GitHub issues](https://img.shields.io/github/issues/dotkernel/dot-annotated-services)](https://github.com/dotkernel/dot-annotated-services/issues)
13+
[![GitHub forks](https://img.shields.io/github/forks/dotkernel/dot-annotated-services)](https://github.com/dotkernel/dot-annotated-services/network)
14+
[![GitHub stars](https://img.shields.io/github/stars/dotkernel/dot-annotated-services)](https://github.com/dotkernel/dot-annotated-services/stargazers)
15+
[![GitHub license](https://img.shields.io/github/license/dotkernel/dot-annotated-services)](https://github.com/dotkernel/dot-annotated-services/blob/4.0/LICENSE.md)
16+
17+
[![Build Static](https://github.com/dotkernel/dot-annotated-services/actions/workflows/continuous-integration.yml/badge.svg?branch=4.0)](https://github.com/dotkernel/dot-annotated-services/actions/workflows/continuous-integration.yml)
18+
[![codecov](https://codecov.io/gh/dotkernel/dot-annotated-services/graph/badge.svg?token=ZBZDEA3LY8)](https://codecov.io/gh/dotkernel/dot-annotated-services)
19+
[![PHPStan](https://github.com/dotkernel/dot-annotated-services/actions/workflows/static-analysis.yml/badge.svg?branch=4.0)](https://github.com/dotkernel/dot-annotated-services/actions/workflows/static-analysis.yml)

docs/book/v5/overview.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Overview
22

3-
`dot-annotated-services` is DotKernel's dependency injection service.
3+
`dot-annotated-services` is Dotkernel's dependency injection service.
44

55
By providing reusable factories for service and repository injection, it reduces code complexity in projects.
66

phpstan.neon

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
includes:
2+
- vendor/phpstan/phpstan-phpunit/extension.neon
3+
parameters:
4+
level: 5
5+
paths:
6+
- src
7+
- test
8+
treatPhpDocTypesAsCertain: false

psalm.xml

Lines changed: 0 additions & 17 deletions
This file was deleted.

test/AnnotatedRepositoryFactoryTest.php

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,38 @@
1010
use Dot\AnnotatedServices\Annotation\Entity;
1111
use Dot\AnnotatedServices\Exception\RuntimeException;
1212
use Dot\AnnotatedServices\Factory\AnnotatedRepositoryFactory as Subject;
13+
//use DotTest\AnnotatedServices\TestClass;
14+
use PHPUnit\Framework\MockObject\Exception;
15+
use PHPUnit\Framework\MockObject\MockObject;
1316
use PHPUnit\Framework\TestCase;
17+
use Psr\Container\ContainerExceptionInterface;
1418
use Psr\Container\ContainerInterface;
19+
use Psr\Container\NotFoundExceptionInterface;
20+
use ReflectionException;
1521

1622
use function get_class;
1723

1824
class AnnotatedRepositoryFactoryTest extends TestCase
1925
{
20-
private ContainerInterface $container;
21-
22-
private Subject $subject;
23-
24-
private Reader $annotationReader;
26+
private MockObject&ContainerInterface $container;
27+
private MockObject&Subject $subject;
28+
private MockObject&Reader $annotationReader;
2529

30+
/**
31+
* @throws Exception
32+
*/
2633
public function setUp(): void
2734
{
2835
$this->container = $this->createMock(ContainerInterface::class);
2936
$this->annotationReader = $this->createMock(Reader::class);
3037
$this->subject = $this->createPartialMock(Subject::class, ['createAnnotationReader']);
3138
}
3239

40+
/**
41+
* @throws ContainerExceptionInterface
42+
* @throws NotFoundExceptionInterface
43+
* @throws ReflectionException
44+
*/
3345
public function testThrowsExceptionClassNotFound()
3446
{
3547
$requestedName = 'TestRepository';
@@ -39,9 +51,14 @@ public function testThrowsExceptionClassNotFound()
3951
$this->subject->__invoke($this->container, $requestedName);
4052
}
4153

54+
/**
55+
* @throws ContainerExceptionInterface
56+
* @throws ReflectionException
57+
* @throws NotFoundExceptionInterface
58+
*/
4259
public function testThrowsExceptionClassNotExtendsEntityRepository()
4360
{
44-
$requestedName = 'TestRepository';
61+
$requestedName = TestClass::class;
4562

4663
$this->getMockBuilder($requestedName)->getMock();
4764

@@ -50,6 +67,12 @@ public function testThrowsExceptionClassNotExtendsEntityRepository()
5067
$this->subject->__invoke($this->container, $requestedName);
5168
}
5269

70+
/**
71+
* @throws ContainerExceptionInterface
72+
* @throws NotFoundExceptionInterface
73+
* @throws Exception
74+
* @throws ReflectionException
75+
*/
5376
public function testCreateObjectThrowsExceptionAnnotationNotFound()
5477
{
5578
$repository = $this->createMock(EntityRepository::class);
@@ -67,6 +90,12 @@ public function testCreateObjectThrowsExceptionAnnotationNotFound()
6790
$this->subject->__invoke($this->container, $repository::class);
6891
}
6992

93+
/**
94+
* @throws ContainerExceptionInterface
95+
* @throws Exception
96+
* @throws NotFoundExceptionInterface
97+
* @throws ReflectionException
98+
*/
7099
public function testCreateObjectReturnsEntityRepository()
71100
{
72101
$repository = $this->createMock(EntityRepository::class);
@@ -87,6 +116,6 @@ public function testCreateObjectReturnsEntityRepository()
87116

88117
$object = $this->subject->__invoke($this->container, $repository::class);
89118

90-
$this->assertInstanceOf(EntityRepository::class, $object);
119+
$this->assertContainsOnlyInstancesOf(EntityRepository::class, [$object]);
91120
}
92121
}

test/AnnotatedServiceFactoryTest.php

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,27 @@
88
use Dot\AnnotatedServices\Annotation\Inject;
99
use Dot\AnnotatedServices\Exception\RuntimeException;
1010
use Dot\AnnotatedServices\Factory\AnnotatedServiceFactory as Subject;
11+
use PHPUnit\Framework\MockObject\Exception;
12+
use PHPUnit\Framework\MockObject\MockObject;
1113
use PHPUnit\Framework\TestCase;
14+
use Psr\Container\ContainerExceptionInterface;
1215
use Psr\Container\ContainerInterface;
16+
use Psr\Container\NotFoundExceptionInterface;
1317
use ReflectionClass;
18+
use ReflectionException;
1419
use ReflectionMethod;
1520

1621
use function get_class;
1722

1823
class AnnotatedServiceFactoryTest extends TestCase
1924
{
20-
private ContainerInterface $container;
21-
22-
private Subject $subject;
23-
24-
private Reader $annotationReader;
25+
private MockObject&ContainerInterface $container;
26+
private MockObject&Subject $subject;
27+
private MockObject&Reader $annotationReader;
2528

29+
/**
30+
* @throws Exception
31+
*/
2632
public function setUp(): void
2733
{
2834
$this->container = $this->createMock(ContainerInterface::class);
@@ -33,6 +39,11 @@ public function setUp(): void
3339
]);
3440
}
3541

42+
/**
43+
* @throws ContainerExceptionInterface
44+
* @throws NotFoundExceptionInterface
45+
* @throws ReflectionException
46+
*/
3647
public function testThrowsExceptionClassNotFound()
3748
{
3849
$requestedName = 'TestService';
@@ -43,9 +54,15 @@ public function testThrowsExceptionClassNotFound()
4354
$this->subject->__invoke($this->container, $requestedName);
4455
}
4556

57+
/**
58+
* @throws ContainerExceptionInterface
59+
* @throws Exception
60+
* @throws NotFoundExceptionInterface
61+
* @throws ReflectionException
62+
*/
4663
public function testReturnServiceWithNoDependencies()
4764
{
48-
$requestedName = 'TestService';
65+
$requestedName = TestClass::class;
4966
$this->getMockBuilder($requestedName)->allowMockingUnknownTypes()->getMock();
5067
$refClass = $this->createMock(ReflectionClass::class);
5168

@@ -60,12 +77,18 @@ public function testReturnServiceWithNoDependencies()
6077

6178
$object = $this->subject->__invoke($this->container, $requestedName);
6279

63-
$this->assertInstanceOf($requestedName, $object);
80+
$this->assertSame($requestedName, $object::class);
6481
}
6582

83+
/**
84+
* @throws ContainerExceptionInterface
85+
* @throws Exception
86+
* @throws NotFoundExceptionInterface
87+
* @throws ReflectionException
88+
*/
6689
public function testThrowsExceptionAnnotationNotFound()
6790
{
68-
$requestedName = 'TestService';
91+
$requestedName = TestClass::class;
6992
$this->getMockBuilder($requestedName)->allowMockingUnknownTypes()->getMock();
7093
$refClass = $this->createMock(ReflectionClass::class);
7194
$refConstructor = $this->createMock(ReflectionMethod::class);
@@ -89,9 +112,15 @@ public function testThrowsExceptionAnnotationNotFound()
89112
$this->subject->__invoke($this->container, $requestedName);
90113
}
91114

115+
/**
116+
* @throws ContainerExceptionInterface
117+
* @throws Exception
118+
* @throws NotFoundExceptionInterface
119+
* @throws ReflectionException
120+
*/
92121
public function testReturnService()
93122
{
94-
$requestedName = 'TestService';
123+
$requestedName = TestClass::class;
95124
$this->getMockBuilder($requestedName)->allowMockingUnknownTypes()->getMock();
96125
$refClass = $this->createMock(ReflectionClass::class);
97126
$refConstructor = $this->createMock(ReflectionMethod::class);
@@ -108,6 +137,6 @@ public function testReturnService()
108137

109138
$service = $this->subject->__invoke($this->container, $requestedName);
110139

111-
$this->assertInstanceOf($requestedName, $service);
140+
$this->assertSame($requestedName, $service::class);
112141
}
113142
}

test/TestClass.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace DotTest\AnnotatedServices;
6+
7+
class TestClass
8+
{
9+
}

0 commit comments

Comments
 (0)