diff --git a/config/sets/symfony/symfony25.php b/config/sets/symfony/symfony25.php
index b574690d..28bc5d70 100644
--- a/config/sets/symfony/symfony25.php
+++ b/config/sets/symfony/symfony25.php
@@ -4,7 +4,11 @@
use Rector\Config\RectorConfig;
use Rector\Symfony\Rector\MethodCall\AddViolationToBuildViolationRector;
+use Rector\Symfony\Rector\MethodCall\MaxLengthSymfonyFormOptionToAttrRector;
return static function (RectorConfig $rectorConfig): void {
- $rectorConfig->rule(AddViolationToBuildViolationRector::class);
+ $rectorConfig->rules([
+ AddViolationToBuildViolationRector::class,
+ MaxLengthSymfonyFormOptionToAttrRector::class,
+ ]);
};
diff --git a/docs/rector_rules_overview.md b/docs/rector_rules_overview.md
index c83ebb87..966c78e1 100644
--- a/docs/rector_rules_overview.md
+++ b/docs/rector_rules_overview.md
@@ -1,4 +1,4 @@
-# 68 Rules Overview
+# 70 Rules Overview
## ActionSuffixRemoverRector
@@ -714,6 +714,27 @@ Turns properties with `@inject` to private properties and constructor injection
+## KernelTestCaseContainerPropertyDeprecationRector
+
+Simplify use of assertions in WebTestCase
+
+- class: [`Rector\Symfony\Rector\StaticPropertyFetch\KernelTestCaseContainerPropertyDeprecationRector`](../src/Rector/StaticPropertyFetch/KernelTestCaseContainerPropertyDeprecationRector.php)
+
+```diff
+ use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
+
+ class SomeTest extends KernelTestCase
+ {
+ protected function setUp(): void
+ {
+- $container = self::$container;
++ $container = self::getContainer();
+ }
+ }
+```
+
+
+
## LiteralGetToRequestClassConstantRector
Replace "GET" string by Symfony Request object class constants
@@ -927,6 +948,23 @@ Make event object a first argument of `dispatch()` method, event name as second
+## MaxLengthSymfonyFormOptionToAttrRector
+
+Change form option "max_length" to a form "attr" > "max_length"
+
+- class: [`Rector\Symfony\Rector\MethodCall\MaxLengthSymfonyFormOptionToAttrRector`](../src/Rector/MethodCall/MaxLengthSymfonyFormOptionToAttrRector.php)
+
+```diff
+ $formBuilder = new Symfony\Component\Form\FormBuilder();
+
+ $form = $formBuilder->create('name', 'text', [
+- 'max_length' => 123,
++ 'attr' => ['maxlength' => 123],
+ ]);
+```
+
+
+
## MergeMethodAnnotationToRouteAnnotationRector
Merge removed `@Method` annotation to `@Route` one
@@ -1354,9 +1392,9 @@ Change RouteCollectionBuilder to RoutingConfiguratorRector
## ServiceSetStringNameToClassNameRector
-Change `$service->set()` string names to class-type-based names, to allow `$container->get()` by types in Symfony 2.8
+Change `$service->set()` string names to class-type-based names, to allow `$container->get()` by types in Symfony 2.8. Provide XML config via `$rectorConfig->symfonyContainerXml(...);`
-- class: [`Rector\Symfony\Rector\Closure\ServiceSetStringNameToClassNameRector`](../src/Rector/MethodCall/ServiceSetStringNameToClassNameRector.php)
+- class: [`Rector\Symfony\Rector\Closure\ServiceSetStringNameToClassNameRector`](../src/Rector/Closure/ServiceSetStringNameToClassNameRector.php)
```diff
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
diff --git a/src/Rector/MethodCall/MaxLengthSymfonyFormOptionToAttrRector.php b/src/Rector/MethodCall/MaxLengthSymfonyFormOptionToAttrRector.php
new file mode 100644
index 00000000..3d0e23ea
--- /dev/null
+++ b/src/Rector/MethodCall/MaxLengthSymfonyFormOptionToAttrRector.php
@@ -0,0 +1,161 @@
+ "max_length"', [
+ new CodeSample(
+ <<<'CODE_SAMPLE'
+$formBuilder = new Symfony\Component\Form\FormBuilder();
+
+$form = $formBuilder->create('name', 'text', [
+ 'max_length' => 123,
+]);
+CODE_SAMPLE
+
+ ,
+ <<<'CODE_SAMPLE'
+$formBuilder = new Symfony\Component\Form\FormBuilder();
+
+$form = $formBuilder->create('name', 'text', [
+ 'attr' => ['maxlength' => 123],
+]);
+CODE_SAMPLE
+ ),
+ ]);
+ }
+
+ /**
+ * @return array>
+ */
+ public function getNodeTypes(): array
+ {
+ return [MethodCall::class];
+ }
+
+ /**
+ * @param MethodCall $node
+ */
+ public function refactor(Node $node): ?Node
+ {
+ if (! $this->isFormCreateMethodCallMatch($node)) {
+ return null;
+ }
+
+ $optionsArg = $node->getArgs()[2] ?? null;
+ if (! $optionsArg instanceof Arg) {
+ return null;
+ }
+
+ if (! $optionsArg->value instanceof Array_) {
+ return null;
+ }
+
+ $optionsArray = $optionsArg->value;
+
+ $itemToAddToAttrs = null;
+
+ foreach ($optionsArray->items as $arrayKey => $arrayItem) {
+ if (! $arrayItem instanceof ArrayItem) {
+ continue;
+ }
+
+ if (! $arrayItem->key instanceof String_) {
+ continue;
+ }
+
+ if (! $this->valueResolver->isValue($arrayItem->key, 'max_length')) {
+ continue;
+ }
+
+ unset($optionsArray->items[$arrayKey]);
+
+ $itemToAddToAttrs = $arrayItem;
+ break;
+ }
+
+ if (! $itemToAddToAttrs instanceof ArrayItem) {
+ return null;
+ }
+
+ $this->addArrayItemToAttrsItemOrCreateOne($optionsArray, $itemToAddToAttrs);
+ return $node;
+ }
+
+ private function matchAttrArrayItem(Array_ $array): ?ArrayItem
+ {
+ foreach ($array->items as $arrayItem) {
+ if (! $arrayItem instanceof ArrayItem) {
+ continue;
+ }
+
+ if (! $arrayItem->key instanceof String_) {
+ continue;
+ }
+
+ if (! $this->valueResolver->isValue($arrayItem->key, 'attrs')) {
+ continue;
+ }
+
+ return $arrayItem;
+ }
+
+ return null;
+ }
+
+ private function addArrayItemToAttrsItemOrCreateOne(Array_ $array, ArrayItem $arrayItem): Array_
+ {
+ // rename
+ $arrayItem->key = new String_('maxlength');
+
+ $attrArrayItem = $this->matchAttrArrayItem($array);
+
+ if ($attrArrayItem instanceof ArrayItem) {
+ if (! $attrArrayItem->value instanceof Array_) {
+ throw new ShouldNotHappenException();
+ }
+
+ $attrArrayItem->value->items[] = $arrayItem;
+ return $array;
+ }
+
+ $array->items[] = new ArrayItem(new Array_([$arrayItem]), new String_('attr'));
+ return $array;
+ }
+
+ private function isFormCreateMethodCallMatch(MethodCall $methodCall): bool
+ {
+ if (
+ ! $this->isObjectType($methodCall->var, new ObjectType('Symfony\Component\Form\FormFactoryInterface'))
+ && ! $this->isObjectType($methodCall->var, new ObjectType('Symfony\Component\Form\FormBuilderInterface'))
+ ) {
+ return false;
+ }
+
+ return $this->isNames($methodCall->name, ['create', 'add']);
+ }
+}
diff --git a/stubs/Symfony/Component/Form/FormBuilder.php b/stubs/Symfony/Component/Form/FormBuilder.php
index 2f51de62..25e82c78 100644
--- a/stubs/Symfony/Component/Form/FormBuilder.php
+++ b/stubs/Symfony/Component/Form/FormBuilder.php
@@ -10,5 +10,7 @@
class FormBuilder implements FormBuilderInterface
{
-
+ public function add()
+ {
+ }
}
diff --git a/stubs/Symfony/Component/Form/FormFactory.php b/stubs/Symfony/Component/Form/FormFactory.php
new file mode 100644
index 00000000..b0a48892
--- /dev/null
+++ b/stubs/Symfony/Component/Form/FormFactory.php
@@ -0,0 +1,14 @@
+add('name', 'text', [
+ 'max_length' => 123,
+]);
+
+?>
+-----
+add('name', 'text', [
+ 'attr' => ['maxlength' => 123],
+]);
+
+?>
diff --git a/tests/Rector/Array_/MaxLengthSymfonyFormOptionToAttrRector/Fixture/some_form_factory.php.inc b/tests/Rector/Array_/MaxLengthSymfonyFormOptionToAttrRector/Fixture/some_form_factory.php.inc
new file mode 100644
index 00000000..f2e90b9b
--- /dev/null
+++ b/tests/Rector/Array_/MaxLengthSymfonyFormOptionToAttrRector/Fixture/some_form_factory.php.inc
@@ -0,0 +1,23 @@
+create('name', 'text', [
+ 'max_length' => 123,
+]);
+
+?>
+-----
+create('name', 'text', [
+ 'attr' => ['maxlength' => 123],
+]);
+
+?>
diff --git a/tests/Rector/Array_/MaxLengthSymfonyFormOptionToAttrRector/MaxLengthSymfonyFormOptionToAttrRectorTest.php b/tests/Rector/Array_/MaxLengthSymfonyFormOptionToAttrRector/MaxLengthSymfonyFormOptionToAttrRectorTest.php
new file mode 100644
index 00000000..6a0cde34
--- /dev/null
+++ b/tests/Rector/Array_/MaxLengthSymfonyFormOptionToAttrRector/MaxLengthSymfonyFormOptionToAttrRectorTest.php
@@ -0,0 +1,32 @@
+doTestFile($file);
+ }
+
+ /**
+ * @return Iterator
+ */
+ public function provideData(): Iterator
+ {
+ return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
+ }
+
+ public function provideConfigFilePath(): string
+ {
+ return __DIR__ . '/config/configured_rule.php';
+ }
+}
diff --git a/tests/Rector/Array_/MaxLengthSymfonyFormOptionToAttrRector/config/configured_rule.php b/tests/Rector/Array_/MaxLengthSymfonyFormOptionToAttrRector/config/configured_rule.php
new file mode 100644
index 00000000..6ef67f6a
--- /dev/null
+++ b/tests/Rector/Array_/MaxLengthSymfonyFormOptionToAttrRector/config/configured_rule.php
@@ -0,0 +1,12 @@
+import(__DIR__ . '/../../../../../config/config.php');
+
+ $rectorConfig->rule(MaxLengthSymfonyFormOptionToAttrRector::class);
+};