2014-12-08 2 views
0

Я боролся с этим в течение нескольких дней, поэтому я надеюсь, что кто-то может помочь.Symfony2 встроенная форма OneToMany отношения, как сохранить связанные данные

У меня есть отношение OneToMany между таблицей. Ресурсы и мой FOSUserBundle предоставляют пользовательский объект, так что один пользователь может разместить много ресурсов.

Примечание: сущности, были отредактированы для краткости, однако я не считаю, что я удалил что-нибудь важное для этого вопроса

Мои ресурсы объект:

<?php 

namespace SFI\MainBundle\Entity; 
use Doctrine\ORM\Mapping as ORM; 

/** 
* @ORM\Entity(repositoryClass="SFI\MainBundle\Entity\ResourcesRepository") 
* @ORM\Table(name="resources") 
*/ 

class Resources { 
/** 
* @ORM\Column(name="id", type="integer", nullable=false) 
* @ORM\Id() 
* @ORM\GeneratedValue(strategy="IDENTITY") 
*/ 

protected $id; 

/** 
* @ORM\Column(type="string", length=255) 
*/ 

protected $name; 

/** 
* @ORM\Column(type="string", length=255) 
*/ 

protected $type; 

/** 
* @ORM\Column(type="string", length=255) 
*/ 

protected $link; 

/** 
* @ORM\Column(type="text") 
*/ 

protected $description; 

/** 
* @ORM\Column(type="datetime") 
*/ 

protected $created_time; 

/** 
* @ORM\ManyToOne(targetEntity="SFI\UserBundle\Entity\User", inversedBy="created_by") 
* @ORM\JoinColumn(name="created_by", referencedColumnName="id") 
*/ 
protected $created_by; 

---rest of getters and setters--- 

    /** 
    * Set created_by 
    * 
    * @param \SFI\UserBundle\Entity\User $createdBy 
    * @return Resources 
    */ 
    public function setCreatedBy(\SFI\UserBundle\Entity\User $createdBy = null) 
    { 
     $this->created_by = $createdBy; 

     return $this; 
    } 

    /** 
    * Get created_by 
    * 
    * @return \SFI\UserBundle\Entity\User 
    */ 
    public function getCreatedBy() 
    { 
     return $this->created_by; 
    } 
} 

Моя сущность Пользователь:

<?php 

namespace SFI\UserBundle\Entity; 

use FOS\UserBundle\Model\User as BaseUser; 
use Doctrine\ORM\Mapping as ORM; 
use Symfony\Component\Validator\Constraints as Assert; 

/** 
* @ORM\Entity(repositoryClass="SFI\UserBundle\Entity\UserRepository") 
* @ORM\Table(name="fos_user") 
*/ 
class User extends BaseUser 
{ 
    /** 
    * @ORM\Id 
    * @ORM\Column(type="integer") 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    protected $id; 

    public function __construct() 
    { 
     parent::__construct(); 
    } 

    /** 
    * @ORM\Column(type="string", length=255) 
    * 
    * @Assert\NotBlank(message="Please enter your name.", groups={"Registration", "Profile"}) 
    * @Assert\Length(
    *  min=3, 
    *  max="255", 
    *  minMessage="The name is too short.", 
    *  maxMessage="The name is too long.", 
    *  groups={"Registration", "Profile"} 
    *) 
    */ 
    protected $name; 

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

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

     return $this; 
    } 

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

    /** 
    * @ORM\OneToMany(targetEntity="SFI\MainBundle\Entity\Resources", mappedBy="created_by") 
    */ 
    protected $created_by; 

    /** 
    * Add created_by 
    * 
    * @param \SFI\MainBundle\Entity\Resources $createdBy 
    * @return User 
    */ 
    public function addCreatedBy(\SFI\MainBundle\Entity\Resources $createdBy) 
    { 
     $this->created_by[] = $createdBy; 

     return $this; 
    } 

    /** 
    * Remove created_by 
    * 
    * @param \SFI\MainBundle\Entity\Resources $createdBy 
    */ 
    public function removeCreatedBy(\SFI\MainBundle\Entity\Resources $createdBy) 
    { 
     $this->created_by->removeElement($createdBy); 
    } 

    /** 
    * Get created_by 
    * 
    * @return \Doctrine\Common\Collections\Collection 
    */ 
    public function getCreatedBy() 
    { 
     return $this->created_by; 
    } 
} 

У меня есть несколько типов форм, но основной, с которыми я работаю, это ResourceType:

<?php 
namespace SFI\MainBundle\Form\Type; 

use Symfony\Component\Form\AbstractType; 
use Symfony\Component\Form\FormBuilderInterface; 
use Symfony\Component\OptionsResolver\OptionsResolverInterface; 

class ResourceType extends AbstractType 
{ 

    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 

    //Setting date and time 
    $created_at = new \DateTime('now'); 

    $builder 
     ->add('name', 'text', array(
     'required' => true, 
     'attr' => array(
      'class' => 'form-control', 
      'placeholder' => 'Resource name', 
     ), 
    )) 
     ->add('type', 'choice', array(
     'required' => true, 
     'empty_value' => 'Choose a type', 
     'choices' => array('w' => 'Website', 'v' => 'Video', 'a' => 'Audio'), 
     'attr' => array(
      'class' => 'form-control', 
     ), 
    )) 
     ->add('link', 'text', array(
     'required' => true, 
     'attr' => array(
      'class' => 'form-control', 
      'placeholder' => 'Add a link', 
     ), 
    )) 
     ->add('description', 'textarea', array(
     'required' => true, 
     'attr' => array(
      'class' => 'textarea', 
      'style' => 'width: 100%; height: 200px; font-size: 14px; line-height: 18px; border: 1px solid #dddddd; padding: 10px;', 
      'placeholder' => 'Write a description...', 
     ), 
    )) 
     ->add('created_time', 'datetime', array(
     'disabled' => true, 
     'data' => $created_at, 
    )) 
     ->add('save', 'submit', array(
     'attr' => array('class' => 'btn btn-primary'), 
    )); 
    } 

    public function getName() 
    { 
    return 'resource'; 
    } 

    public function setDefaultOptions(OptionsResolverInterface $resolver) 
    { 
    $resolver->setDefaults(array(
     'data_class' => 'SFI\MainBundle\Entity\Resources', 
    )); 
    } 
} 

Мой контроллер для вида ресурса части:

public function resourcesAction(Request $request) 
    { 

     $breadcrumbs = $this->get("white_october_breadcrumbs"); 
     $breadcrumbs->addItem("SFI Portalen", $this->get("router")->generate("sfi_static_index")); 
     $breadcrumbs->addItem("Teacher Dashboard", $this->get("router")->generate("sfi_teacher_dashboard")); 
     $breadcrumbs->addItem("Resources"); 

     $em = $this->getDoctrine()->getManager(); 

     $resource = new Resources(); 

     $newResourceForm = $this->createForm(new ResourceType(), $resource); 
     $newResourceForm->handleRequest($request); 

     if ($newResourceForm->isValid()) { 

     $session = $this->getRequest()->getSession(); 
     //$session->getFlashBag()->add('notice', 'Form processed'); 
     $session->getFlashBag()->add('notice', 'Form processed, testing, no persist'); 

     //$em->persist($resource); 
     //$em->flush(); 

     return $this->redirect($this->generateUrl('sfi_teacher_resources')); 
     } 

     return $this->render('SFIMainBundle:Teacher:resources.html.twig', array(
     'form' => $newResourceForm->createView(), 
    )); 
    } 

Что мне нужно сделать, это связать эти объекты при создании нового ресурса, чтобы «назначить» его вошедшего пользователя через отношение в таблицах.

Я изучил встроенные формы и другие предложения по документации Symfony, но я не могу окунуться в то, как применять то, что я читал к этому конкретному примеру. Я следовал примеру с задачами, тегами и категориями, и все это, но я не могу понять, как это применимо к моей ситуации, имея объект User в другом комплекте и тип формы пользователя, который связывает пользователя с их и добавляет дополнительное полное поле имени, наследуя исходный тип формы FOSUserBundle.

У меня также есть смешное ощущение, что я не занимался или «правильно формулировал» отношения в своем коде, чтобы было легче понять, какие объекты связаны.

Любая помощь была бы высоко оценена! Также, пожалуйста, дайте мне знать, если вам нужен другой код или дополнительная информация.

+1

