Skip to content

Commit

Permalink
chore: psalm plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
nikophil committed Jul 21, 2023
1 parent 7dfd952 commit 8abd8e3
Show file tree
Hide file tree
Showing 36 changed files with 498 additions and 549 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ docker-start: ### Start containers

.PHONY: docker-stop
docker-stop: ### Stop containers
@rm $(DOCKER_PHP_CONTAINER_FLAG)
@rm $(DOCKER_PHP_CONTAINER_FLAG) || true
@$(DOCKER_COMPOSE) stop

.PHONY: docker-purge
Expand Down
9 changes: 9 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"zenstruck/callback": "^1.1"
},
"require-dev": {
"ext-simplexml": "*",
"bamarni/composer-bin-plugin": "^1.4",
"dama/doctrine-test-bundle": "^7.0",
"doctrine/doctrine-bundle": "^2.5",
Expand Down Expand Up @@ -63,6 +64,14 @@
"target-directory": "bin/tools",
"bin-links": true,
"forward-command": false
},
"phpstan": {
"includes": [
"phpstan-foundry.neon"
]
},
"psalm": {
"pluginClass": "Zenstruck\\Foundry\\Psalm\\FoundryPlugin"
}
},
"minimum-stability": "dev",
Expand Down
30 changes: 0 additions & 30 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,6 @@ parameters:
count: 1
path: src/AnonymousFactory.php

-
message: "#^Method Zenstruck\\\\Foundry\\\\AnonymousFactory\\:\\:many\\(\\) should return Zenstruck\\\\Foundry\\\\FactoryCollection\\<TModel of object\\> but returns Zenstruck\\\\Foundry\\\\FactoryCollection\\<object\\>\\.$#"
count: 1
path: src/AnonymousFactory.php

-
message: "#^Method Zenstruck\\\\Foundry\\\\AnonymousFactory\\:\\:sequence\\(\\) should return Zenstruck\\\\Foundry\\\\FactoryCollection\\<TModel of object\\> but returns Zenstruck\\\\Foundry\\\\FactoryCollection\\<object\\>\\.$#"
count: 1
path: src/AnonymousFactory.php

-
message: "#^Parameter \\#1 \\$objectOrClass of class ReflectionClass constructor expects class\\-string\\<T of object\\>\\|T of object, string\\|null given\\.$#"
count: 1
Expand Down Expand Up @@ -89,23 +79,3 @@ parameters:
message: "#^Parameter \\#2 \\$configuration of static method Zenstruck\\\\Foundry\\\\BaseFactory\\<mixed\\>\\:\\:boot\\(\\) expects Zenstruck\\\\Foundry\\\\Configuration, object\\|null given\\.$#"
count: 1
path: src/ZenstruckFoundryBundle.php

-
message: "#^Function Zenstruck\\\\Foundry\\\\create\\(\\) should return \\(T of object\\)\\|Zenstruck\\\\Foundry\\\\Proxy\\<T of object\\> but returns object\\.$#"
count: 1
path: src/functions.php

-
message: "#^Function Zenstruck\\\\Foundry\\\\create_many\\(\\) should return array\\<int, \\(T of object\\)\\|Zenstruck\\\\Foundry\\\\Proxy\\<T of object\\>\\> but returns array\\<int, object\\>\\.$#"
count: 1
path: src/functions.php

-
message: "#^Function Zenstruck\\\\Foundry\\\\instantiate\\(\\) should return \\(T of object\\)\\|Zenstruck\\\\Foundry\\\\Proxy\\<T of object\\> but returns object\\.$#"
count: 1
path: src/functions.php

-
message: "#^Function Zenstruck\\\\Foundry\\\\instantiate_many\\(\\) should return array\\<int, \\(T of object\\)\\|Zenstruck\\\\Foundry\\\\Proxy\\<T of object\\>\\> but returns array\\<int, object\\>\\.$#"
count: 1
path: src/functions.php
4 changes: 2 additions & 2 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ parameters:
- ./src

