简体   繁体   中英

Symfony Form CollectionType with API post of new/existing entities

Building an internal API endpoint which allows another service to update specific fields for users, identified by email addresses. If the user does not exist, it needs to be created.

The code is working perfectly fine providing only new users are submitted.

This is the POST request to the API endpoint.

[
    {
        "email":"existing@user.com",
        "favouriteFood": "pizza"
    },
    {
        "email":"new@user.com",
        "favouriteFood": "sweets"
    }
]

Controller action

public function postUsersAction(Request $request)
{
    $form = $this->createForm(UserCollectionType::class);
    $form->submit(['users' => json_decode($request->getContent(), true)], true);

    if (!$form->isValid()) {
        return $form;
    }

    /** @var User $user */
    foreach ($form->getData()['users'] as $user) {
        $this->userManager->updateUser($user);
    }

    $this->em->flush();

    return $form->getData()['users'];
}

UserCollectionType

class UserCollectionType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('users', 'collection', [
            'allow_add' => true,
            'by_reference' => false,
            'type' => UserType::class
        ]);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'csrf_protection' => false,
            'cascade_validation' => true
        ]);
    }

    public function getBlockPrefix()
    {
        return '';
    }
}

UserType

class UserType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('email')
            ->add('favouriteFood', TextType::class);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => User::class,
            'validation_groups' => ['user_api'],
            'cascade_validation' => true
        ]);
    }
} 

How can I update the above code so that it will check to see if the user exists first, otherwise continue to create a new one how it's currently working.

I'd have assumed a DataTransformer could have been used, but not exactly how.

EDIT: Proposed solution by ShylockTheCamel

Inside the controller.

$post = json_decode($request->getContent(), true);
$users = [];

foreach ($post as $userRaw) {
    $user = $this->em->findOneBy($userRaw['email']); // example search logic in the DB

    if (!$user) {
        $user = new User();
    }

    $users[] = $user;
}

$form = $this->createForm(UserCollectionType::class, $users);
$form->submit(['users' => $post], true);

If I understand correctly, your user(s) entity(ies) exist when you enter the foreach loop. So you must create them in the form creation process. In that case, why not check th existence of a user in one of your form validators?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM