2016-06-02 51 views
6

Spero che tu possa aiutarmi. Sto usando Symfony 2.xe Doctrine 2.x e vorrei creare un modulo composto da due entità. Compilando questo modulo, voglio mantenere i dati su due entità di dottrina.Il modulo incorporato Symfony2 non mantiene i dati nel database

Per semplicità ho fatto un esempio. Un webshop multilingue deve avere un nome e una descrizione del prodotto in inglese e francese. Voglio usare un modulo per creare un nuovo prodotto. Questo modulo di creazione includerà i dati dall'entità Product (id, productTranslations, price, productTranslations) e anche dall'entità ProductTranslation (id, nome, descrizione, lingua, prodotto). Il modulo di creazione dei risultati risultante include i seguenti campi (Nome, Descrizione, Lingua (EN/FR); Prezzo).

Le entità prodotto e prodotto di traduzione sono correlate tra loro attraverso una relazione bidirezionale uno-a-molti. Il sito di proprietà della relazione è ProductTranslation.

Dopo aver inviato il modulo, desidero mantenere i dati per entrambe le entità (prodotto e traduzione del prodotto). Qui è dove le cose vanno male. Non posso mantenere i dati.

thusfar, ho provato la seguente:

Entity prodotto:

<?php 

namespace AppBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 
use Doctrine\Common\Collections\ArrayCollection; 
use Symfony\Component\Validator\Constraints as Assert; 

/** 
* Product 
* 
* @ORM\Table(name="product") 
* @ORM\Entity(repositoryClass="AppBundle\Repository\ProductRepository") 
*/ 
class Product 
{ 
    /** 
    * @var int 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="price", type="decimal", precision=10, scale=0) 
    */ 
    private $price; 

    /** 
    * @ORM\OneToMany(targetEntity="AppBundle\Entity\ProductTranslation", mappedBy="product") 
    */ 
    private $productTranslations; 

    public function __construct() 
    { 
     $this->productTranslations = new ArrayCollection(); 
    } 

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

    /** 
    * Set price 
    * 
    * @param string $price 
    * 
    * @return Product 
    */ 
    public function setPrice($price) 
    { 
     $this->price = $price; 

     return $this; 
    } 

    /** 
    * Get price 
    * 
    * @return string 
    */ 
    public function getPrice() 
    { 
     return $this->price; 
    } 

    /** 
    * Set productTranslations 
    * 
    * @param \stdClass $productTranslations 
    * 
    * @return Product 
    */ 
    public function setProductTranslations($productTranslations) 
    { 
     $this->productTranslations = $productTranslations; 

     return $this; 
    } 

    /** 
    * Get productTranslations 
    * 
    * @return \stdClass 
    */ 
    public function getProductTranslations() 
    { 
     return $this->productTranslations; 
    } 

    /** 
    * Add productTranslation 
    * 
    * @param \AppBundle\Entity\ProductTranslation $productTranslation 
    * 
    * @return Product 
    */ 
    public function addProductTranslation(\AppBundle\Entity\ProductTranslation $productTranslation) 
    { 
     $this->productTranslations[] = $productTranslation; 

     return $this; 
    } 

    /** 
    * Remove productTranslation 
    * 
    * @param \AppBundle\Entity\ProductTranslation $productTranslation 
    */ 
    public function removeProductTranslation(\AppBundle\Entity\ProductTranslation $productTranslation) 
    { 
     $this->productTranslations->removeElement($productTranslation); 
    } 
} 

ProductTranslation Entity:

<?php 

namespace AppBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 

