Я боролся с этим в течение нескольких дней, поэтому я надеюсь, что кто-то может помочь.
У меня есть отношение 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.
У меня также есть смешное чувство, что я не занимался или "правильно формулировал" отношения в моем коде, чтобы было легче понять, какие объекты связаны.
Любая помощь приветствуется! Также, пожалуйста, дайте мне знать, если вам нужен другой код или дополнительная информация.
Вы должны просто настроить пользователя вручную, прежде чем продолжать работу с ресурсом.
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).
Хорошо, поэтому, основываясь на предложении Джейсона, а предыдущем - на 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, и отношение работает правильно.
Еще раз спасибо!
$createdBy = $this->getUser();
вместо того, чтобы извлечь целую сущность из Доктрины? Кроме того, вы могли бы взглянуть на обратные вызовы жизненного цикла для обработки установки, созданной в настоящее время
User
сущность, чтобы иметь что-то похожее наresources
а не наcreated_by
как свойство.