Doctrine 2.0 / One-To-Many : Many-To-One

2019-03-11 10:31发布

问题:

I try to setup an one-to-many / many-to-one entity association in Doctrine 2.0. Because i need a field "read" in the association-table user_message i've got 3 entities.

User.php

namespace Console\Entity;

use Doctrine\Common\Collections\ArrayCollection;

/**
 * @Entity(repositoryClass="Console\Repository\User")
 * @Table(name="user")
 */
class User {

    /**
     * @Id 
     * @GeneratedValue 
     * @Column(type="integer")
     */
    protected $id;

    /**
     * @OneToMany(targetEntity="Message", mappedBy="users", cascade={"all"}, orphanRemoval=true)
     * @JoinTable(name="user_message",
     *      joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},
     *      inverseJoinColumns={@JoinColumn(name="message_id", referencedColumnName="id", unique=true)}
     * )
     */
    protected $messages;

    public function __construct(){
        $this->messages = new ArrayCollection();
    }

    public function addMessage(Message $message){
        $message->addUser($this);
        $this->messages[] = $message;
    }

}

Message.php

namespace Console\Entity;

use Doctrine\Common\Collections\ArrayCollection;

/**
 * @Entity(repositoryClass="Console\Repository\Message")
 * @Table(name="message")
 */
class Message {

    /**
     * @Id 
     * @GeneratedValue 
     * @Column(type="integer")
     */
    protected $id;

    /**
     * @Column(type="text")
     */
    protected $value;

    /**
     * @OneToMany(targetEntity="User", mappedBy="messages", cascade={"all"}, orphanRemoval=true)
     * @JoinTable(name="user_message",
     *      joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},
     *      inverseJoinColumns={@JoinColumn(name="message_id", referencedColumnName="id", unique=true)}
     * )
     */
    protected $users;

    public function __construct(){
        $this->users = new ArrayCollection();
    }

    /**
     * @param Console\Entity\User $user 
     */
    public function addUser(User $user){
        $this->users[] = $user;
    }

}

UserMessage.php

namespace Console\Entity;

/**
 * @Entity
 * @Table(name="user_message")
 */
class UserMessage {

    /**
     * @Id 
     * @GeneratedValue 
     * @Column(type="integer")
     */
    protected $id;

    /**
     * @Column(name="user_id", type="integer")
     */
    protected $userId;

    /**
     * @Column(name="message_id", type="integer")
     */
    protected $messageId;

    /**
     * @Column(name="is_read", type="boolean")
     */
    protected $isRead;

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

    public function setIsRead($flag = true){
        $this->isRead = (bool)$flag;
    }

}

dump.sql (generated from doctrine)

