Symfony2嵌入形式OneToMany关系,如何持久保存相关数据

时间:2014-12-08 16:24:55

标签: php forms symfony

我几天都在努力解决这个问题,所以我希望有人可以提供帮助。

我在表资源和我的FOSUserBundle提供的User实体之间有一个OneToMany关系,这样一个用户可以发布很多资源。

注意:为简洁起见,实体已经过编辑,但我不相信我删除了对此问题重要的内容

我的资源实体:

<?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(),
      ));
  }

我需要做的是在创建新资源时将这些实体联系起来,然后分配&#34;它通过表格中的关系登录用户。

我已经查看了有关Symfony文档的嵌入式表单和其他建议,但我无法理解如何将我读到的内容应用于此特定示例。我已经按照示例了解了任务,标签和类别以及所有这些,但我无法理解它如何适用于我的情况,将User实体放在另一个包中,以及一个与用户相关的用户表单类型到他们的学校,只需添加一个额外的全名字段,同时继承FOSUserBundle的原始表格类型。

我也有一种有趣的感觉,我无法解决或排除&#34;我的代码中的关系正确,以便更容易理解哪些对象相关。

任何帮助将不胜感激!如果您需要其他代码或更多信息,请告知我们。

2 个答案:

答案 0 :(得分:2)

您应该能够在持久化Resources实体之前手动设置用户。

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

Symfony使用控制器中的 $ this-&gt; getUser()快捷方式(参见http://symfony.com/doc/current/book/security.html#retrieving-the-user-object)。我假设您在用户登录时只允许使用此表单。

此外,如果您使用的是Doctrine,我建议您使用它来为您生成实体和getter / setter,因为它会生成符合Symfony约定的合理名称。例如,您的实体最终会被命名为“资源”和“资源”。 vs.&#39;资源&#39;,你的变量将是camelCased($ createdBy vs. $ created_by)。

答案 1 :(得分:1)

好的,基于Jason的建议,以及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 中传递当前用户的整个对象,并且关系正常。

再次感谢大家!