Advanced usage: example with Doctrine

That's not really an advanced topic, but the sample will be a bit hard to read (as it takes many files), so let's say it targets more experienced Symfony users.

In this demo, we're displaying a MyArray of MyElements, both persisted into the database. The MyArray entity only have an id and a name, and MyElement has id, MyArray's id and a value. This is quite the same as we seen in all demos, but persisted.

Array name:
Add an element...

Existing arrays:
Name Open Delete
name}) }} Open Delete
_ Open Delete
___ ☘ Cela fonctionne à Open Delete
_____ Open Delete
_________coucou Open Delete
___array___ Open Delete
__bvnvbnvbnvbn Open Delete
---#i1097c8b84b58a65ed6ec7b4f0da3ab67 Open Delete
---#i21ef661e2506d5d0e513dce166c17d49 Open Delete
. Open Delete
'rtrt Open Delete
#69 Open Delete
#AlgoSucks Open Delete
%231 Open Delete
%25237233333#ic3ee8978c60737ab5d058b5a3f6a1b09 Open Delete
%252372uuuu#i21ef661e2506d5d0e513dce166c17d49 Open Delete
%252372uuuu#i8c18088ea4d8dd4d6e5e986bceed35da Open Delete
%252372uuuu#ie025efbbb0738ed01a63b326c174233e Open Delete
%252391 Open Delete
%253F#i5784b3886628c4362594ffa43547edb4 Open Delete
%253F#ic3ee8978c60737ab5d058b5a3f6a1b09 Open Delete
%253F#ie025efbbb0738ed01a63b326c174233e Open Delete
%C3%B1lkjlkj Open Delete
%C3%B1sfkjaldsa Open Delete
<?php echo ' i don't like it ' Open Delete
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<LETTRE GREC>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Open Delete
<script>alert('test')</script> Open Delete
<script>alert('test')</script>%n%n%n%n%n%n Open Delete
<script>alert('test')</script>%n%n%n%n%n%n<script>alert('test')</script>%n%n%n%n%n%n<script>alert('test')</script>%n%n%n%n%n%n<script>alert('test')</script>%n%n%n%n%n%n<script>alert('test')</script>%n%n%n%n%n%n<script>alert('test')</script>%n%n%n%n%n%n<sc Open Delete
~~~ Open Delete
00000 Open Delete
11#i27992875ec4286a24e569b1e015b0473 Open Delete
11#i8c18088ea4d8dd4d6e5e986bceed35da Open Delete
11#ic3ee8978c60737ab5d058b5a3f6a1b09 Open Delete
1111#i1097c8b84b58a65ed6ec7b4f0da3ab67 Open Delete
1111#i8c18088ea4d8dd4d6e5e986bceed35da Open Delete
1111111111111111111111111111111111#i27992875ec4286a24e569b1e015b0473 Open Delete
1111111111111111111111111111111111#i5784b3886628c4362594ffa43547edb4 Open Delete
1111111111111111111111111111111111#i8c18088ea4d8dd4d6e5e986bceed35da Open Delete
12 Delete
12345 Open Delete
2' Open Delete
222 Open Delete
2222%2520example Open Delete
2323 Open Delete
3 Open Delete
86787 Open Delete
8888 Open Delete
8chan.org Open Delete
a Open Delete
☘ Cela fonctionne ☘ Open Delete
A1 Open Delete
ñlkjlkj Open Delete
aaaaaaa Open Delete
aaaaaaaaaaaaaa22 Open Delete
тест Open Delete
aaamine Open Delete
aaamine22222 Open Delete
aaamine22222#i1097c8b84b58a65ed6ec7b4f0da3ab67 Open Delete
aaamine22222#i21ef661e2506d5d0e513dce166c17d49 Open Delete
aaamine22222#ic3ee8978c60737ab5d058b5a3f6a1b09 Open Delete
adsada Open Delete
adsfdsf Open Delete
aee Open Delete
alsi Open Delete
as Open Delete
asd asd asd Open Delete
asdas Open Delete
asdasd#i1dcd1cbb0d8eeb1fd3a32dc2aa9c8013 Open Delete
asdasd#i27992875ec4286a24e569b1e015b0473 Open Delete
asdasd#ibcac9f4c58199eeaa7ba5c7750b8434b Open Delete
asdasd#ic3ee8978c60737ab5d058b5a3f6a1b09 Open Delete
asdasdadasd Open Delete
asdasdadasd#i5784b3886628c4362594ffa43547edb4 Open Delete
asdasdadasd#ic3ee8978c60737ab5d058b5a3f6a1b09 Open Delete
asdasdasd Open Delete
asdasddadsd Open Delete
azerty'A=0 Open Delete
balala Open Delete
bbbbbbbbbbbbbbbb Open Delete
bite Open Delete
bjfhj#i1097c8b84b58a65ed6ec7b4f0da3ab67 Open Delete
bjfhj#i1dcd1cbb0d8eeb1fd3a32dc2aa9c8013 Open Delete
bjfhj#i5784b3886628c4362594ffa43547edb4 Open Delete
bjfhj#i8c18088ea4d8dd4d6e5e986bceed35da Open Delete
bjfhj#ibcac9f4c58199eeaa7ba5c7750b8434b Open Delete
bjfhj#ie025efbbb0738ed01a63b326c174233e Open Delete
blah#i1097c8b84b58a65ed6ec7b4f0da3ab67 Open Delete
blah#ic3ee8978c60737ab5d058b5a3f6a1b09 Open Delete
blah#ie025efbbb0738ed01a63b326c174233e Open Delete
Bra Open Delete
cdcdc Open Delete
ciao Open Delete
crap Open Delete
cvSDFSD Open Delete
cx%3Cwc Open Delete
D#i8c18088ea4d8dd4d6e5e986bceed35da Open Delete
D#ie025efbbb0738ed01a63b326c174233e Open Delete
dadd Open Delete
dcdc Open Delete
dddd Open Delete
Demo Open Delete
dfa#i5784b3886628c4362594ffa43547edb4 Open Delete
dfa#ibcac9f4c58199eeaa7ba5c7750b8434b Open Delete
dfa#ic3ee8978c60737ab5d058b5a3f6a1b09 Open Delete
dfa#ie025efbbb0738ed01a63b326c174233e Open Delete
dfdfdf Open Delete
dfdsf Open Delete
dfg Open Delete
dfty Open Delete
dghdfgdfgd Open Delete
drgd Open Delete
dsds Open Delete
eeeeee Open Delete
ejemplo 2017 Open Delete
ejemplo 2017-11-23 Open Delete
erwgfuıgj8hlı Open Delete
example Open Delete
example%20exam Open Delete
example123#i1097c8b84b58a65ed6ec7b4f0da3ab67 Open Delete
example123#i21ef661e2506d5d0e513dce166c17d49 Open Delete
example123#i5784b3886628c4362594ffa43547edb4 Open Delete
example123#i8c18088ea4d8dd4d6e5e986bceed35da Open Delete
example123#ie025efbbb0738ed01a63b326c174233e Open Delete
exampleasfsafasf#i1097c8b84b58a65ed6ec7b4f0da3ab67 Open Delete
exampleasfsafasf#i1dcd1cbb0d8eeb1fd3a32dc2aa9c8013 Open Delete
exampleasfsafasf#ic3ee8978c60737ab5d058b5a3f6a1b09 Open Delete
exampledsdsdd Open Delete
exampledsdsdda Open Delete
examplesadas Open Delete
examplesafs;af;sfsf Open Delete
exampleu Open Delete
exampleuy Open Delete
examplexzasca Open Delete
Existing arr Open Delete
exkiample Open Delete
eze Open Delete
fdf#i27992875ec4286a24e569b1e015b0473 Open Delete
fdf#i5784b3886628c4362594ffa43547edb4 Open Delete
fdf#i8c18088ea4d8dd4d6e5e986bceed35da Open Delete
fdf#ic3ee8978c60737ab5d058b5a3f6a1b09 Open Delete
fdf#ie025efbbb0738ed01a63b326c174233e Open Delete
fdsf Open Delete
fdsfds Open Delete
ff Open Delete
ff d Open Delete
ffff Open Delete
fgfdg Open Delete
gdfg#i1097c8b84b58a65ed6ec7b4f0da3ab67 Open Delete
gdfg#i1dcd1cbb0d8eeb1fd3a32dc2aa9c8013 Open Delete
gdfg#i21ef661e2506d5d0e513dce166c17d49 Open Delete
gdfg#i27992875ec4286a24e569b1e015b0473 Open Delete
gege Open Delete
geht nicht Open Delete
gfgddgfd Open Delete
gg Open Delete
Ggg Open Delete
GGI Open Delete
ghj Open Delete
ghjk#i1097c8b84b58a65ed6ec7b4f0da3ab67 Open Delete
ghjk#i1dcd1cbb0d8eeb1fd3a32dc2aa9c8013 Open Delete
ghjk#i21ef661e2506d5d0e513dce166c17d49 Open Delete
ghjk#i5784b3886628c4362594ffa43547edb4 Open Delete
ghjk#ic3ee8978c60737ab5d058b5a3f6a1b09 Open Delete
Group C Open Delete
Group%20B Open Delete
Group%2BC Open Delete
Group%2BC#i1dcd1cbb0d8eeb1fd3a32dc2aa9c8013 Open Delete
Group%2BC#i21ef661e2506d5d0e513dce166c17d49 Open Delete
Group%2BC#ie025efbbb0738ed01a63b326c174233e Open Delete
gtgt Open Delete
gufc fucvuy Open Delete
hbhbhb Open Delete
Hello World Open Delete
hellowrld Open Delete
HEYY%2520:D Open Delete
HEYY%2520:D#i1097c8b84b58a65ed6ec7b4f0da3ab67 Open Delete
HEYY%2520:D#i21ef661e2506d5d0e513dce166c17d49 Open Delete
HEYY%2520:D#i27992875ec4286a24e569b1e015b0473 Open Delete
HEYY%2520:D#i5784b3886628c4362594ffa43547edb4 Open Delete
HEYY%2520:D#i8c18088ea4d8dd4d6e5e986bceed35da Open Delete
hgkjh Open Delete
hhmm Open Delete
hoho Open Delete
hrthrh Open Delete
htrhrh Open Delete
htt Open Delete
interest Open Delete
iujjj Open Delete
j Open Delete
jhj Open Delete
jtujjk Open Delete
kfhk Open Delete
khj#i8c18088ea4d8dd4d6e5e986bceed35da Open Delete
khj#ibcac9f4c58199eeaa7ba5c7750b8434b Open Delete
khj#ic3ee8978c60737ab5d058b5a3f6a1b09 Open Delete
kjkk Open Delete
kkik Open Delete
kkk#i1dcd1cbb0d8eeb1fd3a32dc2aa9c8013 Open Delete
kkk#ic3ee8978c60737ab5d058b5a3f6a1b09 Open Delete
kkk#ie025efbbb0738ed01a63b326c174233e Open Delete
kmkm Open Delete
kpok Open Delete
lkj Open Delete
llllllllllllllll Open Delete
Lorenz du Open Delete
loslos Open Delete
Marcin Open Delete
mmm Open Delete
moi Open Delete
mon tableau Open Delete
mon%20exemple Open Delete
mon%20putain%20de%20tableau Open Delete
mon%20tableau Open Delete
Mumbojumbo Open Delete
mytest Open Delete
name Open Delete
тест Open Delete
New Array Open Delete
New_test_2017-03_03 Open Delete
new%20test Open Delete
nmn#i21ef661e2506d5d0e513dce166c17d49 Open Delete
nmn#ibcac9f4c58199eeaa7ba5c7750b8434b Open Delete
Nouveau Open Delete
o%C4%B1 Open Delete
oezjfez Open Delete
oij Open Delete
oui Open Delete
perses#i1097c8b84b58a65ed6ec7b4f0da3ab67 Open Delete
perses#i8c18088ea4d8dd4d6e5e986bceed35da Open Delete
perses#ic3ee8978c60737ab5d058b5a3f6a1b09 Open Delete
perses#ie025efbbb0738ed01a63b326c174233e Open Delete
po Open Delete
polo Open Delete
pornhub.com Open Delete
pp Open Delete
pppppii#i1dcd1cbb0d8eeb1fd3a32dc2aa9c8013 Open Delete
pppppii#i27992875ec4286a24e569b1e015b0473 Open Delete
pppppii#ic3ee8978c60737ab5d058b5a3f6a1b09 Open Delete
Premier element de test Open Delete
quantite%20--1 Open Delete
qweqw Open Delete
qwert Open Delete
r Open Delete
rar Open Delete
rdfgdf Open Delete
referees Open Delete
rerererere Open Delete
rewq Open Delete
rrr Open Delete
rrrr#ibcac9f4c58199eeaa7ba5c7750b8434b Open Delete
rrrr#ic3ee8978c60737ab5d058b5a3f6a1b09 Open Delete
rrrr#ie025efbbb0738ed01a63b326c174233e Open Delete
sad Open Delete
sasa Open Delete
sdasd Open Delete
seeme#i21ef661e2506d5d0e513dce166c17d49 Open Delete
seeme#i27992875ec4286a24e569b1e015b0473 Open Delete
seeme#i5784b3886628c4362594ffa43547edb4 Open Delete
seeme#i8c18088ea4d8dd4d6e5e986bceed35da Open Delete
seeme#ie025efbbb0738ed01a63b326c174233e Open Delete
someNewArray#i1097c8b84b58a65ed6ec7b4f0da3ab67 Open Delete
someNewArray#i1dcd1cbb0d8eeb1fd3a32dc2aa9c8013 Open Delete
someNewArray#i21ef661e2506d5d0e513dce166c17d49 Open Delete
someNewArray#i27992875ec4286a24e569b1e015b0473 Open Delete
someNewArray#ic3ee8978c60737ab5d058b5a3f6a1b09 Open Delete
someNewArray#ie025efbbb0738ed01a63b326c174233e Open Delete
sqsq Open Delete
Starojitski Open Delete
STASI Open Delete
Ta mere la Open Delete
Ta%20mere%20la%20grosse%20tchoin Open Delete
Ta%2520mere%2520la%2520grosse%2520choin#i27992875ec4286a24e569b1e015b0473 Open Delete
terst Open Delete
tesst Open Delete
test nours Open Delete
test--1 Open Delete
test34'A=0 Open Delete
testarray Open Delete
teste Open Delete
teste2 Open Delete
TESTEN Open Delete
testing Open Delete
testsetse Open Delete
testtest Open Delete
texte Open Delete
the test Open Delete
This Open Delete
try01 Open Delete
tset Open Delete
tutu Open Delete
tyty Open Delete
ui Open Delete
uu Open Delete
uuu Open Delete
vcvcvcvcvv Open Delete
Volta Dilma Fo Open Delete
Volta Dilma Fora Temer Open Delete
Volta%20Dilma%20Fora% Open Delete
Volta%2520Dilma%2520Fora%2520Temer#i1097c8b84b58a65ed6ec7b4f0da3ab67 Open Delete
Volta%2520Dilma%2520Fora%2520Temer#i2 Open Delete
Volta%2520Dilma%2520Fora%2520Temer#i21ef661e2506d5d0e513dce166c17d49 Open Delete
Volta%2520Dilma%2520Fora%2520Temer#ic3ee8978c60737ab5d058b5a3f6a1b09 Open Delete
Volta%2520Dilma%2520Fora%2520Temer#ie025efbbb0738ed01a63b326c174233e Open Delete
werweexample Open Delete
why%20doctrine%20on%20delete%20not%20work Open Delete
Woop% Open Delete
Woop%20wooop Open Delete
wqeqe Open Delete
xcxcxcx Open Delete
xx Open Delete
xxx Open Delete
xy Open Delete
yfcx Open Delete
yiktikrtr Open Delete
zdzd Open Delete
zzzz1 Open Delete
ролр Open Delete
File: Base/BaseController.php
<?php

namespace Fuz\AppBundle\Base;

use Fuz\AppBundle\Entity\Value;
use Fuz\AppBundle\Form\ValueType;
use Fuz\QuickStartBundle\Base\BaseController as QuickStartBase;
use Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\HttpFoundation\Request;

class BaseController extends QuickStartBase
{
    protected function createContextSample(Request $request, $name = 'form', $values = ['a', 'b', 'c'])
    {
        $data = ['values' => $values];

        $form = $this
           ->get('form.factory')
           ->createNamedBuilder($name, Type\FormType::class, $data)
           ->add('values', Type\CollectionType::class, [
               'entry_type'    => Type\TextType::class,
               'label'         => 'Add, move, remove values and press Submit.',
               'entry_options' => [
                   'label' => 'Value',
               ],
               'allow_add'    => true,
               'allow_delete' => true,
               'prototype'    => true,
               'attr'         => [
                   'class' => "{$name}-collection",
               ],
           ])
           ->add('submit', Type\SubmitType::class)
           ->getForm()
        ;

        $form->handleRequest($request);
        if ($form->isValid()) {
            $data = $form->getData();
        }

        return [
            $name         => $form->createView(),
            "{$name}Data" => $data,
        ];
    }

    protected function createAdvancedContextSample(Request $request, $name = 'advancedForm')
    {
        $a = new Value('a');
        $b = new Value('b');
        $c = new Value('c');

        $data = ['values' => [$a, $b, $c]];

        $form = $this
           ->get('form.factory')
           ->createNamedBuilder($name, Type\FormType::class, $data)
           ->add('values', Type\CollectionType::class, [
               'entry_type'   => ValueType::class,
               'label'        => 'Add, move, remove values and press Submit.',
               'allow_add'    => true,
               'allow_delete' => true,
               'prototype'    => true,
               'required'     => false,
               'attr'         => [
                   'class' => "{$name}-collection",
               ],
           ])
           ->add('submit', Type\SubmitType::class)
           ->getForm()
        ;

        $form->handleRequest($request);
        if ($form->isValid()) {
            $data = $form->getData();
        }

        return [
            $name         => $form->createView(),
            "{$name}Data" => $data,
        ];
    }
}
File: Base/BaseController.php
File: Controller/AdvancedController.php
<?php

namespace Fuz\AppBundle\Controller;

use Fuz\AppBundle\Base\BaseController;
use Fuz\AppBundle\Entity\Address;
use Fuz\AppBundle\Entity\Addresses;
use Fuz\AppBundle\Entity\Fancy;
use Fuz\AppBundle\Entity\FancyCollection;
use Fuz\AppBundle\Entity\Value;
use Fuz\AppBundle\Form\AddressesType;
use Fuz\AppBundle\Form\FancyCollectionType;
use Fuz\AppBundle\Form\MyArrayType;
use Fuz\AppBundle\Form\ValueType;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\HttpFoundation\Request;

/**
 * @Route("/advanced")
 */
class AdvancedController extends BaseController
{
    /**
     * Advanced usage
     *
     * You can reference your form collection in the view, instead of
     * putting a selector in the form type.
     *
     * @Route("/mvcCompliance", name="mvcCompliance")
     * @Template()
     */
    public function mvcComplianceAction(Request $request)
    {
        $data = ['values' => ['a', 'b', 'c']];

        $form = $this
           ->createFormBuilder($data)
           ->add('values', Type\CollectionType::class, [
               'entry_type'    => Type\TextType::class,
               'label'         => 'Add, move, remove values and press Submit.',
               'entry_options' => [
                   'label' => 'Value',
               ],
               'allow_add'    => true,
               'allow_delete' => true,
               'prototype'    => true,
               'required'     => false,
//                   'attr' => array (
//                           'class' => 'my-selector', <--- Not MVC compliant!
//                   ),
           ])
           ->add('submit', Type\SubmitType::class)
           ->getForm()
        ;

        $form->handleRequest($request);
        if ($form->isValid()) {
            $data = $form->getData();
        }

        return [
            'form' => $form->createView(),
            'data' => $data,
        ];
    }

    /**
     * Advanced usage
     *
     * A custom form theme helps define button's layout and positions as and where you want.
     *
     * @Route("/customFormTheme", name="customFormTheme")
     * @Template()
     */
    public function customFormThemeAction(Request $request)
    {
        $data = ['values' => [new Value('a'), new Value('b'), new Value('c')]];

        $form = $this
           ->createFormBuilder($data)
           ->add('values', Type\CollectionType::class, [
               'entry_type'   => ValueType::class,
               'label'        => 'Add, move, remove values and press Submit.',
               'allow_add'    => true,
               'allow_delete' => true,
               'prototype'    => true,
               'required'     => false,
               'attr'         => [
                   'class' => 'collection',
               ],
           ])
           ->add('submit', Type\SubmitType::class)
           ->getForm()
        ;

        $form->handleRequest($request);
        if ($form->isValid()) {
            $data = $form->getData();
        }

        return [
            'form' => $form->createView(),
            'data' => $data,
        ];
    }

    /**
     * Advanced usage
     *
     * Same demo as above, but with the add button located at the bottom of
     * the form instead of close to each field.
     *
     * @Route("/customFormThemeAddBottom", name="customFormThemeAddBottom")
     * @Template()
     */
    public function customFormThemeAddBottomAction(Request $request)
    {
        return $this->customFormThemeAction($request);
    }

