Symfony2 встроенная форма отношения OneToMany, как сохранить связанные данные

0

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

У меня есть отношение OneToMany между таблицей Resources и моим объектом 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 сущность, чтобы иметь что-то похожее на resources а не на created_by как свойство.
  • 0
    Я изменил это, я согласен, это облегчает жизнь. Я также изменю заголовок, так как в настоящее время нет никакой ошибки в отображении формы, я просто хотел бы знать, что еще мне нужно для создания формы, которая будет сохранять данные с правильными отношениями.
Теги:
forms

2 ответа

2
Лучший ответ

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

  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, я бы рекомендовал использовать его для создания ваших сущностей и getters/seters для вас, так как это создаст разумные имена, совпадающие с соглашениями Symfony. Например, ваш объект будет иметь имя "Ресурс" и "Ресурсы", а ваши переменные будут camelCased ($ createdBy vs. $ created_by).

  • 0
    Я пробовал это, но когда я сохраняю данные, это поле отсутствует. Я попытаюсь снова, поскольку я переименовал несколько вещей. Но когда запрос отправляется, поле этого столбца остается пустым.
  • 0
    Просто любопытно, какое поле пропало? «create_by» не было установлено в таблице?
Показать ещё 1 комментарий
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(); вместо того, чтобы извлечь целую сущность из Доктрины? Кроме того, вы могли бы взглянуть на обратные вызовы жизненного цикла для обработки установки, созданной в настоящее время
  • 0
    Да, я пробовал это, Джейсон, и мне это не понравилось, потому что эта переменная оказалась просто строкой. Что касается даты, я на самом деле верю, что я вообще откажусь от этой колонки, так как не вижу смысла в ней.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню