mirror of
https://github.com/danog/psalm-plugin-symfony.git
synced 2024-11-26 11:55:00 +01:00
Form get errors (#243)
* FormGetErrors provider * Wip * Add stub * Update stub
This commit is contained in:
parent
83830775d5
commit
f5348e9a7c
@ -15,6 +15,7 @@ use Psalm\SymfonyPsalmPlugin\Handler\DoctrineRepositoryHandler;
|
||||
use Psalm\SymfonyPsalmPlugin\Handler\HeaderBagHandler;
|
||||
use Psalm\SymfonyPsalmPlugin\Handler\ParameterBagHandler;
|
||||
use Psalm\SymfonyPsalmPlugin\Handler\RequiredSetterHandler;
|
||||
use Psalm\SymfonyPsalmPlugin\Provider\FormGetErrorsReturnTypeProvider;
|
||||
use Psalm\SymfonyPsalmPlugin\Symfony\ContainerMeta;
|
||||
use Psalm\SymfonyPsalmPlugin\Twig\AnalyzedTemplatesTainter;
|
||||
use Psalm\SymfonyPsalmPlugin\Twig\CachedTemplatesMapping;
|
||||
@ -39,6 +40,7 @@ class Plugin implements PluginEntryPointInterface
|
||||
require_once __DIR__.'/Handler/ContainerDependencyHandler.php';
|
||||
require_once __DIR__.'/Handler/RequiredSetterHandler.php';
|
||||
require_once __DIR__.'/Handler/DoctrineQueryBuilderHandler.php';
|
||||
require_once __DIR__.'/Provider/FormGetErrorsReturnTypeProvider.php';
|
||||
|
||||
$api->registerHooksFromClass(HeaderBagHandler::class);
|
||||
$api->registerHooksFromClass(ConsoleHandler::class);
|
||||
@ -99,6 +101,8 @@ class Plugin implements PluginEntryPointInterface
|
||||
|
||||
TemplateFileAnalyzer::setTemplateRootPath($twig_root_path);
|
||||
}
|
||||
|
||||
$api->registerHooksFromClass(FormGetErrorsReturnTypeProvider::class);
|
||||
}
|
||||
|
||||
private function addStubs(RegistrationInterface $api, string $path): void
|
||||
|
55
src/Provider/FormGetErrorsReturnTypeProvider.php
Normal file
55
src/Provider/FormGetErrorsReturnTypeProvider.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Psalm\SymfonyPsalmPlugin\Provider;
|
||||
|
||||
use Psalm\Plugin\EventHandler\Event\MethodReturnTypeProviderEvent;
|
||||
use Psalm\Type;
|
||||
use Psalm\Type\Atomic\TNamedObject;
|
||||
use Symfony\Component\Form\FormError;
|
||||
use Symfony\Component\Form\FormErrorIterator;
|
||||
|
||||
class FormGetErrorsReturnTypeProvider implements \Psalm\Plugin\EventHandler\MethodReturnTypeProviderInterface
|
||||
{
|
||||
public static function getClassLikeNames(): array
|
||||
{
|
||||
return ['Symfony\Component\Form\FormInterface'];
|
||||
}
|
||||
|
||||
public static function getMethodReturnType(MethodReturnTypeProviderEvent $event): ?Type\Union
|
||||
{
|
||||
$method_name_lowercase = $event->getMethodNameLowercase();
|
||||
if ('geterrors' !== $method_name_lowercase) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$args = $event->getCallArgs();
|
||||
$source = $event->getSource();
|
||||
|
||||
if (isset($args[0]) && isset($args[1])) {
|
||||
$first_arg_type = $source->getNodeTypeProvider()->getType($args[0]->value);
|
||||
$second_arg_type = $source->getNodeTypeProvider()->getType($args[1]->value);
|
||||
|
||||
if (
|
||||
$first_arg_type
|
||||
&& $first_arg_type->isTrue()
|
||||
&& $second_arg_type
|
||||
&& $second_arg_type->isFalse()
|
||||
) {
|
||||
return new Type\Union([
|
||||
new Type\Atomic\TGenericObject(FormErrorIterator::class, [
|
||||
new Type\Union([
|
||||
new TNamedObject(FormError::class),
|
||||
new TNamedObject(FormErrorIterator::class),
|
||||
]),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return new Type\Union([
|
||||
new Type\Atomic\TGenericObject(FormErrorIterator::class, [
|
||||
new Type\Union([new TNamedObject(FormError::class)]),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
27
src/Stubs/common/Component/Form/FormErrorIterator.stubphp
Normal file
27
src/Stubs/common/Component/Form/FormErrorIterator.stubphp
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Form;
|
||||
|
||||
/**
|
||||
* @template T of FormError|FormErrorIterator
|
||||
* @implements \ArrayAccess<int, T>
|
||||
* @implements \RecursiveIterator<int, T>
|
||||
* @implements \SeekableIterator<int, T>
|
||||
*/
|
||||
class FormErrorIterator implements \RecursiveIterator, \SeekableIterator, \ArrayAccess, \Countable
|
||||
{
|
||||
/**
|
||||
* @param T[]
|
||||
*/
|
||||
public function __construct(FormInterface $form, array $errors);
|
||||
|
||||
/** @return T */
|
||||
public function current();
|
||||
|
||||
/**
|
||||
* @param int $position
|
||||
*
|
||||
* @return T
|
||||
*/
|
||||
public function offsetGet($position);
|
||||
}
|
72
tests/acceptance/acceptance/forms/FormGetErrors.feature
Normal file
72
tests/acceptance/acceptance/forms/FormGetErrors.feature
Normal file
@ -0,0 +1,72 @@
|
||||
@symfony-common
|
||||
Feature: Form getErrors return type provider
|
||||
|
||||
Background:
|
||||
Given I have Symfony plugin enabled
|
||||
Scenario: getErrors with anything else than (true, false)
|
||||
Given I have the following code
|
||||
"""
|
||||
<?php
|
||||
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
|
||||
function foo(FormInterface $form): array
|
||||
{
|
||||
$messages = [];
|
||||
|
||||
foreach ($form->getErrors() as $error1) {
|
||||
$messages[] = $error1->getMessage();
|
||||
}
|
||||
|
||||
foreach ($form->getErrors(true) as $error2) {
|
||||
$messages[] = $error2->getMessage();
|
||||
}
|
||||
|
||||
foreach ($form->getErrors(false) as $error3) {
|
||||
$messages[] = $error3->getMessage();
|
||||
}
|
||||
|
||||
foreach ($form->getErrors(true, true) as $error4) {
|
||||
$messages[] = $error4->getMessage();
|
||||
}
|
||||
|
||||
foreach ($form->getErrors(false, false) as $error5) {
|
||||
$messages[] = $error5->getMessage();
|
||||
}
|
||||
|
||||
foreach ($form->getErrors(false, true) as $error6) {
|
||||
$messages[] = $error6->getMessage();
|
||||
}
|
||||
|
||||
return $messages;
|
||||
}
|
||||
"""
|
||||
When I run Psalm
|
||||
Then I see no other errors
|
||||
|
||||
Scenario: getErrors with (true, false)
|
||||
Given I have the following code
|
||||
"""
|
||||
<?php
|
||||
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
|
||||
function foo(FormInterface $form): array
|
||||
{
|
||||
$messages = [];
|
||||
|
||||
foreach ($form->getErrors(true, false) as $error7) {
|
||||
/** @psalm-trace $error7 */
|
||||
$messages[] = $error7->getMessage();
|
||||
}
|
||||
|
||||
return $messages;
|
||||
}
|
||||
"""
|
||||
When I run Psalm
|
||||
Then I see these errors
|
||||
| Type | Message |
|
||||
| Trace | $error7: Symfony\Component\Form\FormError\|Symfony\Component\Form\FormErrorIterator |
|
||||
| MixedAssignment | Unable to determine the type of this assignment |
|
||||
| PossiblyUndefinedMethod | Method Symfony\Component\Form\FormErrorIterator::getMessage does not exist |
|
||||
And I see no other errors
|
Loading…
Reference in New Issue
Block a user