/** 
* ProductTranslation 
* 
* @ORM\Table(name="product_translation") 
* @ORM\Entity(repositoryClass="AppBundle\Repository\ProductTranslationRepository") 
*/ 
class ProductTranslation 
{ 
    /** 
    * @var int 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="name", type="string", length=255) 
    */ 
    private $name; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="description", type="text") 
    */ 
    private $description; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="language", type="string", length=5) 
    */ 
    private $language; 

    /** 
    * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Product", inversedBy="productTranslations",cascade={"persist"}) 
    * @ORM\JoinColumn(name="product_translation_id", referencedColumnName="id") 
    * 
    */ 
    private $product; 

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

    /** 
    * Set name 
    * 
    * @param string $name 
    * 
    * @return ProductTranslation 
    */ 
    public function setName($name) 
    { 
     $this->name = $name; 

     return $this; 
    } 

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

    /** 
    * Set description 
    * 
    * @param string $description 
    * 
    * @return ProductTranslation 
    */ 
    public function setDescription($description) 
    { 
     $this->description = $description; 

     return $this; 
    } 

    /** 
    * Get description 
    * 
    * @return string 
    */ 
    public function getDescription() 
    { 
     return $this->description; 
    } 

    /** 
    * Set language 
    * 
    * @param string $language 
    * 
    * @return ProductTranslation 
    */ 
    public function setLanguage($language) 
    { 
     $this->language = $language; 

     return $this; 
    } 

    /** 
    * Get language 
    * 
    * @return string 
    */ 
    public function getLanguage() 
    { 
     return $this->language; 
    } 

    /** 
    * Set product 
    * 
    * @param \AppBundle\Entity\Product $product 
    * 
    * @return ProductTranslation 
    */ 
    public function setProduct(\AppBundle\Entity\Product $product = null) 
    { 
     $this->product = $product; 

     return $this; 
    } 

    /** 
    * Get product 
    * 
    * @return \AppBundle\Entity\Product 
    */ 
    public function getProduct() 
    { 
     return $this->product; 
    } 
} 

ProductType:

<?php 

namespace AppBundle\Form; 

use Symfony\Component\Form\AbstractType; 
use Symfony\Component\Form\FormBuilderInterface; 
use Symfony\Component\OptionsResolver\OptionsResolver; 
use Symfony\Component\Form\Extension\Core\Type\MoneyType; 

class ProductType extends AbstractType { 

    /** 
    * @param FormBuilderInterface $builder 
    * @param array $options 
    */ 
    public function buildForm(FormBuilderInterface $builder, array $options) { 
     $builder->add('productTranslations', ProductTranslationType::class, array('label' => false, 'data_class' => null)); 
     $builder 
       ->add('price', MoneyType::class) 
     ; 
    } 

    /** 
    * @param OptionsResolver $resolver 
    */ 
    public function configureOptions(OptionsResolver $resolver) { 
     $resolver->setDefaults(array(
      'data_class' => 'AppBundle\Entity\Product' 
     )); 
    } 

} 

ProductTranslationType:

<?php 

namespace AppBundle\Form; 

use Symfony\Component\Form\AbstractType; 
use Symfony\Component\Form\FormBuilderInterface; 
use Symfony\Component\OptionsResolver\OptionsResolver; 
use Symfony\Component\Form\Extension\Core\Type\TextType; 
use Symfony\Component\Form\Extension\Core\Type\TextareaType; 
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; 

class ProductTranslationType extends AbstractType 
{ 
    /** 
    * @param FormBuilderInterface $builder 
    * @param array $options 
    */ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $builder 
      ->add('name', TextType::class) 
      ->add('description', TextareaType::class) 
      ->add('language', ChoiceType::class, array('choices' => array('en' => 'EN', 'fr' => 'FR'))) 
     ; 
    } 

    /** 
    * @param OptionsResolver $resolver 
    */ 
    public function configureOptions(OptionsResolver $resolver) 
    { 
     $resolver->setDefaults(array(
      'data_class' => 'AppBundle\Entity\ProductTranslation' 
     )); 
    } 
} 

ProductController:

<?php 

namespace AppBundle\Controller; 

use Symfony\Component\HttpFoundation\Request; 
use Symfony\Bundle\FrameworkBundle\Controller\Controller; 
use AppBundle\Entity\Product; 
use AppBundle\Form\ProductType; 
use AppBundle\Entity\ProductTranslation; 

/** 
* Product controller. 
* 
*/ 
class ProductController extends Controller { 

