mercredi 5 juillet 2017

PHP silex Formbuilder and object with array of object

I am using PHP with the Silex framework and after some hours trying to find a satisfying solution I am still blocked with the following problem regarding forms and objects containing array of Objects. The hours spent permitted me to find a working solution but I hope there is a better way to do that with Silex.

In my application I have a User class that is defined like :

class User implements UserInterface
{
    private $id;
    private $username;
    private $displayname;
    private $capacities;
    //...
}

$capacities variable contains an array of objects from another class (Capacity). A Capacity is a specific role in my app with various information (label, place of the capacity ...) and I have added, in that Capacity class a boolean telling if the Capacity is active for a specific user, when attached to a user via the $capacities array.

At the moment I am able to create the form that looks as I want with the following code :

use Planning\Domain\User;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints as Assert;


class UserType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('username', TextType::class, array(
                    'required'    => true,
                    'label' => "Login (pour Jean Durant → jdurant)"
                    ))
            ->add('displayname', TextType::class, array(
                    'label' => "Nom à afficher"
                ));

        $choices = array();
        $choicesActive = array();
        foreach ($builder->getData()->getCapacities() as $id => $capacity) {
            $choices[$capacity->getLabel()] = $capacity->getId();
            if ($capacity->getActive()) {
                $choicesActive[] = $capacity->getId();
            }
        }

        $builder->add('capacities', ChoiceType::class, array(
            'choices' => $choices,
            'data' => $choicesActive,
            'label' => "Groupes",
            'multiple' => True,
            'expanded' => True
        ));
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => User::class,

        ));
    }

    public function getName()
    {
        return 'capacity';
    }
}

but the User object I am getting after the form is validated contains for capacities :

[capacities:Planning\Domain\User:private] => Array
    (
        [0] => 2
        [1] => 4
        [2] => 1
    )

capacities variable contains the list of values for checkboxes that have been checked in the form. The issue is that my User object is not consistant with its definition which says that the capacities property should be an array of Capacity objects. What I am doing at the moment is that I have added the following code to my controller when $userForm->isSubmitted() and $userForm->isValid() :

// Getting the array from the returned user, should contain Capacity object but just contains the IDs.
$capacitiesChecked = $userForm->getData()->getCapacities();
// We regenerate the full array of capacities for this user
$user->setCapacities($app["dao.capacity"]->findAll());

// Then we will activate capacities that have been checked, one by one
foreach ($capacitiesChecked as $capacityChecked) {
    $user->getCapacityById($capacityChecked)->setActive(True);
}

This is working and I am happy with it but being new to Silex and the framework world, I am surprized that I have not been able to find an easier way to answer my problem which I believe should be quite common.

I might be missing something from the Silex/Symfony philosophy and I hope someone there will be able to point me to the correct place to get more information or find a solution!

Aucun commentaire:

Enregistrer un commentaire