Skip to content

Commit

Permalink
feature #1373 Add relations to entity form generation (maelanleborgne)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
weaverryan committed Oct 31, 2023
2 parents a4bfda9 + 85e4306 commit 112f946
Show file tree
Hide file tree
Showing 17 changed files with 735 additions and 8 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## [v1.52.0](https://github.com/symfony/maker-bundle/releases/tag/v1.52.0)

### Feature

- [#1372](https://github.com/symfony/maker-bundle/issue/1372) - Support Entity relations in form generation - *@maelanleborgne*

## [v1.50.0](https://github.com/symfony/maker-bundle/releases/tag/v1.50.0)

### Feature
Expand Down
21 changes: 15 additions & 6 deletions src/Doctrine/EntityDetails.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Bundle\MakerBundle\Doctrine;

use Doctrine\Persistence\Mapping\ClassMetadata;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;

/**
* @author Sadicov Vladimir <sadikoff@gmail.com>
Expand Down Expand Up @@ -55,17 +56,25 @@ public function getFormFields(): array
}
}

foreach ($this->metadata->associationMappings as $fieldName => $relation) {
if (\Doctrine\ORM\Mapping\ClassMetadata::ONE_TO_MANY !== $relation['type']) {
$fields[] = $fieldName;
}
}

$fieldsWithTypes = [];
foreach ($fields as $field) {
$fieldsWithTypes[$field] = null;
}

foreach ($this->metadata->associationMappings as $fieldName => $relation) {
if (\Doctrine\ORM\Mapping\ClassMetadata::ONE_TO_MANY === $relation['type']) {
continue;
}
$fieldsWithTypes[$fieldName] = [
'type' => EntityType::class,
'options_code' => sprintf('\'class\' => %s::class,', $relation['targetEntity']).PHP_EOL.'\'choice_label\' => \'id\',',
'extra_use_classes' => [$relation['targetEntity']],
];
if (\Doctrine\ORM\Mapping\ClassMetadata::MANY_TO_MANY === $relation['type']) {
$fieldsWithTypes[$fieldName]['options_code'] .= "\n'multiple' => true,";
}
}

return $fieldsWithTypes;
}
}
8 changes: 8 additions & 0 deletions src/Renderer/FormTypeRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ public function render(ClassNameDetails $formClassDetails, array $formFields, Cl
if (isset($fieldTypeOptions['type'])) {
$fieldTypeUseStatements[] = $fieldTypeOptions['type'];
$fieldTypeOptions['type'] = Str::getShortClassName($fieldTypeOptions['type']);
if (\array_key_exists('extra_use_classes', $fieldTypeOptions) && \count($fieldTypeOptions['extra_use_classes']) > 0) {
$extraUseClasses = array_merge($extraUseClasses, $fieldTypeOptions['extra_use_classes'] ?? []);
$fieldTypeOptions['options_code'] = str_replace(
$fieldTypeOptions['extra_use_classes'],
array_map(fn ($class) => Str::getShortClassName($class), $fieldTypeOptions['extra_use_classes']),
$fieldTypeOptions['options_code']
);
}
}

$fields[$name] = $fieldTypeOptions;
Expand Down
2 changes: 1 addition & 1 deletion src/Resources/skeleton/form/Type.tpl.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
->add('<?= $form_field ?>', <?= $typeOptions['type'] ?>::class)
<?php else: ?>
->add('<?= $form_field ?>', <?= $typeOptions['type'] ? ($typeOptions['type'].'::class') : 'null' ?>, [
<?= $typeOptions['options_code']."\n" ?>
<?= $typeOptions['options_code']."\n" ?>
])
<?php endif; ?>
<?php endforeach; ?>
Expand Down
84 changes: 84 additions & 0 deletions tests/Maker/MakeFormTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,90 @@ public function getTestDetails()
}),
];

yield 'it_generates_form_with_many_to_one_relation' => [$this->createMakerTest()
->addExtraDependencies('orm')
->run(function (MakerTestRunner $runner) {
$runner->copy(
'make-form/relation_one_to_many/Book.php',
'src/Entity/Book.php'
);
$runner->copy(
'make-form/relation_one_to_many/Author.php',
'src/Entity/Author.php'
);

$runner->runMaker([
// Entity name
'BookType',
'Book',
]);

$this->runFormTest($runner, 'it_generates_form_with_many_to_one_relation.php');
}),
];
yield 'it_generates_form_with_one_to_many_relation' => [$this->createMakerTest()
->addExtraDependencies('orm')
->run(function (MakerTestRunner $runner) {
$runner->copy(
'make-form/relation_one_to_many/Book.php',
'src/Entity/Book.php'
);
$runner->copy(
'make-form/relation_one_to_many/Author.php',
'src/Entity/Author.php'
);

$runner->runMaker([
// Entity name
'AuthorType',
'Author',
]);

$this->runFormTest($runner, 'it_generates_form_with_one_to_many_relation.php');
}),
];
yield 'it_generates_form_with_many_to_many_relation' => [$this->createMakerTest()
->addExtraDependencies('orm')
->run(function (MakerTestRunner $runner) {
$runner->copy(
'make-form/relation_many_to_many/Book.php',
'src/Entity/Book.php'
);
$runner->copy(
'make-form/relation_many_to_many/Library.php',
'src/Entity/Library.php'
);

$runner->runMaker([
// Entity name
'BookType',
'Book',
]);

$this->runFormTest($runner, 'it_generates_form_with_many_to_many_relation.php');
}),
];
yield 'it_generates_form_with_one_to_one_relation' => [$this->createMakerTest()
->addExtraDependencies('orm')
->run(function (MakerTestRunner $runner) {
$runner->copy(
'make-form/relation_one_to_one/Librarian.php',
'src/Entity/Librarian.php'
);
$runner->copy(
'make-form/relation_one_to_one/Library.php',
'src/Entity/Library.php'
);

$runner->runMaker([
// Entity name
'LibraryType',
'Library',
]);

$this->runFormTest($runner, 'it_generates_form_with_one_to_one_relation.php');
}),
];
yield 'it_generates_form_with_embeddable_entity' => [$this->createMakerTest()
->addExtraDependencies('orm')
->run(function (MakerTestRunner $runner) {
Expand Down
12 changes: 12 additions & 0 deletions tests/fixtures/make-form/Property.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,16 @@ class Property
#[ORM\ManyToOne(inversedBy: 'properties')]
#[ORM\JoinColumn(name: 'sour_food_id', referencedColumnName: 'id')]
private ?SourFood $sourFood = null;

public function setSourFood(?SourFood $sourFood): static
{
$this->sourFood = $sourFood;

return $this;
}

public function getSourFood(): ?SourFood
{
return $this->sourFood;
}
}
4 changes: 3 additions & 1 deletion tests/fixtures/make-form/SourFood.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@ public function getTitle()
/**
* @param mixed $title
*/
public function setTitle($title)
public function setTitle($title): static
{
$this->title = $title;

return $this;
}
}
54 changes: 54 additions & 0 deletions tests/fixtures/make-form/relation_many_to_many/Book.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
class Book
{
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'AUTO')]
#[ORM\Column()]
private ?int $id = null;