CREATE TABLE IF NOT EXISTS `message` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `type_id` int(11) DEFAULT NULL,
  `value` longtext NOT NULL,
  `created` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `IDX_B6BD307FC54C8C93` (`type_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;

CREATE TABLE IF NOT EXISTS `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `ip_id` int(11) DEFAULT NULL,
  `username` varchar(50) NOT NULL,
  `password` varchar(64) NOT NULL,
  `created` datetime NOT NULL,
  `last_action` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `UNIQ_8D93D649F85E0677` (`username`),
  UNIQUE KEY `UNIQ_8D93D649A03F5E9F` (`ip_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;

CREATE TABLE IF NOT EXISTS `user_message` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `message_id` int(11) NOT NULL,
  `is_read` tinyint(1) NOT NULL,
  `created` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;


ALTER TABLE `message`
  ADD CONSTRAINT `message_ibfk_1` FOREIGN KEY (`type_id`) REFERENCES `message_type` (`id`);

ALTER TABLE `user`
  ADD CONSTRAINT `user_ibfk_1` FOREIGN KEY (`ip_id`) REFERENCES `ip` (`id`);

And now my test:

$user = $em->find('Console\Entity\User', 1);

$message = new Console\Entity\Message();
$message->setValue('TestNachricht');

$user->addMessage($message);

$em->persist($user);
$em->flush();

What's happen: message table is filled in, user_message is empty. What can I do to use the user_message table and what I have to do, to set en message as "read"?

Thanks for help

回答1:

I've got it:

Message.php

namespace Console\Entity;

use Doctrine\Common\Collections\ArrayCollection;

/**
 * @Entity(repositoryClass="Console\Repository\Message")
 * @Table(name="message")
 * @HasLifecycleCallbacks
 */
class Message {

    /**
     * @Id 
     * @GeneratedValue 
     * @Column(type="integer")
     */
    protected $id;

    /**
     * @Column(type="text")
     */
    protected $value;

    /**
     * @ManyToOne(targetEntity="Console\Entity\MessageType", cascade={"persist"})
     */
    protected $type;

    /**
     * @OneToMany(targetEntity="Console\Entity\UserMessage", mappedBy="message", cascade={"all"}, orphanRemoval=true)
     */
    protected $userMessages;

    /**
     * @Column(type="datetime")
     */
    protected $created;

    /**
     * @param Console\Entity\MessageType $type
     * @param string $value
     */
    public function __construct(MessageType $type, $value){
        $this->type         = $type;
        $this->value        = $value;
        $this->userMessages = new ArrayCollection();
    }

    /** @PrePersist */
    public function prePersist(){
        $this->created = new \DateTime("now");
    }

    /**
     * @return int 
     */
    public function getId(){
        return $this->id;
    }

    /**
     * @return string 
     */
    public function getValue(){
        return $this->value;
    }

    /**
     * @return Console\Entity\MessageType 
     */
    public function getType(){
        return $this->type;
    }

}

User.php

namespace Console\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Console\Resource\Resource;

/**
 * @Entity(repositoryClass="Console\Repository\User")
 * @Table(name="user")
 * @HasLifecycleCallbacks
 */
class User implements Resource {

    /**
     * @Id 
     * @GeneratedValue 
     * @Column(type="integer")
     */
    protected $id;

    /**
     * @Column(type="string", length=50, unique=true)
     */
    protected $username;

    /**
     * @Column(type="string", length=64)
     */
    protected $password;

    /**
     * @OneToOne(targetEntity="Console\Entity\Ip", cascade={"all"}, orphanRemoval=true)
     */
    protected $ip = null;

    /**
     * @OneToMany(targetEntity="Console\Entity\UserMessage", mappedBy="sender", cascade={"all"}, orphanRemoval=true)
     */
    protected $sentMessages;

    /**
     * @OneToMany(targetEntity="Console\Entity\UserMessage", mappedBy="receiver", cascade={"all"}, orphanRemoval=true)
     */
    protected $receivedMessages;

    /**
     * @Column(type="datetime")
     */
    protected $created;

    /**
     * @Column(type="datetime", name="last_action", nullable=true)
     */
    protected $lastAction;

    public function __construct($username, $password){
        $this->username         = $username;
        $this->password         = hash_hmac(self::PASSWORD_ALGO, $password, self::PASSWORD_SALT);
        $this->sentMessages     = new ArrayCollection();
        $this->receivedMessages = new ArrayCollection();
    }

    /** @PreUpdate */
    public function preUpdate(){
        $this->lastAction = new \DateTime("now");
    }

    /** @PrePersist */
    public function prePersist(){
        $this->created = new \DateTime("now");
    }

    /**
     * @return int 
     */
    public function getId(){
        return $this->id;
    }

    /**
     * @return string 
     */
    public function getUsername(){
        return $this->username;
    }

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

    /**
     * @return Console\Entity\Ip 
     */
    public function getIp(){
        return $this->ip;
    }

    /**
     * @return Doctrine\Common\Collections\ArrayCollection 
     */
    public function getReceivedMessages(){
        return $this->receivedMessages;
    }

    /**
     * @return \DateTime 
     */
    public function getCreated(){
        return $this->created;
    }

    /**
     * @return \DateTime 
     */
    public function getLastAction(){
        return $this->lastAction;
    }

    /**
     * @param Console\Entity\User $receiver
     * @param Message $message
     * @param type $isRead 
     */
    public function sendMessage(User $receiver, Message $message, $isRead = false){
        $this->sentMessages[] = new UserMessage($this, $receiver, $message, $isRead);
    }

    /**
     * @param \DateTime $dateTime 
     */
    public function setLastAction(\DateTime $dateTime = null){
        $this->lastAction = ($dateTime) ? $dateTime : new \DateTime("now");
    }

    public function setIp(Ip $ip){
        $this->ip = $ip;
    }

    public function removeIp(){
        $this->ip = null;
    }

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

}

MessageUser.php

namespace Console\Entity;

/**
 * @Entity(repositoryClass="Console\Repository\UserMessage")
 * @Table(name="user_message")
 * @HasLifecycleCallbacks
 */
class UserMessage {

    /**
     * @Id 
     * @GeneratedValue 
     * @Column(type="integer")
     */
    protected $id;

    /**
     * @ManyToOne(targetEntity="Console\Entity\User", cascade={"all"})
     */
    protected $sender;

    /**
     * @ManyToOne(targetEntity="Console\Entity\User", cascade={"all"})
     */
    protected $receiver;

    /**
     * @ManyToOne(targetEntity="Console\Entity\Message", cascade={"all"})
     */
    protected $message;

    /**
     * @Column(name="is_read", type="boolean")
     */
    protected $isRead = false;

    /**
     * @Column(name="read_at", type="datetime", nullable=true)
     */
    protected $readAt = null;

    /**
     * @Column(type="datetime")
     */
    protected $created;

    public function __construct(User $sender, User $receiver, Message $message, $isRead = false){
        $this->sender   = $sender;
        $this->receiver = $receiver;
        $this->message  = $message;
        if($isRead)
            $this->setIsRead();
    }

    /** @PrePersist */
    public function prePersist(){
        $this->created = new \DateTime("now");
    }

    /**
     * @return int 
     */
    public function getId(){
        return $this->id;
    }

    /**
     * @return Console\Entity\User 
     */
    public function getSender(){
        return $this->sender;
    }

    /**
     * @return Console\Entity\User 
     */
    public function getReceiver(){
        return $this->receiver;
    }

    /**
     * @return Console\Entity\Message 
     */
    public function getMessage(){
        return $this->message;
    }

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

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

    public function setIsRead(){
        $this->isRead = true;
        $this->readAt = new \DateTime("now");
    }

    public function setUnread(){
        $this->isRead = false;
        $this->readAt = null;
    }

}