    /** 
    * Creates a new Product entity. 
    * 
    */ 
    public function newAction(Request $request) { 
     $em = $this->getDoctrine()->getManager(); 
     $product = new Product(); 

     $productTranslation = new ProductTranslation(); 

     $form = $this->createForm('AppBundle\Form\ProductType', $product); 
     $form->handleRequest($request); 

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

      $product->getProductTranslations()->add($product); 

      $productTranslation->setProduct($product); 

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

      return $this->redirectToRoute('product_show', array('id' => $product->getId())); 
     } 

     return $this->render('product/new.html.twig', array(
        'product' => $product, 
        'form' => $form->createView(), 
     )); 
    } 
} 

Errore:

Warning: spl_object_hash() expects parameter 1 to be object, string given 
500 Internal Server Error - ContextErrorException 

Ho consultato il ricettario per aiuto: http://symfony.com/doc/current/book/forms.html#embedded-forms, tuttavia non sono riuscito a farlo funzionare.

Update 1

non ho ancora trovato una risposta alla mia domanda. Seguendo i commenti qui sotto ho dato un'occhiata alle associazioni. Ho apportato delle modifiche a ProductController, che mi consente di verificare se i dati vengono inseriti nel database nel modo corretto. I dati sono stati inseriti correttamente, ma non riesco a inserirlo attraverso il modulo. Spero che qualcuno possa aiutarmi.

ProductController:

<?php 

namespace AppBundle\Controller; 

use Symfony\Component\HttpFoundation\Request; 
use Symfony\Bundle\FrameworkBundle\Controller\Controller; 

use AppBundle\Entity\Product; 
use AppBundle\Form\ProductType; 

/** 
* Creates a new Product entity. 
* 
*/ 
public function newAction(Request $request) { 
    $em = $this->getDoctrine()->getManager(); 
    $product = new Product(); 

    $productTranslation = new ProductTranslation(); 

    /* Sample data insertion */ 
    $productTranslation->setProduct($product); 
    $productTranslation->setName('Product Q'); 
    $productTranslation->setDescription('This is product Q'); 
    $productTranslation->setLanguage('EN'); 

    $product->setPrice(95); 
    $product->addProductTranslation($productTranslation); 

    $em->persist($product); 
    $em->persist($productTranslation); 
    $em->flush(); 
    /* End sample data insertion */ 

    $form = $this->createForm('AppBundle\Form\ProductType', $product); 
    $form->handleRequest($request); 

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

     $product->getProductTranslations()->add($product); 

     $productTranslation->setProduct($product); 

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

     return $this->redirectToRoute('product_show', array('id' => $product->getId())); 
    } 

    return $this->render('product/new.html.twig', array(
       'product' => $product, 
       'form' => $form->createView(), 
    )); 
} 

ottengo il seguente messaggio di errore ora:

Expected value of type "Doctrine\Common\Collections\Collection|array" for association field "AppBundle\Entity\Product#$productTranslations", got "string" instead. 

Update 2

A var_dump() dal prodotto variabile ProductController newAction prima persistente i dati mostrano:

object(AppBundle\Entity\Product)[493] 
    private 'id' => null 
    private 'price' => float 3 
    private 'productTranslations' => 
    object(Doctrine\Common\Collections\ArrayCollection)[494] 
     private 'elements' => 
     array (size=4) 
      'name' => string 'abc' (length=45) 
      'description' => string 'alphabet' (length=35) 
      'language' => string 'en' (length=2) 
      0 => 
      object(AppBundle\Entity\ProductTranslation)[495] 
       ... 
+0

Per prima cosa è necessario correggere i mapping di entità http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/association-mapping.html e impostare i metodi di gestione dell'associazione corretti http: // doctrine -orm.readthedocs.io/projects/doctrine-orm/it/latest/reference/working-with-associations.html di provare a mantenere un prodotto con le traduzioni in un controller e se funziona è meglio che puoi passare a utilizzare i moduli. – 1ed

+0

@ 1ed Penso che ti stavi riferendo all'errore che ho fatto con l'entità ProductTranslation. Ho dimenticato di aggiungere l'annotazione many-to-one per il prodotto. Tuttavia, il risultato è sempre lo stesso. –

+0

