我有一个Message类,并且希望扩展一个Ticket类,它将成为某种支持票据类,因此它们可能有另一个名为'status'的字段。
父类:
namespace PrivateMessageBundle'Entity;
use Doctrine'ORM'Mapping as ORM;
use MedApp'CrudBundle'Entity'User;
/**
* Message
*
* @ORM'Table()
* @ORM'Entity
*/
class Message
{
/**
* @var integer
*
* @ORM'Column(name="id", type="integer")
* @ORM'Id
* @ORM'GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @var string
*
* @ORM'Column(name="title", type="string", length=50)
*/
protected $title;
/**
* @ORM'ManyToOne(targetEntity="MedApp'CrudBundle'Entity'User")
* @ORM'JoinColumn(referencedColumnName="id")
*/
protected $receiver;
/**
* @ORM'ManyToOne(targetEntity="MedApp'CrudBundle'Entity'User")
* @ORM'JoinColumn(referencedColumnName="id")
*/
protected $sender;
/**
* @var string
*
* @ORM'Column(name="content", type="string", length=2000)
*/
protected $content;
/**
* @var 'DateTime
*
* @ORM'Column(name="date", type="datetime")
*/
protected $date;
/**
* @var boolean
*
* @ORM'Column(name="is_spam", type="boolean")
*/
protected $is_spam=false;
/**
* @var 'DateTime
*
* @ORM'Column(name="seen_at", type="datetime",nullable=true)
*/
protected $seen_at=null;
//autogenerated functions here
}
可以看到,它与我的User类在字段receiver和sender上有多对一的关系。这个类生成得很好。
我想从Message类扩展的子类:
namespace SupportMessageBundle'Entity;
use Doctrine'ORM'Mapping as ORM;
use PrivateMessageBundle'Entity'Message;
/**
* Ticket
*
* @ORM'Table()
* @ORM'Entity
*/
class Ticket extends Message
{
/**
* @var integer
*/
private $id;
/**
* @var string
*/
private $title;
/**
* @var string
*/
private $content;
/**
* @var 'DateTime
*/
private $date;
/**
* @var boolean
*/
private $is_spam;
/**
* @var 'DateTime
*/
private $seen_at;
/**
* @var 'MedApp'CrudBundle'Entity'User
*/
private $receiver;
/**
* @var 'MedApp'CrudBundle'Entity'User
*/
private $sender;
//auto generated functions
}
这个类有几个问题。它是空的,但是我用doctrine:generate:entities SupportMessageBundle生成了字段和函数。
首先,它生成字段private,在schema:update我得到
Compile Error: Access level to SupportMessageBundle'Entity'Ticket::$id must
be protected (as in class PrivateMessageBundle'Entity'Message) or weaker
因此我将所有字段更改为protected,它在数据库中生成我的表,但没有发送方和接收方id。有什么办法能让它也这么做吗?或者为什么我的田地一开始就被设为私有?
注意,我希望Ticket仍然有Message的字段,我不希望我的一些消息是Tickets
这总是取决于你想要设计什么。首先,让我们说,生成器不能为您的提议工作,所以我建议,不要在这种情况下使用它。
Something I changed:
- 我使用两个bundle PrivateMessageBundle和PrivateTicketBundle都在命名空间Acme
- 我将属性$is_spam和$seen_at更改为$isSeen和$seenAt,因为symfony代码风格
<?php
namespace Acme'PrivateMessageBundle'Entity;
use Doctrine'ORM'Mapping as ORM;
use AppBundle'Entity'User;
/**
* Message
*
* @ORM'Table(name="message")
* @ORM'Entity()
* @ORM'InheritanceType("JOINED")
* @ORM'DiscriminatorColumn(name="discr", type="string")
* @ORM'DiscriminatorMap({"message"="Message", "ticket" = "Acme'PrivateTicketBundle'Entity'Ticket"})
*
*/
class Message
{
/**
* @var integer
*
* @ORM'Column(name="id", type="integer")
* @ORM'Id
* @ORM'GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @var string
*
* @ORM'Column(name="title", type="string", length=50)
*/
protected $title;
/**
* @ORM'ManyToOne(targetEntity="AppBundle'Entity'User")
* @ORM'JoinColumn(referencedColumnName="id")
*/
protected $receiver;
/**
* @ORM'ManyToOne(targetEntity="AppBundle'Entity'User")
* @ORM'JoinColumn(referencedColumnName="id")
*/
protected $sender;
/**
* @var string
*
* @ORM'Column(name="content", type="string", length=2000)
*/
protected $content;
/**
* @var 'DateTime
*
* @ORM'Column(name="date", type="datetime")
*/
protected $date;
/**
* @var boolean
*
* @ORM'Column(name="is_spam", type="boolean")
*/
protected $isSpam = false;
/**
* @var 'DateTime
*
* @ORM'Column(name="seen_at", type="datetime",nullable=true)
*/
protected $seenAt = null;
// [...] skip constructor, getter, setter and other methods
}
Ticket类是这样的
<?php
namespace Acme'PrivateTicketBundle'Entity;
use Acme'PrivateMessageBundle'Entity'Message;
use Doctrine'ORM'Mapping as ORM;
/**
* Ticket extending Message
*
* @ORM'Table(name="ticket")
* @ORM'Entity()
*/
class Ticket extends Message
{
/**
* @var string
* @ORM'Column(name="status", type="string")
*/
protected $status;
/**
* Set status
*
* @param string $status
* @return Ticket
*/
public function setStatus($status)
{
$this->status = $status;
return $this;
}
/**
* Get status
*
* @return string
*/
public function getStatus()
{
return $this->status;
}
}
将生成以下表:
CREATE TABLE message (id INTEGER NOT NULL, receiver_id INTEGER DEFAULT NULL, sender_id INTEGER DEFAULT NULL, title VARCHAR(50) NOT NULL, content VARCHAR(2000) NOT NULL, date DATETIME NOT NULL, is_spam BOOLEAN NOT NULL, seen_at DATETIME DEFAULT NULL, discr VARCHAR(255) NOT NULL, PRIMARY KEY(id));
CREATE TABLE ticket (id INTEGER NOT NULL, status VARCHAR(255) NOT NULL, PRIMARY KEY(id));
一个用于包含为消息定义的所有字段的消息实体,一个用于仅包含和id的ticket表(它将始终与消息表中相应的id相同)和额外的字段状态。
具有相同列的两个表
这也可以使用traits:信息实体:
<?php
namespace Acme'PrivateMessageBundle'Entity;
use Doctrine'ORM'Mapping as ORM;
/**
* Message
*
* @ORM'Table(name="message")
* @ORM'Entity()
*/
class Message
{
// Use the MessageTraid
use MessageTrait;
}
(你必须保留use Doctrine'ORM'Mapping as ORM;
!)
票务实体:
<?php
namespace Acme'PrivateTicketBundle'Entity;
use Acme'PrivateMessageBundle'Entity'MessageTrait;
use Doctrine'ORM'Mapping as ORM;
/**
* Ticket extending Message
*
* @ORM'Table(name="ticket")
* @ORM'Entity()
*/
class Ticket
{
// Use the MessageTraid
use MessageTrait;
/**
* @var string
* @ORM'Column(name="status", type="string")
*/
protected $status;
/**
* Set status
*
* @param string $status
* @return Ticket
*/
public function setStatus($status)
{
$this->status = $status;
return $this;
}
/**
* Get status
*
* @return string
*/
public function getStatus()
{
return $this->status;
}
}
这是性状:
<?php
namespace Acme'PrivateMessageBundle'Entity;
trait MessageTrait
{
/**
* @var integer
*
* @ORM'Column(name="id", type="integer")
* @ORM'Id
* @ORM'GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @var string
*
* @ORM'Column(name="title", type="string", length=50)
*/
protected $title;
/**
* @ORM'ManyToOne(targetEntity="AppBundle'Entity'User")
* @ORM'JoinColumn(referencedColumnName="id")
*/
protected $receiver;
/**
* @ORM'ManyToOne(targetEntity="AppBundle'Entity'User")
* @ORM'JoinColumn(referencedColumnName="id")
*/
protected $sender;
/**
* @var string
*
* @ORM'Column(name="content", type="string", length=2000)
*/
protected $content;
/**
* @var 'DateTime
*
* @ORM'Column(name="date", type="datetime")
*/
protected $date;
/**
* @var boolean
*
* @ORM'Column(name="is_spam", type="boolean")
*/
protected $isSpam = false;
/**
* @var 'DateTime
*
* @ORM'Column(name="seen_at", type="datetime",nullable=true)
*/
protected $seenAt = null;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set title
*
* @param string $title
* @return Message
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set content
*
* @param string $content
* @return Message
*/
public function setContent($content)
{
$this->content = $content;
return $this;
}
/**
* Get content
*
* @return string
*/
public function getContent()
{
return $this->content;
}
/**
* Set date
*
* @param 'DateTime $date
* @return Message
*/
public function setDate($date)
{
$this->date = $date;
return $this;
}
/**
* Get date
*
* @return 'DateTime
*/
public function getDate()
{
return $this->date;
}
/**
* Set isSpam
*
* @param boolean $isSpam
* @return Message
*/
public function setIsSpam($isSpam)
{
$this->isSpam = $isSpam;
return $this;
}
/**
* Get isSpam
*
* @return boolean
*/
public function getIsSpam()
{
return $this->isSpam;
}
/**
* Set seenAt
*
* @param 'DateTime $seenAt
* @return Message
*/
public function setSeenAt($seenAt)
{
$this->seenAt = $seenAt;
return $this;
}
/**
* Get seenAt
*
* @return 'DateTime
*/
public function getSeenAt()
{
return $this->seenAt;
}
/**
* Set receiver
*
* @param 'AppBundle'Entity'User $receiver
* @return Message
*/
public function setReceiver('AppBundle'Entity'User $receiver = null)
{
$this->receiver = $receiver;
return $this;
}
/**
* Get receiver
*
* @return 'AppBundle'Entity'User
*/
public function getReceiver()
{
return $this->receiver;
}
/**
* Set sender
*
* @param 'AppBundle'Entity'User $sender
* @return Message
*/
public function setSender('AppBundle'Entity'User $sender = null)
{
$this->sender = $sender;
return $this;
}
/**
* Get sender
*
* @return 'AppBundle'Entity'User
*/
public function getSender()
{
return $this->sender;
}
}
注意trait中没有任何关于ORM的use语句
Doctrine将使用在您的类中定义的ODM名称空间。
将生成两个表:
CREATE TABLE message (id INTEGER NOT NULL, receiver_id INTEGER DEFAULT NULL, sender_id INTEGER DEFAULT NULL, title VARCHAR(50) NOT NULL, content VARCHAR(2000) NOT NULL, date DATETIME NOT NULL, is_spam BOOLEAN NOT NULL, seen_at DATETIME DEFAULT NULL, PRIMARY KEY(id));
CREATE TABLE ticket (id INTEGER NOT NULL, receiver_id INTEGER DEFAULT NULL, sender_id INTEGER DEFAULT NULL, status VARCHAR(255) NOT NULL, title VARCHAR(50) NOT NULL, content VARCHAR(2000) NOT NULL, date DATETIME NOT NULL, is_spam BOOLEAN NOT NULL, seen_at DATETIME DEFAULT NULL, PRIMARY KEY(id));
快乐编码
第一个示例的更新
在本例中,如果使用$em->getRepository('AcmePrivateMessageBundle:Message')->findAll();
搜索消息,还将获得Ticket实体,因为创建的查询如下所示:
SELECT
t0.id AS id2,
t0.title AS title3,
t0.content AS content4,
t0.date AS date5,
t0.is_spam AS is_spam6,
t0.seen_at AS seen_at7,
t0.receiver_id AS receiver_id8,
t0.sender_id AS sender_id9,
t0.discr,
t1.status AS status10
FROM
message t0
LEFT JOIN ticket t1 ON t0.id = t1.id
(注意LEFT JOIN
)
但是如果你用$entities = $em->getRepository('AcmePrivateTicketBundle:Ticket')->findAll();
搜索Tickets,你会发现Ticket只是因为生成的sql看起来有点不同:
SELECT
t1.id AS id2,
t1.title AS title3,
t1.content AS content4,
t1.date AS date5,
t1.is_spam AS is_spam6,
t1.seen_at AS seen_at7,
t0.status AS status8,
t1.receiver_id AS receiver_id9,
t1.sender_id AS sender_id10,
t1.discr
FROM
ticket t0
INNER JOIN message t1 ON t0.id = t1.id
要获取消息,您必须使用查询生成器:
$query = $em->createQuery("SELECT message FROM Acme'PrivateMessageBundle'Entity'Message message WHERE message INSTANCE OF Acme'PrivateMessageBundle'Entity'Message");
$entities = $query->getResult();
这将产生如下查询:
SELECT
m0_.id AS id0,
m0_.title AS title1,
m0_.content AS content2,
m0_.date AS date3,
m0_.is_spam AS is_spam4,
m0_.seen_at AS seen_at5,
t1_.status AS status6,
m0_.discr AS discr7,
m0_.receiver_id AS receiver_id8,
m0_.sender_id AS sender_id9
FROM
message m0_
LEFT JOIN ticket t1_ ON m0_.id = t1_.id
WHERE
m0_.discr IN ('message')
这样就可以了。但是你应该关注@StuBez评论并阅读https://doctrine-orm.readthedocs.org/en/latest/reference/inheritance-mapping.html
这是一个在某些用例中对性能有影响的join示例。
<?php
namespace PrivateMessageBundle'Entity;
use Doctrine'ORM'Mapping as ORM;
/**
* @ORM'Entity
* @ORM'InheritanceType("JOINED")
* @ORM'DiscriminatorColumn(name="discr", type="string")
* @ORM'DiscriminatorMap({"ticket" = "Ticket")
*/
class Message
{
/**
* @var integer
*
* @ORM'Column(name="id", type="integer")
* @ORM'Id
* @ORM'GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @var string
*
* @ORM'Column(name="title", type="string", length=50)
*/
protected $title;
// ...
}
/** @ORM'Entity */
class Ticket extends Message
{
// ... New fields don't repeat parent one
}