# let's analyse factories generated with maker
- ./tests/Fixtures/Maker/expected/can_create_factory_for_entity_with_repository_with_data_set_phpstan.php
- ./tests/Fixtures/Maker/expected/can_create_factory_with_static_analysis_annotations_with_data_set_phpstan.php
- ./tests/Fixtures/Maker/expected/can_create_factory.php
level: 8
bootstrapFiles:
- ./vendor/autoload.php
Expand All @@ -35,3 +34,4 @@ parameters:
excludePaths:
- ./src/Bundle/Resources
- ./src/PhpStan
- ./src/Psalm
9 changes: 7 additions & 2 deletions psalm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@
xsi:schemaLocation="https://getpsalm.org/schema/config bin/tools/psalm/vendor/vimeo/psalm/config.xsd"
findUnusedBaselineEntry="true"
findUnusedCode="false"
autoloader="vendor/autoload.php"
>
<projectFiles>
<file name="tests/Fixtures/Maker/expected/can_create_factory_for_entity_with_repository_with_data_set_psalm.php" />
<file name="tests/Fixtures/Maker/expected/can_create_factory_with_static_analysis_annotations_with_data_set_psalm.php" />
<file name="tests/Fixtures/Maker/expected/can_create_factory.php"/>
<file name="tests/Fixtures/Psalm/test-types-with-persistence.php"/>
<file name="tests/Fixtures/Psalm/test-types-without-persistence.php"/>
</projectFiles>
<plugins>
<pluginClass class="Zenstruck\Foundry\Psalm\FoundryPlugin"/>
</plugins>
</psalm>
2 changes: 1 addition & 1 deletion src/AnonymousFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
*
* @deprecated
*
* @phpstan-import-type SequenceAttributes from BaseFactory
* @psalm-import-type SequenceAttributes from BaseFactory
*/
final class AnonymousFactory implements \Countable, \IteratorAggregate
{
Expand Down
27 changes: 13 additions & 14 deletions src/BaseFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,9 @@
*
* @template T
*
* @method static list<T> createMany(int $number, Attributes $attributes = [])
*
* @phpstan-type Parameters array<string,mixed>
* @phpstan-type Attributes Parameters|(callable():Parameters)
* @phpstan-type SequenceAttributes iterable<Parameters>|(callable(): iterable<Parameters>)
* @psalm-type Parameters = array<string,mixed>
* @psalm-type Attributes = Parameters|(callable():Parameters)
* @psalm-type SequenceAttributes = iterable<Parameters>|callable(): iterable<Parameters>
*/
abstract class BaseFactory
{
Expand All @@ -51,15 +49,6 @@ public function __call(string $name, array $arguments): array
return $this->many($arguments[0])->create($arguments[1] ?? []);
}

public static function __callStatic(string $name, array $arguments): array
{
if ('createMany' !== $name) {
throw new \BadMethodCallException(\sprintf('Call to undefined static method "%s::%s".', static::class, $name));
}

return static::new()->many($arguments[0])->create($arguments[1] ?? []);
}

/**
* @param Attributes|string $attributes
*/
Expand Down Expand Up @@ -117,6 +106,16 @@ final public static function createOne(array|callable $attributes = []): mixed
*/
abstract public function create(array|callable $attributes = []): mixed;

/**
* @param Attributes $attributes
*
* @return list<T>
*/
public static function createMany(int $min, array|callable $attributes = []): array
{
return static::new()->many($min)->create($attributes);
}

/**
* @param int|null $max If set, when created, the collection will be a random size between $min and $max
*
Expand Down
15 changes: 0 additions & 15 deletions src/Bundle/Maker/Factory/FactoryGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,16 @@
use Symfony\Bundle\MakerBundle\Str;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\HttpKernel\KernelInterface;
use Zenstruck\Foundry\Bundle\Maker\Factory\Exception\FactoryClassAlreadyExistException;

/**
* @internal
*/
final class FactoryGenerator
{
public const PHPSTAN_PATH = '/vendor/phpstan/phpstan/phpstan';
public const PSALM_PATH = '/vendor/vimeo/psalm/psalm';

/** @param \Traversable<int, DefaultPropertiesGuesser> $defaultPropertiesGuessers */
public function __construct(
private ManagerRegistry $managerRegistry,
private KernelInterface $kernel,
private \Traversable $defaultPropertiesGuessers,
private FactoryClassMap $factoryClassMap,
private NamespaceGuesser $namespaceGuesser,
Expand Down Expand Up @@ -136,17 +131,7 @@ private function createMakeFactoryData(Generator $generator, string $class, Make
$object,
$factory,
$repository ?? null,
$this->staticAnalysisTool(),
$persisted
);
}

private function staticAnalysisTool(): string
{
return match (true) {
\file_exists($this->kernel->getProjectDir().self::PHPSTAN_PATH) => MakeFactoryData::STATIC_ANALYSIS_TOOL_PHPSTAN,
\file_exists($this->kernel->getProjectDir().self::PSALM_PATH) => MakeFactoryData::STATIC_ANALYSIS_TOOL_PSALM,
default => MakeFactoryData::STATIC_ANALYSIS_TOOL_NONE,
};
}
}
16 changes: 1 addition & 15 deletions src/Bundle/Maker/Factory/MakeFactoryData.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,14 @@
*/
final class MakeFactoryData
{
public const STATIC_ANALYSIS_TOOL_NONE = 'none';
public const STATIC_ANALYSIS_TOOL_PHPSTAN = 'phpstan';
public const STATIC_ANALYSIS_TOOL_PSALM = 'psalm';

/** @var list<string> */
private array $uses;
/** @var array<string, string> */
private array $defaultProperties = [];
/** @var non-empty-list<MakeFactoryPHPDocMethod> */
private array $methodsInPHPDoc;

public function __construct(private \ReflectionClass $object, private ClassNameDetails $factoryClassNameDetails, private ?\ReflectionClass $repository, private string $staticAnalysisTool, private bool $persisted)
public function __construct(private \ReflectionClass $object, private ClassNameDetails $factoryClassNameDetails, private ?\ReflectionClass $repository, private bool $persisted)
{
$this->uses = [
PersistentObjectFactory::class,
Expand Down Expand Up @@ -80,16 +76,6 @@ public function isPersisted(): bool
return $this->persisted;
}

public function hasStaticAnalysisTool(): bool
{
return self::STATIC_ANALYSIS_TOOL_NONE !== $this->staticAnalysisTool;
}

public function staticAnalysisTool(): string
{
return $this->staticAnalysisTool;
}

/** @param class-string $use */
public function addUse(string $use): void
{
Expand Down
19 changes: 6 additions & 13 deletions src/Bundle/Maker/Factory/MakeFactoryPHPDocMethod.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,27 +52,20 @@ public static function createAll(MakeFactoryData $makeFactoryData): array
return $methods;
}

public function toString(string|null $staticAnalysisTool = null): string
public function toString(): string
{
$annotation = $staticAnalysisTool ? "{$staticAnalysisTool}-method" : 'method';
$static = $this->isStatic ? 'static' : ' ';

if ($this->repository) {
$returnType = match ((bool) $staticAnalysisTool) {
false => "{$this->repository}|RepositoryProxy",
true => "RepositoryProxy<{$this->objectName}>",
};
$returnType = "{$this->repository}|RepositoryProxy";
} else {
/** @phpstan-ignore-next-line */
$returnType = match ([$this->returnsCollection, (bool) $staticAnalysisTool]) {
[true, true] => "list<Proxy<{$this->objectName}>>",
[true, false] => "{$this->objectName}[]|Proxy[]",
[false, true] => "Proxy<{$this->objectName}>",
[false, false] => "{$this->objectName}|Proxy",
$returnType = match ($this->returnsCollection) {
true => "{$this->objectName}[]|Proxy[]",
false => "{$this->objectName}|Proxy",
};
}

return " * @{$annotation} {$static} {$returnType} {$this->prototype}";
return " * @method {$static} {$returnType} {$this->prototype}";
}

public function sortValue(): string
Expand Down
1 change: 0 additions & 1 deletion src/Bundle/Resources/config/maker.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@

<service id=".zenstruck_foundry.maker.factory.generator" class="Zenstruck\Foundry\Bundle\Maker\Factory\FactoryGenerator">
<argument type="service" id=".zenstruck_foundry.chain_manager_registry" />
<argument type="service" id="kernel" />
<argument type="tagged_iterator" tag="foundry.make_factory.default_properties_guesser" />
<argument type="service" id=".zenstruck_foundry.maker.factory.factory_class_map" />
<argument type="service" id=".zenstruck_foundry.maker.factory.namespace_guesser" />
Expand Down
8 changes: 0 additions & 8 deletions src/Bundle/Resources/skeleton/Factory.tpl.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,6 @@
foreach ($makeFactoryData->getMethodsPHPDoc() as $methodPHPDoc) {
echo "{$methodPHPDoc->toString()}\n";
}

//if ($makeFactoryData->hasStaticAnalysisTool()) {
// echo " *\n";
//
// foreach ($makeFactoryData->getMethodsPHPDoc() as $methodPHPDoc) {
// echo "{$methodPHPDoc->toString($makeFactoryData->staticAnalysisTool())}\n";
// }
//}
?>
*/
final class <?= $class_name ?> extends PersistentObjectFactory
Expand Down
4 changes: 2 additions & 2 deletions src/FactoryCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
*
* @author Kevin Bond <kevinbond@gmail.com>
*
* @phpstan-import-type Parameters from BaseFactory
* @phpstan-import-type Attributes from BaseFactory
* @psalm-import-type Parameters from BaseFactory
* @psalm-import-type Attributes from BaseFactory
*/
final class FactoryCollection implements \IteratorAggregate
{
Expand Down
2 changes: 1 addition & 1 deletion src/FactoryManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
*
* @internal
*
* @phpstan-import-type CallableInstantiator from ObjectFactory
* @psalm-import-type CallableInstantiator from ObjectFactory
*/
final class FactoryManager
{
Expand Down
2 changes: 1 addition & 1 deletion src/Instantiator.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
* @author Kevin Bond <kevinbond@gmail.com>
* @template T of object
*
* @phpstan-import-type Parameters from BaseFactory
* @psalm-import-type Parameters from BaseFactory
*/
final class Instantiator
{
Expand Down
11 changes: 8 additions & 3 deletions src/Object/ObjectFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
* @template T of object
* @extends BaseFactory<T>
*
* @phpstan-type CallableInstantiator Instantiator<T>|\Closure(Parameters,class-string<T>):T
* @psalm-type CallableInstantiator = Instantiator<T>|\Closure(Parameters,class-string<T>):T
*
* @phpstan-import-type Parameters from BaseFactory
* @phpstan-import-type Attributes from BaseFactory
* @psalm-import-type Parameters from BaseFactory
* @psalm-import-type Attributes from BaseFactory
*/
abstract class ObjectFactory extends BaseFactory
{
Expand All @@ -42,6 +42,11 @@ abstract class ObjectFactory extends BaseFactory
*/
abstract public static function class(): string;

/**
* @param Attributes $attributes
*
* @return T
*/
public function create(array|callable $attributes = []): object
{
return $this->normalizeAndInstantiate($attributes)[0];
Expand Down
Loading

0 comments on commit 8abd8e3

Please sign in to comment.