Skip to content

Commit 112f946

Browse files
committed
feature #1373 Add relations to entity form generation (maelanleborgne)
This PR was squashed before being merged into the 1.x-dev branch. Discussion ---------- Add relations to entity form generation PR for #1372 When generating a form for an entity (through `make:form` or `make:crud`), this feature adds an EntityType input for each compatible relations in the generate form. - [x] Add tests Commits ------- 85e4306 Add relations to entity form generation
2 parents a4bfda9 + 85e4306 commit 112f946

17 files changed

+735
-8
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## [v1.52.0](https://github.com/symfony/maker-bundle/releases/tag/v1.52.0)
4+
5+
### Feature
6+
7+
- [#1372](https://github.com/symfony/maker-bundle/issue/1372) - Support Entity relations in form generation - *@maelanleborgne*
8+
39
## [v1.50.0](https://github.com/symfony/maker-bundle/releases/tag/v1.50.0)
410

511
### Feature

src/Doctrine/EntityDetails.php

+15-6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Bundle\MakerBundle\Doctrine;
1313

1414
use Doctrine\Persistence\Mapping\ClassMetadata;
15+
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
1516

1617
/**
1718
* @author Sadicov Vladimir <[email protected]>
@@ -55,17 +56,25 @@ public function getFormFields(): array
5556
}
5657
}
5758

58-
foreach ($this->metadata->associationMappings as $fieldName => $relation) {
59-
if (\Doctrine\ORM\Mapping\ClassMetadata::ONE_TO_MANY !== $relation['type']) {
60-
$fields[] = $fieldName;
61-
}
62-
}
63-
6459
$fieldsWithTypes = [];
6560
foreach ($fields as $field) {
6661
$fieldsWithTypes[$field] = null;
6762
}
6863

64+
foreach ($this->metadata->associationMappings as $fieldName => $relation) {
65+
if (\Doctrine\ORM\Mapping\ClassMetadata::ONE_TO_MANY === $relation['type']) {
66+
continue;
67+
}
68+
$fieldsWithTypes[$fieldName] = [
69+
'type' => EntityType::class,
70+
'options_code' => sprintf('\'class\' => %s::class,', $relation['targetEntity']).PHP_EOL.'\'choice_label\' => \'id\',',
71+
'extra_use_classes' => [$relation['targetEntity']],
72+
];
73+
if (\Doctrine\ORM\Mapping\ClassMetadata::MANY_TO_MANY === $relation['type']) {
74+
$fieldsWithTypes[$fieldName]['options_code'] .= "\n'multiple' => true,";
75+
}
76+
}
77+
6978
return $fieldsWithTypes;
7079
}
7180
}

src/Renderer/FormTypeRenderer.php

+8
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ public function render(ClassNameDetails $formClassDetails, array $formFields, Cl
3939
if (isset($fieldTypeOptions['type'])) {
4040
$fieldTypeUseStatements[] = $fieldTypeOptions['type'];
4141
$fieldTypeOptions['type'] = Str::getShortClassName($fieldTypeOptions['type']);
42+
if (\array_key_exists('extra_use_classes', $fieldTypeOptions) && \count($fieldTypeOptions['extra_use_classes']) > 0) {
43+
$extraUseClasses = array_merge($extraUseClasses, $fieldTypeOptions['extra_use_classes'] ?? []);
44+
$fieldTypeOptions['options_code'] = str_replace(
45+
$fieldTypeOptions['extra_use_classes'],
46+
array_map(fn ($class) => Str::getShortClassName($class), $fieldTypeOptions['extra_use_classes']),
47+
$fieldTypeOptions['options_code']
48+
);
49+
}
4250
}
4351

4452
$fields[$name] = $fieldTypeOptions;

src/Resources/skeleton/form/Type.tpl.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
1616
->add('<?= $form_field ?>', <?= $typeOptions['type'] ?>::class)
1717
<?php else: ?>
1818
->add('<?= $form_field ?>', <?= $typeOptions['type'] ? ($typeOptions['type'].'::class') : 'null' ?>, [
19-
<?= $typeOptions['options_code']."\n" ?>
19+
<?= $typeOptions['options_code']."\n" ?>
2020
])
2121
<?php endif; ?>
2222
<?php endforeach; ?>

tests/Maker/MakeFormTest.php

+84
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,90 @@ public function getTestDetails()
9797
}),
9898
];
9999

100+
yield 'it_generates_form_with_many_to_one_relation' => [$this->createMakerTest()
101+
->addExtraDependencies('orm')
102+
->run(function (MakerTestRunner $runner) {
103+
$runner->copy(
104+
'make-form/relation_one_to_many/Book.php',
105+
'src/Entity/Book.php'
106+
);
107+
$runner->copy(
108+
'make-form/relation_one_to_many/Author.php',
109+
'src/Entity/Author.php'
110+
);
111+
112+
$runner->runMaker([
113+
// Entity name
114+
'BookType',
115+
'Book',
116+
]);
117+
118+
$this->runFormTest($runner, 'it_generates_form_with_many_to_one_relation.php');
119+
}),
120+
];
121+
yield 'it_generates_form_with_one_to_many_relation' => [$this->createMakerTest()
122+
->addExtraDependencies('orm')
123+
->run(function (MakerTestRunner $runner) {
124+
$runner->copy(
125+
'make-form/relation_one_to_many/Book.php',
126+
'src/Entity/Book.php'
127+
);
128+
$runner->copy(
129+
'make-form/relation_one_to_many/Author.php',
130+
'src/Entity/Author.php'
131+
);
132+
133+
$runner->runMaker([
134+
// Entity name
135+
'AuthorType',
136+
'Author',
137+
]);
138+
139+
$this->runFormTest($runner, 'it_generates_form_with_one_to_many_relation.php');
140+
}),
141+
];
142+
yield 'it_generates_form_with_many_to_many_relation' => [$this->createMakerTest()
143+
->addExtraDependencies('orm')
144+
->run(function (MakerTestRunner $runner) {
145+
$runner->copy(
146+
'make-form/relation_many_to_many/Book.php',
147+
'src/Entity/Book.php'
148+
);
149+
$runner->copy(
150+
'make-form/relation_many_to_many/Library.php',
151+
'src/Entity/Library.php'
152+
);
153+
154+
$runner->runMaker([
155+
// Entity name
156+
'BookType',
157+
'Book',
158+
]);
159+
160+
$this->runFormTest($runner, 'it_generates_form_with_many_to_many_relation.php');
161+
}),
162+
];
163+
yield 'it_generates_form_with_one_to_one_relation' => [$this->createMakerTest()
164+
->addExtraDependencies('orm')
165+
->run(function (MakerTestRunner $runner) {
166+
$runner->copy(
167+
'make-form/relation_one_to_one/Librarian.php',
168+
'src/Entity/Librarian.php'
169+
);
170+
$runner->copy(
171+
'make-form/relation_one_to_one/Library.php',
172+
'src/Entity/Library.php'
173+
);
174+
175+
$runner->runMaker([
176+
// Entity name
177+
'LibraryType',
178+
'Library',
179+
]);
180+
181+
$this->runFormTest($runner, 'it_generates_form_with_one_to_one_relation.php');
182+
}),
183+
];
100184
yield 'it_generates_form_with_embeddable_entity' => [$this->createMakerTest()
101185
->addExtraDependencies('orm')
102186
->run(function (MakerTestRunner $runner) {

tests/fixtures/make-form/Property.php

+12
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,16 @@ class Property
1818
#[ORM\ManyToOne(inversedBy: 'properties')]
1919
#[ORM\JoinColumn(name: 'sour_food_id', referencedColumnName: 'id')]
2020
private ?SourFood $sourFood = null;
21+
22+
public function setSourFood(?SourFood $sourFood): static
23+
{
24+
$this->sourFood = $sourFood;
25+
26+
return $this;
27+
}
28+
29+
public function getSourFood(): ?SourFood
30+
{
31+
return $this->sourFood;
32+
}
2133
}

tests/fixtures/make-form/SourFood.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,10 @@ public function getTitle()
4444
/**
4545
* @param mixed $title
4646
*/
47-
public function setTitle($title)
47+
public function setTitle($title): static
4848
{
4949
$this->title = $title;
50+
51+
return $this;
5052
}
5153
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
namespace App\Entity;
4+
5+
use Doctrine\Common\Collections\ArrayCollection;
6+
use Doctrine\Common\Collections\Collection;
7+
use Doctrine\ORM\Mapping as ORM;
8+
9+
#[ORM\Entity]
10+
class Book
11+
{
12+
#[ORM\Id]
13+
#[ORM\GeneratedValue(strategy: 'AUTO')]
14+
#[ORM\Column()]
15+
private ?int $id = null;
16+
17+
#[ORM\Column(name: 'title', length: 255)]
18+
private ?string $title = null;
19+
20+
#[ORM\ManyToMany(targetEntity: Library::class, mappedBy: 'books')]
21+
private Collection $libraries;
22+
23+
public function __construct()
24+
{
25+
$this->libraries = new ArrayCollection();
26+
}
27+
28+
public function getId()
29+
{
30+
return $this->id;
31+
}
32+
33+
public function getTitle(): string
34+
{
35+
return $this->title;
36+
}
37+
38+
public function setTitle(string $title): static
39+
{
40+
$this->title = $title;
41+
42+
return $this;
43+
}
44+
45+
public function getLibraries(): Collection
46+
{
47+
return $this->libraries;
48+
}
49+
public function setLibraries(Collection $libraries): static
50+
{
51+
$this->libraries = $libraries;
52+
return $this;
53+
}
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
namespace App\Entity;
4+
5+
use Doctrine\Common\Collections\ArrayCollection;
6+
use Doctrine\Common\Collections\Collection;
7+
use Doctrine\ORM\Mapping as ORM;
8+
9+
#[ORM\Entity]
10+
class Library
11+
{
12+
#[ORM\Id]
13+
#[ORM\GeneratedValue(strategy: 'AUTO')]
14+
#[ORM\Column()]
15+
private ?int $id = null;
16+
17+
#[ORM\ManyToMany(targetEntity: Book::class, inversedBy: 'libraries')]
18+
private Collection $books;
19+
20+
#[ORM\Column(name: 'name', length: 255)]
21+
private string $name;
22+
23+
public function __construct()
24+
{
25+
$this->books = new ArrayCollection();
26+
}
27+
28+
public function getId(): ?int
29+
{
30+
return $this->id;
31+
}
32+
33+
public function getBooks(): Collection
34+
{
35+
return $this->books;
36+
}
37+
38+
public function addBook(Book $book): static
39+
{
40+
$this->books->add($book);
41+
return $this;
42+
}
43+
44+
public function getName(): ?string
45+
{
46+
return $this->name;
47+
}
48+
public function setName(?string $name): static
49+
{
50+
$this->name = $name;
51+
return $this;
52+
}
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
namespace App\Entity;
4+
5+
use Doctrine\Common\Collections\ArrayCollection;
6+
use Doctrine\Common\Collections\Collection;
7+
use Doctrine\ORM\Mapping as ORM;
8+
9+
#[ORM\Entity]
10+
class Author
11+
{
12+
#[ORM\Id]
13+
#[ORM\GeneratedValue(strategy: 'AUTO')]
14+
#[ORM\Column()]
15+
private ?int $id = null;
16+
17+
#[ORM\OneToMany(targetEntity: Book::class, mappedBy: 'library')]
18+
private Collection $books;
19+
20+
#[ORM\Column(name: 'name', length: 255)]
21+
private string $name;
22+
23+
public function __construct()
24+
{
25+
$this->books = new ArrayCollection();
26+
}
27+
28+
public function getId(): ?int
29+
{
30+
return $this->id;
31+
}
32+
33+
public function getBooks(): Collection
34+
{
35+
return $this->books;
36+
}
37+
38+
public function getName(): ?string
39+
{
40+
return $this->name;
41+
}
42+
public function setName(?string $name): static
43+
{
44+
$this->name = $name;
45+
return $this;
46+
}
47+
}

0 commit comments

Comments
 (0)