Symfony3 - 如何在多对一关系 属性 中添加默认值或保留默认值

Symfony3 - How to add default values or persist default values in a property that is a Many-to-One relation property

我有 2 个通过多对一关系关联的实体。 当我是用户输入的 persisting/storing 值时,在实际坚持之前,我有一个用户没有 populate/provide 输入的属性,我想通过代码设置它。

所以,我有登录实体:

<?php

namespace Vendor\MyBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * Logins
 *
 * @ORM\Table(name="logins", indexes={@ORM\Index(name="RoleID", columns={"RoleID"})})
 * @ORM\Entity(repositoryClass="Vendor\MyBundle\Repository\LoginsRepository")
 * @UniqueEntity(fields="email", message="Email already taken")
 * @ORM\HasLifecycleCallbacks
 */
class Logins implements UserInterface, \Serializable
{
    /**
     * @var string
     *
     * @ORM\Column(name="FirstName", type="string", length=255, nullable=false)
     */
    private $firstname;

    /**
     * @var string
     *
     * @ORM\Column(name="LastName", type="string", length=255, nullable=false)
     */
    private $lastname;

    /**
     * @var string
     *
     * @ORM\Column(name="Email", type="string", length=255, nullable=false)
     */
    private $email;

    /**
     * @var string
     *
     * @ORM\Column(name="Password", type="string", length=255, nullable=false)
     */
    private $password;

    /**
     * @var string
     *
     * @ORM\Column(name="City", type="string", length=255, nullable=false)
     */
    private $city;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="CreationTime", type="datetime", nullable=false)
     */
    private $creationtime;

    /**
     * @var integer
     *
     * @ORM\Column(name="loginID", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $loginid;

    public function __toString() {
        return (string)$this->loginid;
    }

    /**
     * @var \Vendor\MyBundle\Entity\Roles
     *
     * @ORM\ManyToOne(targetEntity="Vendor\MyBundle\Entity\Roles", cascade={"persist"})
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="RoleID", referencedColumnName="roleID")
     * })
     */
    private $roleid;

    /**
     * Set firstname
     *
     * @param string $firstname
     *
     * @return Logins
     */
    public function setFirstname($firstname)
    {
        $this->firstname = $firstname;

        return $this;
    }

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

    /**
     * Set lastname
     *
     * @param string $lastname
     *
     * @return Logins
     */
    public function setLastname($lastname)
    {
        $this->lastname = $lastname;

        return $this;
    }

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

    /**
     * Set email
     *
     * @param string $email
     *
     * @return Logins
     */
    public function setEmail($email)
    {
        $this->email = $email;

        return $this;
    }

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

    /**
     * Set password
     *
     * @param string $password
     *
     * @return Logins
     */
    public function setPassword($password)
    {
        $this->password = $password;

        return $this;
    }

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

    /**
     * Set city
     *
     * @param string $city
     *
     * @return Logins
     */
    public function setCity($city)
    {
        $this->city = $city;

        return $this;
    }

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

    /**
     * Set creationtime
     *
     * @param \DateTime $creationtime
     * @ORM\PrePersist
     * 
     * @return Logins
     */
    public function setCreationtime()
    {
        $this->creationtime = new \DateTime('now');

        return $this;
    }

    /**
     * Get creationtime
     *
     * @return \DateTime
     */
    public function getCreationtime()
    {
        return $this->creationtime;
    }

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


    /**
     * Set roleid
     *
     * @param \Vendor\MyBundle\Entity\Roles $roleid
     * 
     * @return Logins
     */
    public function setRoleid(\Vendor\MyBundle\Entity\Roles $roleid = null)
    {
        $this->roleid = $roleid;

        return $this;
    }

    /**
     * Get roleid
     *
     * @return \Vendor\MyBundle\Entity\Roles
     */
    public function getRoleid()
    {
        return $this->roleid;
    }

    public function eraseCredentials() {

    }

    public function getRoles() {

        if ($this->roleid == '1'){
            return array('ROLE_ADMIN');
        }
        elseif ($this->roleid == '2'){
            return array('ROLE_USER');
        }
    }

    public function getSalt() {
        return null;
    }

    public function getUsername() {
        return $this->email;
    }

    /** @see \Serializable::serialize() */
    public function serialize() {
        return serialize(array(
            $this->loginid,
            $this->email,
            $this->password,
        ));
    }

    /** @see \Serializable::unserialize() */
    public function unserialize($serialized) {
        list(
        $this->loginid,
        $this->email,
        $this->password,) = unserialize($serialized);
    }

}

然后是角色实体:

<?php

namespace Vendor\MyBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Roles
 *
 * @ORM\Table(name="roles")
 * @ORM\Entity(repositoryClass="Vendor\MyBundle\Repository\RolesRepository")
 */
class Roles
{
    /**
     * @var string
     *
     * @ORM\Column(name="RoleName", type="string", length=255, nullable=false)
     */
    private $rolename;

    /**
     * @var boolean
     *
     * @ORM\Column(name="WishList", type="boolean", nullable=false)
     */
    private $wishlist;

    /**
     * @var boolean
     *
     * @ORM\Column(name="Events", type="boolean", nullable=false)
     */
    private $events;

    /**
     * @var boolean
     *
     * @ORM\Column(name="Reports", type="boolean", nullable=false)
     */
    private $reports;

    /**
     * @var integer
     *
     * @ORM\Column(name="roleID", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $roleid;

    public function __toString() {
        return (string)$this->getRoleid();
    }

    /**
     * Set rolename
     *
     * @param string $rolename
     *
     * @return Roles
     */
    public function setRolename($rolename)
    {
        $this->rolename = $rolename;

        return $this;
    }

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