Не то, чтобы это вызывало какие-либо ошибки, но использование одного и того же имени отношения между двумя объектами является путаным. Подумайте о переименовании своего объекта 'User', чтобы вместо свойства' created_by' как нечто вроде 'resources' вместо свойства' created_by'. – sjagr

+0

Я изменил это, я согласен, это облегчает ситуацию. Я также изменю заголовок, так как сейчас нет ошибки в том, как я показываю форму, я просто хотел бы знать, что мне еще нужно, чтобы создать форму, которая будет сохранять данные с правильной связью. – TuxMeister

ответ

2

Вы должны просто установить пользователя вручную, прежде чем продолжать работу с объектом Resource.

if ($newResourceForm->isValid()) { 
    ... 
    $resource->setCreatedBy($this->getUser()); 
    $em->persist($resource); 
    $em->flush(); 
    ... 
    } 

Symfony использует $ this-> GetUser() ярлыка в контроллерах (см http://symfony.com/doc/current/book/security.html#retrieving-the-user-object). Я предполагаю, что вы разрешаете только эту форму, когда пользователь вошел в систему.

Также, если вы используете Доктрину, я бы рекомендовал использовать ее для создания ваших сущностей и геттеров/сеттеров для вас, так как это создаст разумные имена, которые совпадают с соглашениями Symfony. Например, ваш объект будет иметь имя «Ресурс» и «Ресурсы», а ваши переменные будут camelCased ($ createdBy vs. $ created_by).

+0

Я пробовал это, но когда я сохраняю данные, это поле отсутствует. Я попробую еще раз, поскольку переименовал несколько вещей. Но когда запрос отправляется, это поле столбца просто пустое. – TuxMeister

+0

Просто любопытно, в каком поле отсутствовало? был ли «created_by» не установлен в таблице? –

+0

Сначала я переименовал поле, чтобы было легче связать в моем мозгу. И проблема была в том, что я передавал строку (идентификатор пользователя) вместо объекта пользователя. Сейчас работает как шарм. – TuxMeister

1

ОК, поэтому, основываясь на предложении Джейсона, а предыдущем на sjagr, я переименовал несколько вещей для согласованности и лучшего понимания, и я написал следующее, которое работает правильно!

Спасибо вам за помощь!

public function resourcesAction(Request $request) 
    { 

     $breadcrumbs = $this->get("white_october_breadcrumbs"); 
     $breadcrumbs->addItem("SFI Portalen", $this->get("router")->generate("sfi_static_index")); 
     $breadcrumbs->addItem("Teacher Dashboard", $this->get("router")->generate("sfi_teacher_dashboard")); 
     $breadcrumbs->addItem("Resources"); 

     $em = $this->getDoctrine()->getManager(); 

     $resource = new Resource(); 

     $createdBy = $em->getRepository('SFIUserBundle:User')->find($this->getUser()->getId()); 

     $newResourceForm = $this->createForm(new ResourceType(), $resource); 
     $newResourceForm->handleRequest($request); 

     if ($newResourceForm->isValid()) { 

     //Getting current date and time 
     $created_time = new \DateTime('now'); 
     $resource->setCreatedTime($created_time); 

     $resource->setCreatedBy($createdBy); 

     $session = $this->getRequest()->getSession(); 
     $session->getFlashBag()->add('notice', 'Form processed'); 

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

     return $this->redirect($this->generateUrl('sfi_teacher_resources')); 
     } 

     return $this->render('SFIMainBundle:Teacher:resources.html.twig', array(
     'form' => $newResourceForm->createView(), 
    )); 
    } 

Все, что мне было нужно, чтобы передать весь объект текущего пользователя в setCreatedBy и связь работает правильно.

Спасибо всем снова!

+0

Привет @TuxMeister, вы пытались просто сделать '$ createdBy = $ this-> getUser();' вместо того, чтобы извлекать весь объект из Doctrine? Кроме того, вы можете взглянуть на [обратные вызовы жизненного цикла] (http://symfony.com/doc/current/book/doctrine.html#lifecycle-callbacks) для обработки настроек createdTime до сих пор –

+0

Да, я попытался это сделать, Джейсон, и ему не понравилось, что эта переменная заканчивается просто строкой. Что касается даты, я действительно полагаю, что я полностью откажусь от этой колонки, поскольку я не вижу ее использования. – TuxMeister

Смежные вопросы