Hai appena modificato le mappature? Se è così, dovrai eseguire 'php app/console doctrine: schema: update --force'. Altrimenti, non ho altro suggerimento. Il messaggio di errore non mostra molto. Cosa succede quando usi "app_dev.php" aggiunto al tuo URL? –

risposta

2

stavo guardando attraverso il controller e noto che si sta persisti ProductTranslation, tuttavia nell'entità ProductTranslation vi manca l'annotazione per cascade={"persist"} sul rapporto all'entità del prodotto. Deve essere specificato sull'entità che stai persistendo se vuoi che salvi le entità correlate.

+0

Ho fatto un errore. Nella versione corrente ho 'cascade = {" persist "}', ma questo non cambia l'errore. –

4

L'errore è auto esplicativo; productTranslations deve essere un array o un arrayCollection. È invece una "stringa".

Così nel costruttore di prodotto:

public function __construct() 
{ 
    $this->activityTranslations = new ArrayCollection(); 
    $this->productTranslations = new \Doctrine\Common\Collections\ArrayCollection(); 
} 

Per setter/getter è possibile utilizzare:

public function addProductTranslation(AppBundle\Entity\ProductTranslation $pt) 
{ 
    $this->productTranslations[] = $pt; 
    $pt->setProduct($this); 
    return $this; 
} 


public function removeProductTranslation(AppBundle\Entity\ProductTranslation $pt) 
{ 
    $this->productTranslations->removeElement($pt); 
} 

public function getProductTranslations() 
{ 
    return $this->productTranslations; 
} 

Edit: In YAML con Symfony2.3, ecco la configurazione degli oggetti di mapping Sto usando (per enfatizzare dove si dovrebbe aggiungere la cascata).

//Product entity 
oneToMany: 
     productTranslations: 
     mappedBy: product 
     targetEntity: App\Bundle\...Bundle\Entity\ProductTranslation 
     cascade:  [persist] 

// ProductTranslation entity 
manyToOne: 
     product: 
     targetEntity: App\Bundle\..Bundle\Entity\Product 
     inversedBy: productTranslations 
     joinColumn: 
      name: product_id 
      type: integer 
      referencedColumnName: id 
      onDelete: cascade 

Inoltre, nota che si bisogno setProductTranslation() setter in entità del prodotto dal add e remove scopo di sostituirlo.

Edit2:

In Symfony2, ecco come mi occupo di forme con le collezioni:

class ProductType extends AbstractType 
{ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
     { 
      $builder 
       ->add('productPrice','number',array('required' => false)) 
       ->add('productTranslations', 'collection', array(
        'type' => new ProducatTranslationType() 

        )) 

      ; 

     } 

Non so perché non si specifica collezione nella vostra FormType. è la nuova versione di Symfony?

+0

Errore mio, l'avevo già notato e corretto. Tuttavia, ho dimenticato di aggiornare la domanda. Potresti per favore dare un'occhiata. –

+0

Ho dato un'occhiata alla tua modifica. Intendi dire che ricevi lo stesso errore anche dopo le modifiche? –

+0

Sì, ho lo stesso errore. Il messaggio di errore suggerisce che si tratta di un problema con la matrice, ma non capisco perché viene convertito in una stringa. Penso che il problema sia nel productcontroller dopo la validazione. L'oggetto viene convertito in una stringa. –

2
$product->getProductTranslations()->add($product); 
$productTranslation->setProduct($product); 

IDK cosa si vuole fare qui, ma credo che è necessario utilizzare:

$product->addProductTranslation($productTranslation); 
$productTranslation->setProduct($product); 

$ product-> getProductTranslations() restituisce un ArrayCollection di classe 'ProductTranslation' e si uniscono quella matrice con il valore di tipo 'Prodotto'.

È un po 'incoerente, se sbaglio potresti dirmi cosa stai facendo in quella frase?

Grazie!

+0

Grazie per l'input. Non preoccuparti per il mio codice. Il problema rimane se persisto i dati. Ho fatto un var_dump della mia variabile di prodotto. Spero che aiuti a risolvere il mio problema. –