    /**
     * Set wishlist
     *
     * @param boolean $wishlist
     *
     * @return Roles
     */
    public function setWishlist($wishlist)
    {
        $this->wishlist = $wishlist;

        return $this;
    }

    /**
     * Get wishlist
     *
     * @return boolean
     */
    public function getWishlist()
    {
        return $this->wishlist;
    }

    /**
     * Set events
     *
     * @param boolean $events
     *
     * @return Roles
     */
    public function setEvents($events)
    {
        $this->events = $events;

        return $this;
    }

    /**
     * Get events
     *
     * @return boolean
     */
    public function getEvents()
    {
        return $this->events;
    }

    /**
     * Set reports
     *
     * @param boolean $reports
     *
     * @return Roles
     */
    public function setReports($reports)
    {
        $this->reports = $reports;

        return $this;
    }

    /**
     * Get reports
     *
     * @return boolean
     */
    public function getReports()
    {
        return $this->reports;
    }

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

这个通过注册表单处理用户输入的控制器:

<?php

namespace Vendor\MyBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use Vendor\MyBundle\Entity\Logins;
use Vendor\MyBundle\Form\UserType;
use Vendor\MyBundle\Repository\LoginsRepository;

class MainController extends Controller
{

    /**
     * @Route("/", name="home_page")
     */
    public function indexAction(Request $request)
    {
        // 1) build the form
        $user = new Logins();
        $form = $this->createForm(UserType::class, $user);

        // 2) handle the submit (will only happen on POST)
        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
            // 3) Encode the password
            $password = $this->get('security.password_encoder')
                ->encodePassword($user, $user->getPassword());
            $user->setPassword($password);
            $user->setCreationtime();
            // 4) save the User!
            $em = $this->getDoctrine()->getManager();
            $roleid = $this->$em->getRepository('Vendor\MyBundle\Entity\Roles')->find(2); // or getReference
            $user->setRoleid($roleid);
            $em->persist($user);
            $em->flush();
            return $this->redirectToRoute('home_page');
        }

        return $this->render(
            'VendorMyBundle:Default:index.html.twig',
            array('form' => $form->createView())
        );
    }

简而言之,我的数据库中的角色 table 中有 2 条记录,具有主键 RoleID。 我希望当用户注册时,当我坚持并将数据刷新到数据库时,我在登录 Table 中的 RoleID 列 (FK) 默认填充值 2。

任何见解或替代方案都将受到赞赏。我在 Symfony 3.0.1 上。

我可以想到 2 种可能的解决方案来自动执行此操作。两者都使用 doctrine pre-persist event.

通过添加带有@ORM\PrePersist注解的回调方法为实体添加pre-persist方法,并通过添加@ORM\HasLifecycleCallbacks注解标记实体具有生命周期回调(read also here for more details on how to do this).
Here you can find Symfony specific documentation on the life cycle callback

/**
 * @ORM\PrePersist
 * @param \Doctrine\ORM\Event\LifecycleEventArgs $args
 */
public function prePersist(LifecycleEventArgs $args)
{
    $entity= $args->getEntity();
    if($entity->getRoleid() === null){
        $entityManager = $args->getEntityManager();
        $roleId = $entityManager->getReference(\Vendor\MyBundle\Entity\Roles::class, 2);
        $entity->setRoleId($roleId);
    }
}

注意:您也可以使用方法find代替getReference,但使用getReference会节省您额外的往返时间到数据库。你说你有两个角色,如果你知道它们总是存在(固定装置),那么就没有必要解决它们。


但您也可以在外部侦听器(称为事件订阅者)中执行相同的操作。 Check here the Doctrine 2 documentation on this topic
Here you can find Symfony specific documentation on the event subscriber

namespace Vendor\MyBundle\Listener;

use Doctrine\ORM\Events;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use Doctrine\Common\EventSubscriber;

class DefaultRoleListener implements EventSubscriber
{
    /**
     * @return array
     */
    public function getSubscribedEvents()
    {
        return array(
            Events::prePersist,
        );
    }

    /**
     * @param LifecycleEventArgs $args
     */
    public function prePersist(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();

        if( $entity instanceof Login) {
            if($entity->getRoleid() === null){
                $entityManager = $args->getEntityManager();
                $roleId = $entityManager->getReference(\Vendor\MyBundle\Entity\Roles::class, 2);
                $entity->setRoleId($roleId);
            }
        }            
    }
}

您需要附加您的侦听器(事件订阅者)。

$entityManager = // get your entity manager instance 
$doctrineEventManager = $entityManager->getEventManager();

$defaultRoleListener = // get your listener instance 
$doctrineEventManager->addEventSubscriber($defaultRoleListener);

但也许有一种 Symfony 方法可以做到这一点...我主要使用 Zend Framework。

两种解决方案的作用完全相同。这完全取决于您个人对逻辑存储位置的偏好;在您的实体中或在单独的侦听器中。

更新

如果你有问题让它工作,请确保你首先删除 \Vendor\MyBundle\Resources\config\ 中任何现有的 YML/XML 文件,因为这些可能导致 Doctrine 忽略你的 prePersist 方法。

我忘记了什么。对于第一个解决方案,您还需要标记该实体具有生命周期回调。您可以通过添加注释 @HasLifecycleCallbacks 来完成此操作。并检查您是否在该方法上添加了 @PrePersist。根据您的设置,您有时需要使用 @ORM\HasLifecycleCallbacks@ORM\PrePersist。你应该喜欢你的其他 @Entity 注释。

不确定为什么您收到评论中提到的错误消息。但是你可以反其道而行之,将我在回答中写的行换成你的控制器代码中的行,如果它们对你有用...