Обработка на въвеждане на Json

Случай на употреба

Представете си даден случай на използване на изпращане на цял JSON чрез формуляр (чрез кодиращ масив във Frontend) като този:

Свързана статия: Работа с Vue.js форма в Symfony

Проблемът

Манипулаторът на формуляри на Symfony позволява използването на различни типове вход като TextType, ArrayChoiceList, ChoiceType и т.н., докато при използване на базиран на Array тип резултатът е празен масив. Единственият работещ случай е TextType, но той все още дава само необработен json — но това е нежелан резултат.

JsonType

След като се борих известно време, единственото работещо решение, което намерих, е предоставянето на нов тип въвеждане (JsonType) и нов DataTransformer като този:

DataTransformer

<?php

namespace App\Form\DataTransformer;

use Symfony\Component\Form\DataTransformerInterface;

/**
 * Handles transforming json to array and backward
 */
class JsonTransformer implements DataTransformerInterface
{

    /**
     * @inheritDoc
     */
    public function reverseTransform($value): mixed
    {
        if (empty($value)) {
            return [];
        }

        return json_decode($value);
    }

    /**
     * @ihneritdoc
     */
    public function transform($value): mixed
    {
        if (empty($value)) {
            return json_encode([]);
        }

        return json_encode($value);
    }
}

JsonType

<?php

namespace App\Form\Type;

use App\Form\DataTransformer\JsonTransformer;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Serializer\SerializerInterface;

/**
 * Handles json based input (for example multiselect tag)
 * Will only transform the json to array (and back),
 *
 * If necessary, could probably accept custom options (className) which would be used to
 * transform the data into given class via {@see SerializerInterface}
 */
class JsonType extends AbstractType
{
    /**
     * @inheritDoc
     */
    public function getParent(): string
    {
        return TextType::class;
    }

    /**
     * @inheritDoc
     */
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder->addModelTransformer(new JsonTransformer());
    }
}

Резюме

Крайният резултат е масив, трансформиран от json.