    /**
     * Advanced usage
     *
     * Collection of collections are useful on the most dynamic forms, and a good
     * way to test if the plugin is working as expected too.
     *
     * @Route("/collectionOfCollections", name="collectionOfCollections")
     * @Template()
     */
    public function collectionOfCollectionsAction(Request $request)
    {
        $data = [
            'collections' => [
                [new Value('a'), new Value('b'), new Value('c')],
                [new Value('d'), new Value('e'), new Value('f')],
                [new Value('g'), new Value('h'), new Value('i')],
            ],
        ];

        $form = $this
           ->get('form.factory')
           ->createNamedBuilder('form', Type\FormType::class, $data)
           ->add('collections', Type\CollectionType::class, [
               'entry_type'    => Type\CollectionType::class,
               'label'         => 'Add, move, remove collections',
               'entry_options' => [
                   'entry_type'    => ValueType::class,
                   'label'         => 'Add, move, remove values',
                   'entry_options' => [
                       'label' => 'Value',
                   ],
                   'allow_add'      => true,
                   'allow_delete'   => true,
                   'prototype'      => true,
                   'prototype_name' => '__children_name__',
                   'attr'           => [
                       'class' => 'child-collection',
                   ],
               ],
               'allow_add'      => true,
               'allow_delete'   => true,
               'prototype'      => true,
               'prototype_name' => '__parent_name__',
               'attr'           => [
                   'class' => 'parent-collection',
               ],
           ])
           ->add('submit', Type\SubmitType::class)
           ->getForm()
        ;

        $form->handleRequest($request);
        if ($form->isValid()) {
            $data = $form->getData();
        }

        return [
            'form' => $form->createView(),
            'data' => $data,
        ];
    }

    /**
     * Advanced usage
     *
     * Looks like there are weird behaviours with Doctrine:
     * https://github.com/ninsuo/symfony-collection/issues/7
     * Let's test that live!
     *
     * ... hmm, doesn't look bad anyway
     *
     * @Route(
     *      "/usageWithDoctrine/{name}",
     *      name = "usageWithDoctrine",
     *      defaults = {
     *          "name" = "example"
     *      }
     * )
     * @Template()
     */
    public function usageWithDoctrineAction(Request $request, $name)
    {
        $repo = $this->getDoctrine()->getRepository('FuzAppBundle:MyArray');

        $data = $repo->findOneByName($name);
        if (is_null($data)) {
            $data = $repo->create($name);
        }

        $form = $this->createForm(MyArrayType::class, $data);
        $form->handleRequest($request);

        $form->get('save')->isClicked() && $form->isValid() && $repo->save($data);

        return [
            'names' => $repo->getArrayNames(),
            'form'  => $form->createView(),
            'data'  => $data,
        ];
    }

    /**
     * Related to usageWithDoctrine demo
     *
     * @Route(
     *      "/usageWithDoctrineDelete/{name}",
     *      name = "usageWithDoctrineDelete"
     * )
     */
    public function usageWithDoctrineDeleteAction(Request $request, $name)
    {
        $repo = $this->getDoctrine()->getRepository('FuzAppBundle:MyArray');
        if (!is_null($data = $repo->findOneByName($name))) {
            $repo->delete($data);
        }

        return $this->forward('FuzAppBundle:Advanced:usageWithDoctrine', [
            'name' => 'example',
        ]);
    }

    /**
     * A form having a theme and containing several fields
     *
     * @Route(
     *      "/formHavingSeveralFields",
     *      name = "formHavingSeveralFields"
     * )
     * @Template()
     */
    public function formHavingSeveralFieldsAction(Request $request)
    {
        $address = new Address();
        $address->setName('Mickael Steller');
        $address->setCompany('fuz.org');
        $address->setStreet('41 rue de la Paix');
        $address->setPostalcode('75002');
        $address->setCity('Paris');
        $address->setCountry('France');

        $addresses = new Addresses();
        $addresses->getAddresses()->add($address);

        $form = $this->createForm(AddressesType::class, $addresses);
        if ($request->isMethod('POST')) {
            $form->handleRequest($request);
        }

        return [
            'form' => $form->createView(),
            'data' => $addresses,
        ];
    }

    /**
     * Another example of form theme
     *
     * @Route(
     *      "/fancyFormTheme",
     *      name = "fancyFormTheme"
     * )
     * @Template()
     */
    public function fancyFormThemeAction(Request $request)
    {
        $fancyCollection = new FancyCollection();

        for ($i = 0; $i < 3; $i++) {
            $fancy = new Fancy();
            $fancyCollection->getFancyCollection()->add($fancy);
        }

        $form = $this->createForm(FancyCollectionType::class, $fancyCollection);

        $form->handleRequest($request);
        if ($form->isValid()) {
            $data = $form->getData();
        }

        return [
            'form' => $form->createView(),
            'data' => $fancyCollection,
        ];
    }
}
File: Controller/AdvancedController.php
File: Entity/MyArray.php
<?php

namespace Fuz\AppBundle\Entity;

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

/**
 * MyArray
 *
 * @ORM\Table(
 *      name="my_array",
 *      uniqueConstraints={@ORM\UniqueConstraint(name="name_idx", columns={"name"})}
 * )
 * @ORM\Entity(repositoryClass="Fuz\AppBundle\Repository\MyArrayRepository")
 */
class MyArray
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    protected $name;

    /**
     * @var ArrayCollection
     *
     * @ORM\OneToMany(targetEntity="MyElement", mappedBy="array", cascade={"all"}, orphanRemoval=true)
     */
    protected $elements;

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

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

    public function getName()
    {
        return $this->name;
    }

    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    public function getElements()
    {
        return $this->elements;
    }
}
File: Entity/MyArray.php
File: Entity/MyElement.php
<?php

namespace Fuz\AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * MyElement
 *
 * @ORM\Table(name="my_element"),
 * @ORM\Entity
 */
class MyElement
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @var MyArray
     *
     * @ORM\ManyToOne(targetEntity="MyArray", inversedBy="elements")
     * @ORM\JoinColumn(name="my_array_id", referencedColumnName="id")
     */
    protected $array;

    /**
     * @var string
     *
     * @ORM\Column(name="value", type="string", length=255)
     */
    protected $value;

    public function setId($id)
    {
        $this->id = $id;

        return $this;
    }

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

    public function setArray(MyArray $array)
    {
        $this->array = $array;

        return $this;
    }

    public function getArray()
    {
        return $this->array;
    }

    public function setValue($value)
    {
        $this->value = $value;

        return $this;
    }

    public function getValue()
    {
        return $this->value;
    }
}
File: Entity/MyElement.php
File: Form/MyArrayType.php
<?php

namespace Fuz\AppBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class MyArrayType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('name', TextType::class, [
                'label' => 'Array name:',
        ]);

        $builder->add('elements', CollectionType::class, [
            'label'        => 'Add an element...',
            'entry_type'   => MyElementType::class,
            'allow_add'    => true,
            'allow_delete' => true,
            'prototype'    => true,
            'required'     => false,
            'by_reference' => true,
            'delete_empty' => true,
            'attr'         => [
                'class' => 'doctrine-sample',
            ],
        ]);

        $builder->add('save', SubmitType::class, [
                'label' => 'Save this array',
        ]);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => 'Fuz\AppBundle\Entity\MyArray',
        ]);
    }

    public function getBlockPrefix()
    {
        return 'my_array';
    }
}
File: Form/MyArrayType.php
File: Form/MyElementType.php
<?php

namespace Fuz\AppBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class MyElementType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('value', TextType::class, [
            'required' => false,
        ]);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => 'Fuz\AppBundle\Entity\MyElement',
        ]);
    }

    public function getBlockPrefix()
    {
        return 'my_element';
    }
}
File: Form/MyElementType.php
File: Repository/MyArrayRepository.php
<?php

namespace Fuz\AppBundle\Repository;

use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use Doctrine\ORM\EntityRepository;
use Fuz\AppBundle\Entity\MyArray;

/**
 * MyArrayRepository.
 */
class MyArrayRepository extends EntityRepository
{
    public function create($name)
    {
        $data = new MyArray();
        $data->setName($name);
        try {
            $this->_em->persist($data);
            $this->_em->flush();
        } catch (UniqueConstraintViolationException $e) {
            return null;
        }

        return $data;
    }

