Skip to content

Commit 825a1a1

Browse files
committed
First version
1 parent d22478b commit 825a1a1

14 files changed

+320
-0
lines changed

.coveralls.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
service_name: travis-ci
2+
coverage_clover: tests/tmp/clover.xml
3+
json_path: tests/tmp/coveralls.json

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/tests export-ignore

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/composer.lock
2+
/vendor

.travis.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
language: php
2+
php:
3+
- 7.0
4+
- 7.1
5+
before_script:
6+
- composer self-update
7+
- composer install
8+
script:
9+
- vendor/bin/phing
10+
after_script:
11+
- php vendor/bin/coveralls -v

README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Doctrine extensions for PHPStan
2+
3+
[![Build Status](https://travis-ci.org/phpstan/phpstan-doctrine.svg)](https://travis-ci.org/phpstan/phpstan-doctrine)
4+
[![Latest Stable Version](https://poser.pugx.org/phpstan/phpstan-doctrine/v/stable)](https://packagist.org/packages/phpstan/phpstan-doctrine)
5+
[![License](https://poser.pugx.org/phpstan/phpstan-doctrine/license)](https://packagist.org/packages/phpstan/phpstan-doctrine)
6+
7+
* [PHPStan](https://github.com/phpstan/phpstan)
8+
* [Doctrine](http://www.doctrine-project.org/)
9+
10+
This extension provides following features:
11+
12+
* Provides correct return type for `Doctrine\ORM\EntityManager::find`, `getReference` and `getPartialReference` when `Foo::class` entity class name is provided as the first argument
13+
* Adds missing `matching` method on `Doctrine\Common\Collections\Collection`
14+
15+
## Usage
16+
17+
To use this extension, require it in [Composer](https://getcomposer.org/):
18+
19+
```
20+
composer require --dev phpstan/phpstan-doctrine
21+
```
22+
23+
And include extension.neon in your project's PHPStan config:
24+
25+
```
26+
includes:
27+
- vendor/phpstan/phpstan-doctrine/extension.neon
28+
```

build.xml

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<project name="PHPStan Doctrine extensions" default="check">
3+
4+
<target name="check" depends="
5+
composer,
6+
lint,
7+
cs,
8+
tests,
9+
phpstan
10+
"/>
11+
12+
<target name="composer">
13+
<exec
14+
executable="composer"
15+
logoutput="true"
16+
passthru="true"
17+
checkreturn="true"
18+
>
19+
<arg value="install"/>
20+
</exec>
21+
</target>
22+
23+
<target name="lint">
24+
<exec
25+
executable="vendor/bin/parallel-lint"
26+
logoutput="true"
27+
passthru="true"
28+
checkreturn="true"
29+
>
30+
<arg value="--exclude"/>
31+
<arg path="tests/PHPStan/Analyser/data"/>
32+
<arg path="src" />
33+
<arg path="tests" />
34+
</exec>
35+
</target>
36+
37+
<target name="cs">
38+
<exec
39+
executable="vendor/bin/phpcs"
40+
logoutput="true"
41+
passthru="true"
42+
checkreturn="true"
43+
>
44+
<arg value="--standard=ruleset.xml"/>
45+
<arg value="--extensions=php"/>
46+
<arg value="--encoding=utf-8"/>
47+
<arg value="--tab-width=4"/>
48+
<arg value="--ignore=tests/*/data"/>
49+
<arg value="-sp"/>
50+
<arg path="src"/>
51+
<arg path="tests"/>
52+
</exec>
53+
</target>
54+
55+
<target name="cs-fix">
56+
<exec
57+
executable="vendor/bin/phpcbf"
58+
logoutput="true"
59+
passthru="true"
60+
checkreturn="true"
61+
>
62+
<arg value="--standard=ruleset.xml"/>
63+
<arg value="--extensions=php"/>
64+
<arg value="--encoding=utf-8"/>
65+
<arg value="--tab-width=4"/>
66+
<arg value="--ignore=tests/*/data"/>
67+
<arg value="-sp"/>
68+
<arg path="src"/>
69+
<arg path="tests"/>
70+
</exec>
71+
</target>
72+
73+
<target name="tests">
74+
<exec
75+
executable="vendor/bin/phpunit"
76+
logoutput="true"
77+
passthru="true"
78+
checkreturn="true"
79+
>
80+
<arg value="-c"/>
81+
<arg value="tests/phpunit.xml"/>
82+
<arg path="tests"/>
83+
</exec>
84+
</target>
85+
86+
<target name="phpstan">
87+
<exec
88+
executable="vendor/bin/phpstan"
89+
logoutput="true"
90+
passthru="true"
91+
checkreturn="true"
92+
>
93+
<arg value="analyse"/>
94+
<arg value="-l"/>
95+
<arg value="4"/>
96+
<arg value="-c"/>
97+
<arg path="phpstan.neon"/>
98+
<arg path="src"/>
99+
<arg path="tests"/>
100+
</exec>
101+
</target>
102+
103+
</project>

composer.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "phpstan/phpstan-doctrine",
3+
"description": "Doctrine extensions for PHPStan",
4+
"license": ["MIT"],
5+
"minimum-stability": "dev",
6+
"prefer-stable": true,
7+
"require": {
8+
"php": "~7.0",
9+
"phpstan/phpstan": "^0.6",
10+
"doctrine/common": "^2.7",
11+
"doctrine/orm": "^2.5"
12+
},
13+
"require-dev": {
14+
"consistence/coding-standard": "~0.12.0",
15+
"phing/phing": "^2.16.0",
16+
"phpunit/phpunit": "^5.7",
17+
"slevomat/coding-standard": "dev-php7#d4a1a9c"
18+
},
19+
"autoload": {
20+
"psr-4": {
21+
"PHPStan\\": "src/"
22+
}
23+
},
24+
"autoload-dev": {
25+
"classmap": ["tests/"]
26+
}
27+
}

extension.neon

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
services:
2+
-
3+
class: PHPStan\Reflection\Doctrine\DoctrineSelectableClassReflectionExtension
4+
tags:
5+
- phpstan.broker.methodsClassReflectionExtension
6+
-
7+
class: PHPStan\Type\Doctrine\EntityManagerFindDynamicReturnTypeExtension
8+
tags:
9+
- phpstan.broker.dynamicMethodReturnTypeExtension

phpstan.neon

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
parameters:
2+
ignoreErrors: []

ruleset.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0"?>
2+
<ruleset name="PHPStan Doctrine extensions">
3+
<rule ref="vendor/consistence/coding-standard/Consistence/ruleset.xml"/>
4+
<rule ref="vendor/slevomat/coding-standard/SlevomatCodingStandard/ruleset.xml">
5+
<exclude name="SlevomatCodingStandard.Files.TypeNameMatchesFileName"/>
6+
<exclude name="SlevomatCodingStandard.Namespaces.FullyQualifiedClassNameAfterKeyword"/>
7+
<exclude name="SlevomatCodingStandard.Namespaces.UseOnlyWhitelistedNamespaces"/>
8+
<exclude name="SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly"/>
9+
</rule>
10+
<rule ref="SlevomatCodingStandard.Typehints.TypeHintDeclaration">
11+
<properties>
12+
<property name="usefulAnnotations" type="array" value="
13+
@dataProvider
14+
"/>
15+
</properties>
16+
</rule>
17+
</ruleset>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Reflection\Doctrine;
4+
5+
class DoctrineSelectableClassReflectionExtension implements \PHPStan\Reflection\MethodsClassReflectionExtension, \PHPStan\Reflection\BrokerAwareClassReflectionExtension
6+
{
7+
8+
/** @var \PHPStan\Broker\Broker */
9+
private $broker;
10+
11+
public function setBroker(\PHPStan\Broker\Broker $broker)
12+
{
13+
$this->broker = $broker;
14+
}
15+
16+
public function hasMethod(\PHPStan\Reflection\ClassReflection $classReflection, string $methodName): bool
17+
{
18+
return $classReflection->getName() === \Doctrine\Common\Collections\Collection::class
19+
&& $methodName === 'matching';
20+
}
21+
22+
public function getMethod(\PHPStan\Reflection\ClassReflection $classReflection, string $methodName): \PHPStan\Reflection\MethodReflection
23+
{
24+
$selectableReflection = $this->broker->getClass(\Doctrine\Common\Collections\Selectable::class);
25+
return $selectableReflection->getMethod($methodName);
26+
}
27+
28+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Doctrine;
4+
5+
use PhpParser\Node\Expr\MethodCall;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Reflection\MethodReflection;
8+
use PHPStan\Type\ObjectType;
9+
use PHPStan\Type\Type;
10+
11+
class EntityManagerFindDynamicReturnTypeExtension implements \PHPStan\Type\DynamicMethodReturnTypeExtension
12+
{
13+
14+
public static function getClass(): string
15+
{
16+
return \Doctrine\ORM\EntityManager::class;
17+
}
18+
19+
public function isMethodSupported(MethodReflection $methodReflection): bool
20+
{
21+
return in_array($methodReflection->getName(), [
22+
'find',
23+
'getReference',
24+
'getPartialReference',
25+
], true);
26+
}
27+
28+
public function getTypeFromMethodCall(
29+
MethodReflection $methodReflection,
30+
MethodCall $methodCall,
31+
Scope $scope
32+
): Type
33+
{
34+
if (count($methodCall->args) === 0) {
35+
return $methodReflection->getReturnType();
36+
}
37+
$arg = $methodCall->args[0]->value;
38+
if (!($arg instanceof \PhpParser\Node\Expr\ClassConstFetch)) {
39+
return $methodReflection->getReturnType();
40+
}
41+
42+
$class = $arg->class;
43+
if (!($class instanceof \PhpParser\Node\Name)) {
44+
return $methodReflection->getReturnType();
45+
}
46+
47+
$class = (string) $class;
48+
49+
if ($class === 'static') {
50+
return $methodReflection->getReturnType();
51+
}
52+
53+
if ($class === 'self') {
54+
$class = $scope->getClass();
55+
}
56+
57+
return new ObjectType($class, $methodReflection->getName() === 'find');
58+
}
59+
60+
}

tests/bootstrap.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<?php declare(strict_types = 1);
2+
3+
require_once __DIR__ . '/../vendor/autoload.php';

tests/phpunit.xml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<phpunit
2+
bootstrap="bootstrap.php"
3+
colors="true"
4+
backupGlobals="false"
5+
backupStaticAttributes="false"
6+
beStrictAboutChangesToGlobalState="true"
7+
beStrictAboutOutputDuringTests="true"
8+
beStrictAboutTestsThatDoNotTestAnything="true"
9+
beStrictAboutTodoAnnotatedTests="true"
10+
failOnRisky="true"
11+
failOnWarning="true"
12+
>
13+
<filter>
14+
<whitelist>
15+
<directory suffix=".php">../src</directory>
16+
</whitelist>
17+
</filter>
18+
<logging>
19+
<log
20+
type="coverage-text"
21+
target="php://stdout"
22+
showUncoveredFiles="true"
23+
showOnlySummary="true"
24+
/>
25+
</logging>
26+
</phpunit>

0 commit comments

Comments
 (0)