Array collection is automatically converting to object when flusing to mongodb

166 Views Asked by At

I have following collection called config_settings in my mongo db

/**
 * @MongoDB\Document(collection="config_settings", repositoryClass="AppBundle\Repository\SettingRepository")
 * @MongoDB\HasLifecycleCallbacks()
 */
class Setting
{
    /**
     * @MongoDB\Id()
     * @var ObjectId $id
     */
    protected $id;

    /**
     * @MongoDB\Field(type="string")
     * @var string $name
     */
    protected $name;

    /**
     * @MongoDB\Field(type="raw")
     * @var array<array> $value
     */
    protected $value;

    /**
     * @return mixed
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @param mixed $id
     */
    public function setId($id): void
    {
        $this->id = $id;
    }

    /**
     * @return mixed
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @param mixed $name
     */
    public function setName($name): void
    {
        $this->name = $name;
    }

    /**
     * @return mixed
     */
    public function getValue()
    {
        return $this->value;
    }

    /**
     * @param mixed $value
     */
    public function setValue($value): void
    {
        $this->value = $value;
    }
}

I have a form that take values and name and saved it to the database a follow

<?php

namespace AppBundle\Form;

use AppBundle\Document\Setting;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
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 SettingCollectionType extends AbstractType
{
    /**
     * {@inheritdoc}
     * @param FormBuilderInterface<string|FormBuilderInterface> $builder
     * @param array<array> $options
     * @return void
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $choices = [];
        foreach ($options['featureKeys'] as $key) {
            $choices[$key] = $key;
        }

        $builder
            ->add('name', ChoiceType::class, [
                'label' => 'Feature',
                'choices' => $choices,
                'required' => true,
            ])
            ->add('value', CollectionType::class, array(
                'entry_type' => TextType::class,
                'prototype' => true,
                'allow_add' => true,
                'allow_delete' => true,
                'label' => false,
            ))
            ->add('submit', SubmitType::class, [
                'attr' => [
                    'class' => 'btn btn-outline-secondary'
                ],
            ]);
    }

    /**
     * {@inheritdoc}
     *  @param OptionsResolver $resolver
     *  @return void
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => Setting::class,
            'featureKeys' => null
        ));
    }

    /**
     * {@inheritdoc}
     */
    public function getBlockPrefix()
    {
        return '';
    }
}

So here is the problem, whenever I try to update the form and change the value, it always flush and saved it as an object instead of saving it as an array.

This is before flushing into my database.

enter image description here

And this is after flushed into my database.

enter image description here

Here is how i saved form inside my controller and it is very simple.

 if ('POST' === $request->getMethod()) {
            $form->handleRequest($request);
            if ($form->isValid()) {
                $dm->persist($entity);
                $dm->flush();
             }
    }

Am i doing something wrong ?

1

There are 1 best solutions below

0
malarzm On BEST ANSWER

MongoDB needs to have an array with consecutive indices to have it saved as an array in the database. Most probably it's not hence it's being saved as an object (with numeric keys I presume). Try using a collection type for your value field as it ensures what you're saving to the database is in fact a list. What collection does behind a scene is an additional array_values call while raw type saves the data as is.