    public function save(MyArray $data)
    {
        foreach ($data->getElements() as $element) {
            $element->setArray($data);
        }
        try {
            $this->_em->persist($data);
            $this->_em->flush();
        } catch (UniqueConstraintViolationException $e) {
            return null;
        }

        return $data;
    }

    public function getArrayNames()
    {
        $arrays = $this
            ->_em
            ->createQuery("
               SELECT arr.name
               FROM Fuz\AppBundle\Entity\MyArray arr
            ")
            ->execute();
        $names = [];
        foreach ($arrays as $array) {
            $names[] = $array['name'];
        }

        return $names;
    }

    public function delete(MyArray $data)
    {
        foreach ($data->getElements() as $element) {
            $this->_em->remove($element);
        }
        $this->_em->remove($data);
        $this->_em->flush();
    }
}
File: Repository/MyArrayRepository.php
File: Resources/views/Advanced/doctrine-theme.html.twig

{% block my_element_label %}{% endblock %}
{% block my_element_errors %}{% endblock %}

{% block my_element_widget %}

    <div class="row">
        <div class="col-md-7">
            {{ form_widget(form.value) }}
        </div>
        <div class="col-md-2">
            <a href="#" class="collection-up btn btn-default">Up</a>
            <a href="#" class="collection-down btn btn-default">Down</a>
        </div>
        <div class="col-md-2">
            <a href="#" class="collection-remove btn btn-default">Remove</a>
            <a href="#" class="collection-add btn btn-default">Add</a>
        </div>
        <div class="col-md-1">
            <a href="#" class="collection-duplicate btn btn-default">Duplicate</a>
        </div>
    </div>

{% endblock %}
File: Resources/views/Advanced/doctrine-theme.html.twig
File: Resources/views/Advanced/usageWithDoctrine.html.twig
{% extends 'FuzAppBundle::layout.html.twig' %}

{% block extra_js %}
    <script src="{{ asset('js/jquery.collection.js') }}"></script>
{% endblock %}

{% block title %}Advanced usage: example with Doctrine{% endblock %}

{% block body %}

    <h2>{{ block('title') }}</h2>

    <p>
        That's not really an <i>advanced</i> topic, but the sample will be a bit hard to read (as it takes many files),
        so let's say it targets more experienced Symfony users.
    </p>

    <p>
        In this demo, we're displaying a MyArray of MyElements, both persisted into the database. The MyArray entity
        only have an id and a name, and MyElement has id, MyArray's id and a value. This is quite the same as we seen
        in all demos, but persisted.
    </p>

    <div class="text-center">
        <input type="button" id="new" class="btn btn-default" value="Create new array"/>
    </div>

    {%
        form_theme form
            'jquery.collection.html.twig'
            'FuzAppBundle:Advanced:doctrine-theme.html.twig'
    %}
    {{ form(form) }}

    <hr/>

    {% if names|length %}
        Existing arrays:
        <table class="table">
            <thead>
                <th>Name</th>
                <th>Open</th>
                <th>Delete</th>
            </thead>
            <tbody>
                {% for name in names %}
                    <tr>
                        <td>{{ name }}</td>
                        <td>
                            {% if data.name != name %}<a href="{{ path('usageWithDoctrine', {'name': name}) }}">Open</a>{% endif %}
                        </td>
                        <td><a href="{{ path('usageWithDoctrineDelete', {'name': name}) }}">Delete</a></td>
                    </tr>
                {% endfor %}
            </tbody>
        </table>
    {% endif %}

    {{
        tabs([
            'Base/BaseController.php',
            'Controller/AdvancedController.php',
            'Resources/views/Advanced/usageWithDoctrine.html.twig',
            'Resources/views/Advanced/doctrine-theme.html.twig',
            'Entity/MyArray.php',
            'Form/MyArrayType.php',
            'Entity/MyElement.php',
            'Form/MyElementType.php',
            'Repository/MyArrayRepository.php',
        ])
    }}

{% endblock %}

{% block script %}

    <script type="text/javascript">

        // only useful for the "new" button...
        $('#new').on('click', function() {
           var name = prompt("Which name would you like to use?");
           if (name) {
               var uri = '{{ path('usageWithDoctrine', {'name': 'a'}) }}';
               document.location = uri.substr(0, uri.length - 1) + encodeURIComponent(name);
           }
        });

        $('.doctrine-sample').collection();

    </script>

{% endblock %}
File: Resources/views/Advanced/usageWithDoctrine.html.twig