#[ORM\Column(name: 'title', length: 255)]
private ?string $title = null;

#[ORM\ManyToMany(targetEntity: Library::class, mappedBy: 'books')]
private Collection $libraries;

public function __construct()
{
$this->libraries = new ArrayCollection();
}

public function getId()
{
return $this->id;
}

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

public function setTitle(string $title): static
{
$this->title = $title;

return $this;
}

public function getLibraries(): Collection
{
return $this->libraries;
}
public function setLibraries(Collection $libraries): static
{
$this->libraries = $libraries;
return $this;
}
}
53 changes: 53 additions & 0 deletions tests/fixtures/make-form/relation_many_to_many/Library.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
class Library
{
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'AUTO')]
#[ORM\Column()]
private ?int $id = null;

#[ORM\ManyToMany(targetEntity: Book::class, inversedBy: 'libraries')]
private Collection $books;

#[ORM\Column(name: 'name', length: 255)]
private string $name;

public function __construct()
{
$this->books = new ArrayCollection();
}

public function getId(): ?int
{
return $this->id;
}

public function getBooks(): Collection
{
return $this->books;
}

public function addBook(Book $book): static
{
$this->books->add($book);
return $this;
}

public function getName(): ?string
{
return $this->name;
}
public function setName(?string $name): static
{
$this->name = $name;
return $this;
}
}
47 changes: 47 additions & 0 deletions tests/fixtures/make-form/relation_one_to_many/Author.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
class Author
{
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'AUTO')]
#[ORM\Column()]
private ?int $id = null;

#[ORM\OneToMany(targetEntity: Book::class, mappedBy: 'library')]
private Collection $books;

#[ORM\Column(name: 'name', length: 255)]
private string $name;

public function __construct()
{
$this->books = new ArrayCollection();
}

public function getId(): ?int
{
return $this->id;
}

public function getBooks(): Collection
{
return $this->books;
}

public function getName(): ?string
{
return $this->name;
}
public function setName(?string $name): static
{
$this->name = $name;
return $this;
}
}

0 comments on commit 112f946

Please sign in to comment.