dongpenggan6812
2016-02-02 20:10 阅读 100
已采纳

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

I have 2 entities that are related via a Many-to-One relation. When I am persisting/storing values on user input, before the actual persist I have one of the properties the user doesn't populate/provide input on, and I want to set it via code.

So, I have Logins entity:

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

}

And then the Roles entity:

<?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;
    }
}

And this controller which handles user input via a register form:

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

In short, I have 2 records in the Roles table in my DB with primary Key RoleID. I want that when a user registers, when I persist and flush the data to the DB I have the RoleID column (FK) in the Logins Table populated with the value 2 by default.

Any insight or alternatives are appreciated. I am on Symfony 3.0.1 .

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

1条回答 默认 最新

  • 已采纳
    doulongdan2264 doulongdan2264 2016-02-03 08:28

    I can think of 2 possible solutions to do this automatically. Both are using a doctrine pre-persist event.

    Add a pre-persist method to the entity by adding an a callback method with a @ORM\PrePersist annotation and mark that the entity has life cycle callbacks by adding an @ORM\HasLifecycleCallbacks annotation (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);
        }
    }
    

    Note: You can also use the method find instead of getReference here, but using getReference will save you an additional roundtrip to the database. You said you have two roles and if you know they are always there (fixtures) there is no need to resolve them.


    But you can also do the same in an external listener (called an event subscriber). 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);
                }
            }            
        }
    }
    

    You will need to attach your listener (event subscriber).

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

    But there is maybe a Symfony way to do this... I am mostly working with Zend Framework.

    Both solution will do exactly the same. It all depends on your personal preference on where to store the logic; in your entity or in a separate listener.

    UPDATE

    If you have issues to get it working please make sure that you first delete any existing YML/XML files in \Vendor\MyBundle\Resources\config\, as those can cause Doctrine to ignore your prePersist methods.

    I forgot something. For the first solution you also need to mark that the entity has life cycle callbacks. You do this by adding the annotation @HasLifecycleCallbacks. And check that you added @PrePersist on the method. Depending on your setup you sometimes need to use @ORM\HasLifecycleCallbacks or @ORM\PrePersist. You should do like with your other @Entity annotations.

    Not sure why you got the error message mentioned in your comment. But you can do the opposite and exchange the lines I wrote in my answer for the ones from your controller code if they work for you...

    点赞 3 评论 复制链接分享

相关推荐