diff --git a/UPGRADE-3.x.md b/UPGRADE-3.x.md index 81c854e1e1a..26c7a6686cd 100644 --- a/UPGRADE-3.x.md +++ b/UPGRADE-3.x.md @@ -1,6 +1,21 @@ UPGRADE 3.x =========== +## Deprecated `SonataAdminBundle\Admin\AdminHelper::addNewInstance` + +Use +``` +$instance = $fieldDescription->getAssociationAdmin()->getNewInstance(); +SonataAdminBundle\Admin\AdminHelper::addInstance($object, $fieldDescription, $instance); +``` +Instead of +``` +$this->adminHelper->addNewInstance($object, $fieldDescription); +``` + +The static method `addInstance()` avoids the need to inject the admin helper dependency, +and adds more flexibility with the instance you're adding to the object. + UPGRADE FROM 3.68 to 3.69 ========================= diff --git a/src/Admin/AbstractAdmin.php b/src/Admin/AbstractAdmin.php index d59ab2cb684..70a9e9f7918 100644 --- a/src/Admin/AbstractAdmin.php +++ b/src/Admin/AbstractAdmin.php @@ -1344,6 +1344,34 @@ public function getTemplate($name) public function getNewInstance() { $object = $this->getModelManager()->getModelInstance($this->getClass()); + + // Append parent object if any + if ($this->isChild() && $this->getParentAssociationMapping()) { + $parentAdmin = $this->getParent(); + $parent = $parentAdmin->getObject($this->request->get($parentAdmin->getIdParameter())); + + if (null !== $parent) { + $propertyAccessor = $this->getConfigurationPool()->getPropertyAccessor(); + $propertyPath = new PropertyPath($this->getParentAssociationMapping()); + + $value = $propertyAccessor->getValue($object, $propertyPath); + + if (\is_array($value) || $value instanceof \ArrayAccess) { + $value[] = $parent; + $propertyAccessor->setValue($object, $propertyPath, $value); + } else { + $propertyAccessor->setValue($object, $propertyPath, $parent); + } + } + } elseif ($this->hasParentFieldDescription()) { + $parentAdmin = $this->getParentFieldDescription()->getAdmin(); + $parent = $parentAdmin->getObject($this->request->get($parentAdmin->getIdParameter())); + + if (null !== $parent) { + AdminHelper::addInstance($parent, $this->getParentFieldDescription(), $object); + } + } + foreach ($this->getExtensions() as $extension) { $extension->alterNewInstance($this, $object); } @@ -3352,26 +3380,6 @@ protected function buildForm() $this->loaded['form'] = true; - // append parent object if any - // todo : clean the way the Admin class can retrieve set the object - if ($this->isChild() && $this->getParentAssociationMapping()) { - $parent = $this->getParent()->getObject($this->request->get($this->getParent()->getIdParameter())); - - $propertyAccessor = $this->getConfigurationPool()->getPropertyAccessor(); - $propertyPath = new PropertyPath($this->getParentAssociationMapping()); - - $object = $this->getSubject(); - - $value = $propertyAccessor->getValue($object, $propertyPath); - - if (\is_array($value) || $value instanceof \ArrayAccess) { - $value[] = $parent; - $propertyAccessor->setValue($object, $propertyPath, $value); - } else { - $propertyAccessor->setValue($object, $propertyPath, $parent); - } - } - $formBuilder = $this->getFormBuilder(); $formBuilder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) { $this->preValidate($event->getData()); diff --git a/src/Admin/AdminHelper.php b/src/Admin/AdminHelper.php index 89d0ac6aaea..d9421ab1d14 100644 --- a/src/Admin/AdminHelper.php +++ b/src/Admin/AdminHelper.php @@ -179,16 +179,17 @@ public function appendFormFieldElement(AdminInterface $admin, $subject, $element $objectCount = null === $value ? 0 : \count($value); $postCount = \count($data[$childFormBuilder->getName()]); + $associationAdmin = $fieldDescription->getAssociationAdmin(); + // add new elements to the subject while ($objectCount < $postCount) { // append a new instance into the object - $this->addNewInstance($form->getData(), $fieldDescription); + self::addInstance($form->getData(), $fieldDescription, $associationAdmin->getNewInstance()); ++$objectCount; } - $newInstance = $this->addNewInstance($form->getData(), $fieldDescription); + $newInstance = self::addInstance($form->getData(), $fieldDescription, $associationAdmin->getNewInstance()); - $associationAdmin = $fieldDescription->getAssociationAdmin(); $associationAdmin->setSubject($newInstance); } @@ -213,6 +214,10 @@ public function appendFormFieldElement(AdminInterface $admin, $subject, $element } /** + * NEXT_MAJOR: remove this method. + * + * @deprecated since sonata-project/admin-bundle 3.x, use to be removed with 4.0. + * * Add a new instance to the related FieldDescriptionInterface value. * * @param object $object @@ -223,7 +228,25 @@ public function appendFormFieldElement(AdminInterface $admin, $subject, $element */ public function addNewInstance($object, FieldDescriptionInterface $fieldDescription) { + @trigger_error(sprintf( + 'Method %s() is deprecated since sonata-project/admin-bundle 3.x. It will be removed in version 4.0.' + .' Use %s::addInstance() instead.', + __METHOD__, + __CLASS__ + ), E_USER_DEPRECATED); + $instance = $fieldDescription->getAssociationAdmin()->getNewInstance(); + + return self::addInstance($object, $fieldDescription, $instance); + } + + /** + * @template T of object + * @phpstan-param T $instance + * @phpstan-return T + */ + public static function addInstance(object $object, FieldDescriptionInterface $fieldDescription, object $instance): object + { $mapping = $fieldDescription->getAssociationMapping(); $parentMappings = $fieldDescription->getParentAssociationMappings(); diff --git a/src/Form/Type/AdminType.php b/src/Form/Type/AdminType.php index a3a3f59d5d4..794975c4345 100644 --- a/src/Form/Type/AdminType.php +++ b/src/Form/Type/AdminType.php @@ -36,22 +36,22 @@ class AdminType extends AbstractType { /** - * @var AdminHelper + * NEXT_MAJOR: Remove this property. + * + * @var AdminHelper|null */ private $adminHelper; /** - * NEXT_MAJOR: Allow only `AdminHelper` for argument 1 and remove the default null value. + * NEXT_MAJOR: Remove the __construct method. */ public function __construct(?AdminHelper $adminHelper = null) { - // NEXT_MAJOR: Remove this condition. - if (null === $adminHelper) { + if (\func_num_args() > 0) { @trigger_error(sprintf( - 'Calling %s without passing an %s as argument is deprecated since sonata-project/admin-bundle 3.66' + 'Calling %s with passing an argument is deprecated since sonata-project/admin-bundle 3.x' .' and will throw an exception in 4.0.', - __METHOD__, - AdminHelper::class + __METHOD__ ), E_USER_DEPRECATED); } @@ -107,10 +107,7 @@ static function (array $associationMapping): string { $subject = $p->getValue($parentSubject, $parentPath.$path); } catch (NoSuchIndexException $e) { // no object here, we create a new one - // NEXT_MAJOR: Remove the null check. - if (null !== $this->adminHelper) { - $subject = $this->adminHelper->addNewInstance($parentSubject, $parentFieldDescription); - } + $subject = AdminHelper::addInstance($parentSubject, $parentFieldDescription, $admin->getNewInstance()); } } } diff --git a/tests/Admin/AdminHelperTest.php b/tests/Admin/AdminHelperTest.php index d1227f07adc..3e67830aadc 100644 --- a/tests/Admin/AdminHelperTest.php +++ b/tests/Admin/AdminHelperTest.php @@ -72,6 +72,11 @@ public function testGetChildFormView(): void $this->assertInstanceOf(FormView::class, $this->helper->getChildFormView($formView, 'test_elementId')); } + /** + * @group legacy + * + * @expectedDeprecation Method Sonata\AdminBundle\Admin\AdminHelper::addNewInstance() is deprecated since sonata-project/admin-bundle 3.x. It will be removed in version 4.0. Use Sonata\AdminBundle\Admin\AdminHelper::addInstance() instead. + */ public function testAddNewInstance(): void { $admin = $this->createMock(AdminInterface::class); @@ -90,6 +95,11 @@ public function testAddNewInstance(): void $this->helper->addNewInstance($object, $fieldDescription); } + /** + * @group legacy + * + * @expectedDeprecation Method Sonata\AdminBundle\Admin\AdminHelper::addNewInstance() is deprecated since sonata-project/admin-bundle 3.x. It will be removed in version 4.0. Use Sonata\AdminBundle\Admin\AdminHelper::addInstance() instead. + */ public function testAddNewInstanceWithParentAssociation(): void { $admin = $this->createMock(AdminInterface::class); @@ -113,6 +123,11 @@ public function testAddNewInstanceWithParentAssociation(): void $this->helper->addNewInstance($object1, $fieldDescription); } + /** + * @group legacy + * + * @expectedDeprecation Method Sonata\AdminBundle\Admin\AdminHelper::addNewInstance() is deprecated since sonata-project/admin-bundle 3.x. It will be removed in version 4.0. Use Sonata\AdminBundle\Admin\AdminHelper::addInstance() instead. + */ public function testAddNewInstancePlural(): void { $admin = $this->createMock(AdminInterface::class); @@ -131,6 +146,11 @@ public function testAddNewInstancePlural(): void $this->helper->addNewInstance($object, $fieldDescription); } + /** + * @group legacy + * + * @expectedDeprecation Method Sonata\AdminBundle\Admin\AdminHelper::addNewInstance() is deprecated since sonata-project/admin-bundle 3.x. It will be removed in version 4.0. Use Sonata\AdminBundle\Admin\AdminHelper::addInstance() instead. + */ public function testAddNewInstanceInflector(): void { $admin = $this->createMock(AdminInterface::class); @@ -149,6 +169,67 @@ public function testAddNewInstanceInflector(): void $this->helper->addNewInstance($object, $fieldDescription); } + public function testAddInstance(): void + { + $fieldDescription = $this->createMock(FieldDescriptionInterface::class); + $fieldDescription->expects($this->once())->method('getAssociationMapping')->willReturn(['fieldName' => 'fooBar']); + $fieldDescription->expects($this->once())->method('getParentAssociationMappings')->willReturn([]); + + $object = $this->getMockBuilder(\stdClass::class) + ->setMethods(['addFooBar']) + ->getMock(); + $object->expects($this->once())->method('addFooBar'); + + AdminHelper::addInstance($object, $fieldDescription, new \stdClass()); + } + + public function testAddInstanceWithParentAssociation(): void + { + $fieldDescription = $this->createMock(FieldDescriptionInterface::class); + $fieldDescription->expects($this->once())->method('getAssociationMapping')->willReturn(['fieldName' => 'fooBar']); + $fieldDescription->expects($this->once())->method('getParentAssociationMappings')->willReturn([['fieldName' => 'parent']]); + + $object2 = $this->getMockBuilder(\stdClass::class) + ->setMethods(['addFooBar']) + ->getMock(); + $object2->expects($this->once())->method('addFooBar'); + + $object1 = $this->getMockBuilder(\stdClass::class) + ->setMethods(['getParent']) + ->getMock(); + $object1->expects($this->once())->method('getParent')->willReturn($object2); + + AdminHelper::addInstance($object1, $fieldDescription, new \stdClass()); + } + + public function testAddInstancePlural(): void + { + $fieldDescription = $this->createMock(FieldDescriptionInterface::class); + $fieldDescription->expects($this->once())->method('getAssociationMapping')->willReturn(['fieldName' => 'fooBars']); + $fieldDescription->expects($this->once())->method('getParentAssociationMappings')->willReturn([]); + + $object = $this->getMockBuilder(\stdClass::class) + ->setMethods(['addFooBar']) + ->getMock(); + $object->expects($this->once())->method('addFooBar'); + + AdminHelper::addInstance($object, $fieldDescription, new \stdClass()); + } + + public function testAddInstanceInflector(): void + { + $fieldDescription = $this->createMock(FieldDescriptionInterface::class); + $fieldDescription->expects($this->once())->method('getAssociationMapping')->willReturn(['fieldName' => 'entries']); + $fieldDescription->expects($this->once())->method('getParentAssociationMappings')->willReturn([]); + + $object = $this->getMockBuilder(\stdClass::class) + ->setMethods(['addEntry']) + ->getMock(); + $object->expects($this->once())->method('addEntry'); + + AdminHelper::addInstance($object, $fieldDescription, new \stdClass()); + } + public function testGetElementAccessPath(): void { $object = $this->getMockBuilder(\stdClass::class) diff --git a/tests/Admin/AdminTest.php b/tests/Admin/AdminTest.php index e7f39f0723f..9b4ed2ac5fe 100644 --- a/tests/Admin/AdminTest.php +++ b/tests/Admin/AdminTest.php @@ -60,6 +60,7 @@ use Sonata\AdminBundle\Tests\Fixtures\Bundle\Entity\BlogPost; use Sonata\AdminBundle\Tests\Fixtures\Bundle\Entity\Comment; use Sonata\AdminBundle\Tests\Fixtures\Bundle\Entity\Post; +use Sonata\AdminBundle\Tests\Fixtures\Bundle\Entity\PostWithSingleTag; use Sonata\AdminBundle\Tests\Fixtures\Bundle\Entity\Tag; use Sonata\AdminBundle\Tests\Fixtures\Entity\FooToString; use Sonata\AdminBundle\Tests\Fixtures\Entity\FooToStringNull; @@ -1575,56 +1576,119 @@ public function testGetPersistentParametersWithValidExtension(): void $this->assertSame($expected, $admin->getPersistentParameters()); } - public function testGetFormWithNonCollectionParentValue(): void + public function testGetNewInstanceForChildAdminWithParentValue(): void { - $post = new Post(); - $tagAdmin = $this->createTagAdmin($post); - $tag = $tagAdmin->getSubject(); + $post = new PostWithSingleTag(); + + $postAdmin = $this->getMockBuilder(PostAdmin::class)->disableOriginalConstructor()->getMock(); + $postAdmin->method('getObject')->willReturn($post); - $tag->setPosts(null); - $tagAdmin->getForm(); - $this->assertSame($post, $tag->getPosts()); + $formBuilder = $this->createMock(FormBuilderInterface::class); + $formBuilder->method('getForm')->willReturn(null); + + $tag = new Tag(); + + $modelManager = $this->createMock(ModelManagerInterface::class); + $modelManager->method('getModelInstance')->willReturn($tag); + + $tagAdmin = new TagAdmin('admin.tag', Tag::class, 'MyBundle\MyController'); + $tagAdmin->setModelManager($modelManager); + $tagAdmin->setParent($postAdmin); + + $request = $this->createMock(Request::class); + $tagAdmin->setRequest($request); + + $configurationPool = $this->getMockBuilder(Pool::class) + ->disableOriginalConstructor() + ->getMock(); + + $configurationPool->method('getPropertyAccessor')->willReturn(PropertyAccess::createPropertyAccessor()); + + $tagAdmin->setConfigurationPool($configurationPool); + + $tag = $tagAdmin->getNewInstance(); + + $this->assertInstanceOf(Collection::class, $tag->getPosts()); + $this->assertCount(1, $tag->getPosts()); + $this->assertContains($post, $tag->getPosts()); } - public function testGetFormWithCollectionParentValue(): void + public function testGetNewInstanceForChildAdminWithCollectionParentValue(): void { $post = new Post(); - $tagAdmin = $this->createTagAdmin($post); - $tag = $tagAdmin->getSubject(); - // Case of a doctrine collection - $this->assertInstanceOf(Collection::class, $tag->getPosts()); - $this->assertCount(0, $tag->getPosts()); + $postAdmin = $this->getMockBuilder(PostAdmin::class)->disableOriginalConstructor()->getMock(); + $postAdmin->method('getObject')->willReturn($post); - $tag->addPost(new Post()); + $formBuilder = $this->createMock(FormBuilderInterface::class); + $formBuilder->method('getForm')->willReturn(null); - $this->assertCount(1, $tag->getPosts()); + $tag = new Tag(); + + $modelManager = $this->createMock(ModelManagerInterface::class); + $modelManager->method('getModelInstance')->willReturn($tag); - $tagAdmin->getForm(); + $tagAdmin = new TagAdmin('admin.tag', Tag::class, 'MyBundle\MyController'); + $tagAdmin->setModelManager($modelManager); + $tagAdmin->setParent($postAdmin); + + $request = $this->createMock(Request::class); + $tagAdmin->setRequest($request); + + $configurationPool = $this->getMockBuilder(Pool::class) + ->disableOriginalConstructor() + ->getMock(); + + $configurationPool->method('getPropertyAccessor')->willReturn(PropertyAccess::createPropertyAccessor()); + + $tagAdmin->setConfigurationPool($configurationPool); + + $tag = $tagAdmin->getNewInstance(); $this->assertInstanceOf(Collection::class, $tag->getPosts()); - $this->assertCount(2, $tag->getPosts()); + $this->assertCount(1, $tag->getPosts()); $this->assertContains($post, $tag->getPosts()); } - public function testGetFormWithArrayParentValue(): void + public function testGetNewInstanceForEmbededAdminWithCollectionParentValue(): void { $post = new Post(); - $tagAdmin = $this->createTagAdmin($post); - $tag = $tagAdmin->getSubject(); - // Case of an array - $tag->setPosts([]); - $this->assertCount(0, $tag->getPosts()); + $postAdmin = $this->getMockBuilder(PostAdmin::class)->disableOriginalConstructor()->getMock(); + $postAdmin->method('getObject')->willReturn($post); - $tag->addPost(new Post()); + $formBuilder = $this->createMock(FormBuilderInterface::class); + $formBuilder->method('getForm')->willReturn(null); - $this->assertCount(1, $tag->getPosts()); + $parentField = $this->createMock(FieldDescriptionInterface::class); + $parentField->method('getAdmin')->willReturn($postAdmin); + $parentField->method('getParentAssociationMappings')->willReturn([]); + $parentField->method('getAssociationMapping')->willReturn(['fieldName' => 'tag']); + + $tag = new Tag(); + + $modelManager = $this->createMock(ModelManagerInterface::class); + $modelManager->method('getModelInstance')->willReturn($tag); - $tagAdmin->getForm(); + $tagAdmin = new TagAdmin('admin.tag', Tag::class, 'MyBundle\MyController'); + $tagAdmin->setModelManager($modelManager); + $tagAdmin->setParentFieldDescription($parentField); - $this->assertIsArray($tag->getPosts()); - $this->assertCount(2, $tag->getPosts()); + $request = $this->createMock(Request::class); + $tagAdmin->setRequest($request); + + $configurationPool = $this->getMockBuilder(Pool::class) + ->disableOriginalConstructor() + ->getMock(); + + $configurationPool->method('getPropertyAccessor')->willReturn(PropertyAccess::createPropertyAccessor()); + + $tagAdmin->setConfigurationPool($configurationPool); + + $tag = $tagAdmin->getNewInstance(); + + $this->assertInstanceOf(Collection::class, $tag->getPosts()); + $this->assertCount(1, $tag->getPosts()); $this->assertContains($post, $tag->getPosts()); } @@ -2569,44 +2633,4 @@ public function getDeprecatedAbstractAdminConstructorArgs(): iterable [1, 1, 1], ]; } - - private function createTagAdmin(Post $post): TagAdmin - { - $postAdmin = $this->getMockBuilder(PostAdmin::class) - ->disableOriginalConstructor() - ->getMock(); - - $postAdmin->method('getObject')->willReturn($post); - - $formBuilder = $this->createMock(FormBuilderInterface::class); - $formBuilder->method('getForm')->willReturn(null); - - $tagAdmin = $this->getMockBuilder(TagAdmin::class) - ->setConstructorArgs([ - 'admin.tag', - Tag::class, - 'MyBundle\MyController', - ]) - ->setMethods(['getFormBuilder']) - ->getMock(); - - $tagAdmin->method('getFormBuilder')->willReturn($formBuilder); - $tagAdmin->setParent($postAdmin); - - $tag = new Tag(); - $tagAdmin->setSubject($tag); - - $request = $this->createMock(Request::class); - $tagAdmin->setRequest($request); - - $configurationPool = $this->getMockBuilder(Pool::class) - ->disableOriginalConstructor() - ->getMock(); - - $configurationPool->method('getPropertyAccessor')->willReturn(PropertyAccess::createPropertyAccessor()); - - $tagAdmin->setConfigurationPool($configurationPool); - - return $tagAdmin; - } } diff --git a/tests/Fixtures/Bundle/Entity/Post.php b/tests/Fixtures/Bundle/Entity/Post.php index f6cfc9ccc3f..846db89396d 100644 --- a/tests/Fixtures/Bundle/Entity/Post.php +++ b/tests/Fixtures/Bundle/Entity/Post.php @@ -14,6 +14,7 @@ namespace Sonata\AdminBundle\Tests\Fixtures\Bundle\Entity; use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; class Post { @@ -24,12 +25,12 @@ public function __construct() $this->tags = new ArrayCollection(); } - public function setTags($tags): void + public function setTags(Collection $tags): void { $this->tags = $tags; } - public function getTags() + public function getTags(): Collection { return $this->tags; } @@ -40,7 +41,7 @@ public function addTag(Tag $tag): void $this->tags[] = ($tag); } - public function removePost(Tag $tag): void + public function removeTag(Tag $tag): void { $tag->removePost($this); $this->tags->removeElement($tag); diff --git a/tests/Fixtures/Bundle/Entity/PostWithSingleTag.php b/tests/Fixtures/Bundle/Entity/PostWithSingleTag.php new file mode 100644 index 00000000000..9e79697687d --- /dev/null +++ b/tests/Fixtures/Bundle/Entity/PostWithSingleTag.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\AdminBundle\Tests\Fixtures\Bundle\Entity; + +class PostWithSingleTag +{ + private $tag; + + public function setTag(Tag $tag): void + { + $this->tag = $tag; + } + + public function getTag(): ?Tag + { + return $this->tag; + } +} diff --git a/tests/Fixtures/Bundle/Entity/Tag.php b/tests/Fixtures/Bundle/Entity/Tag.php index fe1d7e526a9..2d59de00a77 100644 --- a/tests/Fixtures/Bundle/Entity/Tag.php +++ b/tests/Fixtures/Bundle/Entity/Tag.php @@ -14,22 +14,25 @@ namespace Sonata\AdminBundle\Tests\Fixtures\Bundle\Entity; use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; class Tag { private $posts; + private $postWithSingleTag; + public function __construct() { $this->posts = new ArrayCollection(); } - public function setPosts($posts): void + public function setPosts(Collection $posts): void { $this->posts = $posts; } - public function getPosts() + public function getPosts(): Collection { return $this->posts; } @@ -43,4 +46,14 @@ public function removePost(Post $post): void { $this->posts->removeElement($post); } + + public function setPostWithSingleTag(PostWithSingleTag $postWithSingleTag): void + { + $this->postWithSingleTag = $postWithSingleTag; + } + + public function getPostWithSingleTag(): ?PostWithSingleTag + { + return $this->postWithSingleTag; + } } diff --git a/tests/Fixtures/Entity/Foo.php b/tests/Fixtures/Entity/Foo.php index 7c3f7ef345d..23ffb4d610c 100644 --- a/tests/Fixtures/Entity/Foo.php +++ b/tests/Fixtures/Entity/Foo.php @@ -16,6 +16,7 @@ class Foo { public $qux; + private $bar; private $baz; diff --git a/tests/Form/Type/AdminTypeTest.php b/tests/Form/Type/AdminTypeTest.php index 16950c75814..f22f9b9ba6c 100644 --- a/tests/Form/Type/AdminTypeTest.php +++ b/tests/Form/Type/AdminTypeTest.php @@ -16,9 +16,7 @@ use Doctrine\Common\Collections\ArrayCollection; use Prophecy\Argument; use Prophecy\Argument\Token\AnyValueToken; -use Prophecy\Prophecy\ObjectProphecy; use Sonata\AdminBundle\Admin\AbstractAdmin; -use Sonata\AdminBundle\Admin\AdminHelper; use Sonata\AdminBundle\Admin\AdminInterface; use Sonata\AdminBundle\Admin\FieldDescriptionInterface; use Sonata\AdminBundle\Form\Extension\Field\Type\FormTypeFieldExtension; @@ -27,18 +25,12 @@ use Sonata\AdminBundle\Tests\Fixtures\Entity\Foo; use Sonata\AdminBundle\Tests\Fixtures\TestExtension; use Symfony\Component\Form\FormTypeGuesserInterface; -use Symfony\Component\Form\PreloadedExtension; use Symfony\Component\Form\Test\TypeTestCase; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException; class AdminTypeTest extends TypeTestCase { - /** - * @var AdminHelper|ObjectProphecy - */ - private $adminHelper; - /** * @var AdminType */ @@ -46,8 +38,7 @@ class AdminTypeTest extends TypeTestCase protected function setUp(): void { - $this->adminHelper = $this->prophesize(AdminHelper::class); - $this->adminType = new AdminType($this->adminHelper->reveal()); + $this->adminType = new AdminType(); parent::setUp(); } @@ -197,15 +188,18 @@ public function testArrayCollection(): void public function testArrayCollectionNotFound(): void { - $parentSubject = new \stdClass(); - $parentSubject->foo = new ArrayCollection(); + $parentSubject = new Foo(); + $parentSubject->setBar(new ArrayCollection()); $parentAdmin = $this->prophesize(AdminInterface::class); $parentAdmin->getSubject()->shouldBeCalled()->willReturn($parentSubject); $parentAdmin->hasSubject()->shouldBeCalled()->willReturn(true); + $parentField = $this->prophesize(FieldDescriptionInterface::class); $parentField->setAssociationAdmin(Argument::type(AdminInterface::class))->shouldBeCalled(); $parentField->getAdmin()->shouldBeCalled()->willReturn($parentAdmin->reveal()); + $parentField->getParentAssociationMappings()->willReturn([]); + $parentField->getAssociationMapping()->willReturn(['fieldName' => 'bar']); $modelManager = $this->prophesize(ModelManagerInterface::class); @@ -218,15 +212,14 @@ public function testArrayCollectionNotFound(): void $admin->getModelManager()->shouldBeCalled()->willReturn($modelManager); $admin->getClass()->shouldBeCalled()->willReturn(Foo::class); $admin->setSubject($foo)->shouldBeCalled(); - - $this->adminHelper->addNewInstance($parentSubject, $parentField->reveal())->shouldBeCalled()->willReturn($foo); + $admin->getNewInstance()->shouldBeCalled()->willReturn(new Foo()); $field = $this->prophesize(FieldDescriptionInterface::class); $field->getAssociationAdmin()->shouldBeCalled()->willReturn($admin->reveal()); - $field->getFieldName()->shouldBeCalled()->willReturn('foo'); + $field->getFieldName()->shouldBeCalled()->willReturn('bar'); $field->getParentAssociationMappings()->shouldBeCalled()->willReturn([]); - $this->builder->add('foo'); + $this->builder->add('bar'); try { $this->adminType->buildForm($this->builder, [ @@ -249,8 +242,6 @@ protected function getExtensions() $extension->addTypeExtension(new FormTypeFieldExtension([], [])); $extensions[] = $extension; - $extensions[] = new PreloadedExtension([$this->adminType], []); - return $extensions; } } diff --git a/tests/Form/Type/LegacyAdminTypeTest.php b/tests/Form/Type/LegacyAdminTypeTest.php deleted file mode 100644 index c52a4352408..00000000000 --- a/tests/Form/Type/LegacyAdminTypeTest.php +++ /dev/null @@ -1,262 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Sonata\AdminBundle\Tests\Form\Type; - -use Doctrine\Common\Collections\ArrayCollection; -use Prophecy\Argument; -use Prophecy\Argument\Token\AnyValueToken; -use Sonata\AdminBundle\Admin\AbstractAdmin; -use Sonata\AdminBundle\Admin\AdminInterface; -use Sonata\AdminBundle\Admin\FieldDescriptionInterface; -use Sonata\AdminBundle\Form\Extension\Field\Type\FormTypeFieldExtension; -use Sonata\AdminBundle\Form\Type\AdminType; -use Sonata\AdminBundle\Model\ModelManagerInterface; -use Sonata\AdminBundle\Tests\Fixtures\Entity\Foo; -use Sonata\AdminBundle\Tests\Fixtures\TestExtension; -use Symfony\Component\Form\FormTypeGuesserInterface; -use Symfony\Component\Form\Test\TypeTestCase; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException; - -/** - * @group legacy - */ -class LegacyAdminTypeTest extends TypeTestCase -{ - /** - * @var AdminType - */ - private $adminType; - - protected function setUp(): void - { - $this->adminType = new AdminType(); - - parent::setUp(); - } - - /** - * @expectedDeprecation Calling Sonata\AdminBundle\Form\Type\AdminType::__construct without passing an Sonata\AdminBundle\Admin\AdminHelper as argument is deprecated since sonata-project/admin-bundle 3.66 and will throw an exception in 4.0. - */ - public function testGetDefaultOptions(): void - { - $optionResolver = new OptionsResolver(); - - $this->adminType->configureOptions($optionResolver); - - $options = $optionResolver->resolve(); - - $this->assertTrue($options['delete']); - $this->assertFalse($options['auto_initialize']); - $this->assertSame('link_add', $options['btn_add']); - $this->assertSame('link_list', $options['btn_list']); - $this->assertSame('link_delete', $options['btn_delete']); - $this->assertSame('SonataAdminBundle', $options['btn_catalogue']); - } - - /** - * @expectedDeprecation Calling Sonata\AdminBundle\Form\Type\AdminType::__construct without passing an Sonata\AdminBundle\Admin\AdminHelper as argument is deprecated since sonata-project/admin-bundle 3.66 and will throw an exception in 4.0. - */ - public function testSubmitValidData(): void - { - $parentAdmin = $this->prophesize(AdminInterface::class); - $parentAdmin->hasSubject()->shouldBeCalled()->willReturn(false); - $parentField = $this->prophesize(FieldDescriptionInterface::class); - $parentField->setAssociationAdmin(Argument::type(AdminInterface::class))->shouldBeCalled(); - $parentField->getAdmin()->shouldBeCalled()->willReturn($parentAdmin->reveal()); - - $modelManager = $this->prophesize(ModelManagerInterface::class); - - $foo = new Foo(); - - $admin = $this->prophesize(AbstractAdmin::class); - $admin->hasParentFieldDescription()->shouldBeCalled()->willReturn(true); - $admin->getParentFieldDescription()->shouldBeCalled()->willReturn($parentField->reveal()); - $admin->hasAccess('delete')->shouldBeCalled()->willReturn(false); - $admin->defineFormBuilder(new AnyValueToken())->shouldBeCalled(); - $admin->getModelManager()->shouldBeCalled()->willReturn($modelManager); - $admin->getClass()->shouldBeCalled()->willReturn(Foo::class); - $admin->getNewInstance()->shouldBeCalled()->willReturn($foo); - $admin->setSubject($foo)->shouldBeCalled(); - - $field = $this->prophesize(FieldDescriptionInterface::class); - $field->getAssociationAdmin()->shouldBeCalled()->willReturn($admin->reveal()); - $field->getAdmin()->shouldBeCalled(); - $field->getName()->shouldBeCalled(); - $field->getOption('edit', 'standard')->shouldBeCalled(); - $field->getOption('inline', 'natural')->shouldBeCalled(); - $field->getOption('block_name', false)->shouldBeCalled(); - $formData = []; - - $form = $this->factory->create( - AdminType::class, - null, - [ - 'sonata_field_description' => $field->reveal(), - ] - ); - $form->submit($formData); - $this->assertTrue($form->isSynchronized()); - } - - /** - * @expectedDeprecation Calling Sonata\AdminBundle\Form\Type\AdminType::__construct without passing an Sonata\AdminBundle\Admin\AdminHelper as argument is deprecated since sonata-project/admin-bundle 3.66 and will throw an exception in 4.0. - */ - public function testDotFields(): void - { - $foo = new \stdClass(); - $foo->bar = 1; - - $parentSubject = new \stdClass(); - $parentSubject->foo = $foo; - - $parentAdmin = $this->prophesize(AdminInterface::class); - $parentAdmin->getSubject()->shouldBeCalled()->willReturn($parentSubject); - $parentAdmin->hasSubject()->shouldBeCalled()->willReturn(true); - $parentField = $this->prophesize(FieldDescriptionInterface::class); - $parentField->setAssociationAdmin(Argument::type(AdminInterface::class))->shouldBeCalled(); - $parentField->getAdmin()->shouldBeCalled()->willReturn($parentAdmin->reveal()); - - $modelManager = $this->prophesize(ModelManagerInterface::class); - - $admin = $this->prophesize(AbstractAdmin::class); - $admin->hasParentFieldDescription()->shouldBeCalled()->willReturn(true); - $admin->getParentFieldDescription()->shouldBeCalled()->willReturn($parentField->reveal()); - $admin->setSubject(1)->shouldBeCalled(); - $admin->defineFormBuilder(new AnyValueToken())->shouldBeCalled(); - $admin->getModelManager()->shouldBeCalled()->willReturn($modelManager); - $admin->getClass()->shouldBeCalled()->willReturn(Foo::class); - - $field = $this->prophesize(FieldDescriptionInterface::class); - $field->getAssociationAdmin()->shouldBeCalled()->willReturn($admin->reveal()); - $field->getFieldName()->shouldBeCalled()->willReturn('bar'); - $field->getParentAssociationMappings()->shouldBeCalled()->willReturn([['fieldName' => 'foo']]); - - $this->builder->add('foo.bar'); - - try { - $this->adminType->buildForm($this->builder, [ - 'sonata_field_description' => $field->reveal(), - 'delete' => false, // not needed - 'property_path' => 'bar', // actual test case - ]); - } catch (NoSuchPropertyException $exception) { - $this->fail($exception->getMessage()); - } - } - - /** - * @expectedDeprecation Calling Sonata\AdminBundle\Form\Type\AdminType::__construct without passing an Sonata\AdminBundle\Admin\AdminHelper as argument is deprecated since sonata-project/admin-bundle 3.66 and will throw an exception in 4.0. - */ - public function testArrayCollection(): void - { - $foo = new Foo(); - - $parentSubject = new \stdClass(); - $parentSubject->foo = new ArrayCollection([$foo]); - - $parentAdmin = $this->prophesize(AdminInterface::class); - $parentAdmin->getSubject()->shouldBeCalled()->willReturn($parentSubject); - $parentAdmin->hasSubject()->shouldBeCalled()->willReturn(true); - $parentField = $this->prophesize(FieldDescriptionInterface::class); - $parentField->setAssociationAdmin(Argument::type(AdminInterface::class))->shouldBeCalled(); - $parentField->getAdmin()->shouldBeCalled()->willReturn($parentAdmin->reveal()); - - $modelManager = $this->prophesize(ModelManagerInterface::class); - - $admin = $this->prophesize(AbstractAdmin::class); - $admin->hasParentFieldDescription()->shouldBeCalled()->willReturn(true); - $admin->getParentFieldDescription()->shouldBeCalled()->willReturn($parentField->reveal()); - $admin->defineFormBuilder(new AnyValueToken())->shouldBeCalled(); - $admin->getModelManager()->shouldBeCalled()->willReturn($modelManager); - $admin->getClass()->shouldBeCalled()->willReturn(Foo::class); - $admin->setSubject($foo)->shouldBeCalled(); - - $field = $this->prophesize(FieldDescriptionInterface::class); - $field->getAssociationAdmin()->shouldBeCalled()->willReturn($admin->reveal()); - $field->getFieldName()->shouldBeCalled()->willReturn('foo'); - $field->getParentAssociationMappings()->shouldBeCalled()->willReturn([]); - - $this->builder->add('foo'); - - try { - $this->adminType->buildForm($this->builder, [ - 'sonata_field_description' => $field->reveal(), - 'delete' => false, // not needed - 'property_path' => '[0]', // actual test case - ]); - } catch (NoSuchPropertyException $exception) { - $this->fail($exception->getMessage()); - } - } - - /** - * @expectedDeprecation Calling Sonata\AdminBundle\Form\Type\AdminType::__construct without passing an Sonata\AdminBundle\Admin\AdminHelper as argument is deprecated since sonata-project/admin-bundle 3.66 and will throw an exception in 4.0. - */ - public function testArrayCollectionNotFound(): void - { - $parentSubject = new \stdClass(); - $parentSubject->foo = new ArrayCollection(); - - $parentAdmin = $this->prophesize(AdminInterface::class); - $parentAdmin->getSubject()->shouldBeCalled()->willReturn($parentSubject); - $parentAdmin->hasSubject()->shouldBeCalled()->willReturn(true); - $parentField = $this->prophesize(FieldDescriptionInterface::class); - $parentField->setAssociationAdmin(Argument::type(AdminInterface::class))->shouldBeCalled(); - $parentField->getAdmin()->shouldBeCalled()->willReturn($parentAdmin->reveal()); - - $modelManager = $this->prophesize(ModelManagerInterface::class); - - $foo = new Foo(); - - $admin = $this->prophesize(AbstractAdmin::class); - $admin->hasParentFieldDescription()->shouldBeCalled()->willReturn(true); - $admin->getParentFieldDescription()->shouldBeCalled()->willReturn($parentField->reveal()); - $admin->defineFormBuilder(new AnyValueToken())->shouldBeCalled(); - $admin->getModelManager()->shouldBeCalled()->willReturn($modelManager); - $admin->getClass()->shouldBeCalled()->willReturn(Foo::class); - $admin->getNewInstance()->shouldBeCalled()->willReturn($foo); - $admin->setSubject($foo)->shouldBeCalled(); - - $field = $this->prophesize(FieldDescriptionInterface::class); - $field->getAssociationAdmin()->shouldBeCalled()->willReturn($admin->reveal()); - $field->getFieldName()->shouldBeCalled()->willReturn('foo'); - $field->getParentAssociationMappings()->shouldBeCalled()->willReturn([]); - - $this->builder->add('foo'); - - try { - $this->adminType->buildForm($this->builder, [ - 'sonata_field_description' => $field->reveal(), - 'delete' => false, // not needed - 'property_path' => '[0]', // actual test case - ]); - } catch (NoSuchPropertyException $exception) { - $this->fail($exception->getMessage()); - } - } - - protected function getExtensions() - { - $extensions = parent::getExtensions(); - - $guesser = $this->prophesize(FormTypeGuesserInterface::class)->reveal(); - $extension = new TestExtension($guesser); - - $extension->addTypeExtension(new FormTypeFieldExtension([], [])); - $extensions[] = $extension; - - return $extensions; - } -}