1

Symfony で Angular2 の API を書いています。JMSSerializerBundle で FOSRestBundle を使用します。現在、OneToOne 関連付けを持つエンティティ フィールド「アドレス」を持つエンティティ「ユーザー」があります。また、ユーザーのアドレスを保存するのに問題があります。

したがって、最初にユーザー オブジェクトの GET を実行すると、オブジェクト全体がアドレスとともに json として返されます。次に、まったく同じオブジェクトで PUT リクエストを行います。私の PUT 関数では、Symfony フォームを使用してデータを検証すると、エラーが返されます。

{
  "children": {
    "address": {
      "errors": [
        "This value is not valid."
      ]
    }
  }
}

User エンティティには他にもいくつかのフィールドがあり、フォーム ビルダーでアドレス フィールドを省略すると、それらは完全に保存されます。ところで: コードの量が過負荷にならないように、他のフィールドは省略しました。

私はこれらのバージョンを使用します:

  • symfony: 3.1
  • jms/シリアライザー: 1.1
  • friendsofsymfony/rest-bundle: 2.0

私は今2日間探していましたが、この問題に役立つものは何も見つかりません. 私は FOSRestBundle が言うように日付変換を使用します: http://symfony.com/doc/current/bundles/FOSRestBundle/2-the-view-layer.html#data-transformation

質問を十分に定式化し、十分な情報を提供したことを願っています。

これが私の簡略化されたコードです:

ユーザークラス:

use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as JMS;

/**
 * @ORM\Entity
 */
class User
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\OneToOne(targetEntity="Address", cascade={"persist", "remove"}, orphanRemoval=true)
     * @JMS\Type("AppBundle\Entity\Address")
     */
    private $address;

住所クラス:

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class Address
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(type="string")
     */
    private $street;

    /**
     * @ORM\Column(type="string")
     */
    private $number;

    /**
     * @ORM\Column(type="string")
     */
    private $postalCode;

    /**
     * @ORM\Column(type="string")
     */
    private $city;

    /**
     * @ORM\Column(type="string")
     */
    private $country;

UserType クラス:

use FOS\RestBundle\Form\Transformer\EntityToIdObjectTransformer;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class UserType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // Data transformation needed for relationship entities
        $addressTransformer = new EntityToIdObjectTransformer($options['em'], 'AppBundle:Address');

        $builder
            ->add($builder->create('address', TextType::class)->addModelTransformer($addressTransformer))
        ;
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\User',
            'csrf_protection'   => false,
            'allow_extra_fields' => true,
            'em' => null
        ));
    }

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

ユーザーコントローラークラス:

use AppBundle\Entity\User;
use AppBundle\Form\UserType;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\View\View;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;

/**
 * Class UserController
 * @package AppBundle\Controller
 */
class UserController extends Controller
{
    /**
     * @Rest\View
     * @Route("/users/{id}")
     * @Method("PUT")
     */
    public function putAction(Request $request, $id)
    {
        $user = $this->getEntity($id);
        $form = $this->createForm(UserType::class, $user, array(
            'method' => 'PUT',
            'em' => $this->getDoctrine()->getManager()
        ));

        $form->handleRequest($request);

        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();

            $em->persist($user);
            $em->flush();

            $response = new Response();
            $response->setStatusCode(204);
            $response->setContent('User saved!');

            return $response;
        }

        return View::create($form, 400);
    }


    /**
     * @Rest\View
     * @Route("/users/{id}", requirements={"id": "\d+"})
     * @Method("GET")
     */
    public function getAction($id)
    {
        $user = $this->getEntity($id);

        return array('user' => $user);
    }

    /**
     * Get the User entity object by the given ID and return it
     *
     * @param $id
     *
     * @return User
     */
    private function getEntity($id)
    {
        $user = $this->getDoctrine()->getRepository('AppBundle:User')->find($id);

        if (!$user instanceof User) {
            throw new NotFoundHttpException('User not found');
        }

        return $user;
    }

そして、GET および PUT した json-object は次のようになります。

{
"user":
    {
        "id":1,
        "address": {
            "id":1,
            "street":"Teststreet",
            "number":"1",
            "postalCode":"9999",
            "city":"Citytest",
            "country":"Countrytest"
        }
    }
}

私のconfig.yml:

fos_rest:
    param_fetcher_listener: true
    body_listener:
        array_normalizer: fos_rest.normalizer.camel_keys
    format_listener:
        rules:
            path: ^/
            fallback_format: json
            prefer_extension: false
            priorities: [json, xml]
    body_converter:
        enabled:              false
        validate:             false
    view:
        view_response_listener: force
        formats:
            json: true
            xml: true
        templating_formats:
            html: true
        force_redirects:
            html: true
        failed_validation: HTTP_BAD_REQUEST
        default_engine: twig
        mime_types:
            json: ['application/json', 'application/json;version=1.0', 'application/json;version=1.1']
    routing_loader:
        default_format: json
    serializer:
        serialize_null: true

nelmio_api_doc: ~

jms_serializer:
    metadata:
        directories:
            FOSUB:
                namespace_prefix: "FOS\\UserBundle"
                path: "%kernel.root_dir%/serializer/FOSUserBundle"
4

1 に答える 1

0

私はそのようなことをしましたが、フォームタイプのモデルトランスフォーマーなしでそれを行いました. これが私のコードです

ユーザータイプ:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('address', AddressType::class)
    ;
}

住所タイプ:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('street', AddressType::class)
        ->add('number', AddressType::class)
        ->add('postalCode', AddressType::class)
        // ...
    ;
}

そして、置くjsonオブジェクト

{
"user":
    {
        "address": {
            "street":"Teststreet",
            "number":"1",
            "postalCode":"9999",
            "city":"Citytest",
            "country":"Countrytest"
        }
    }
}
于 2016-07-24T05:06:24.760 に答える