1

在Symfony中,我正在爲Angular2編寫一個API。我使用帶有JMSSerializerBundle的FOSRestBundle。現在,我有一個實體「用戶」,其實體字段「地址」與OneToOne關聯。而且我無法保存用戶的地址。Symfony REST API - 實體關聯字段 - >值無效

所以我首先做一個用戶對象的GET,它返回的地址爲json的整個對象。然後,我使用完全相同的對象執行PUT請求。在我的PUT功能我用Symfony的形式來驗證數據和有它返回一個錯誤:

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

我有我的用戶實體其他一些領域,當我離開了地址欄的完美救了我形式建設者。順便說一句:我遺漏了其他領域,不超載代碼量。

我使用這些版本:

  • 的symfony:3.1
  • JMS /串行:1.1
  • friendsofsymfony /休息束: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; 

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; 

用戶類型類:

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'; 
    } 
} 

UserController類:

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("https://stackoverflow.com/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("https://stackoverflow.com/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; 
    } 

而且JSON對象,我GET和PUT看起來是這樣的:

{ 
"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" 

回答

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" 
     } 
    } 
}