Symfony2嵌入了一对多关系,如何持久化相关数据


Symfony2 embedded form OneToMany relationship, how to persist related data

我已经为此苦苦挣扎了几天,所以我希望有人可以提供帮助。

我在表资源和我的 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;
    }
}

我有几种表单类型,但我正在使用的主要表单类型是资源类型:

<?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 的原始表单类型。

我还有一个有趣的感觉,我没有在我的代码中正确处理或"布局"关系,以便更容易理解哪些对象相关。

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

您应该能够在保留资源实体之前手动设置用户。

  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(。 我假设您只在用户登录时允许此表单。

另外,如果您正在使用Doctrine,我建议您使用它来为您生成实体和getter/setter,因为它将生成与Symfony约定一致的合理名称。 例如,您的实体最终将被命名为"资源"与"资源",并且您的变量将被命名为驼峰($createdBy vs. $created_by(。

好的,

所以根据 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 中传递当前用户的整个对象,并且关系可以正常工作。

再次感谢大家!