У меня есть класс Message и вы хотите расширить класс Ticket, который будет представлять собой класс билетов на поддержку, поэтому у них может быть, например, другое поле, называемое "статус".
Родительский класс:
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 в приемнике полей и отправителе. Этот класс генерируется просто отлично.
Класс child, который я хочу расширить из класса 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, а в схеме: update я получаю
Compile Error: Access level to SupportMessageBundle\Entity\Ticket::$id must
be protected (as in class PrivateMessageBundle\Entity\Message) or weaker
Поэтому я изменяю все поля на protected и генерирует мои таблицы в базе данных, но без идентификатора отправителя и получателя. Любые идеи, как я могу заставить это сделать это тоже? Или почему мои поля сделаны частными в первую очередь?
Обратите внимание, что я хочу, чтобы у Ticket все еще были поля Message, я не хочу, чтобы некоторые из моих сообщений были билетами.
Это всегда зависит от того, что вы хотите спроектировать. Прежде всего, скажем, что генератор не работает для вашего предложения, поэтому я рекомендую, а не использовать его в этом случае.
Что-то я изменил:
Правильное определение класса, если вы хотите использовать наследование:
<?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));
Один для объекта сообщения со всеми полями, определенными для сообщения, и таблицей для билета только с идентификатором и идентификатором (который всегда будет совпадать с соответствующим идентификатором в таблице сообщений) и дополнительным статусом поля.
Это также возможно с использованием признаков: Сущность сообщения:
<?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;
}
}
Обратите внимание на отсутствие каких-либо утверждений о применении ORM в признаке.
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();
, вы также получите объекты Билета, потому что созданный запрос выглядит так:
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();
вы найдете 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')
$messageRepo->findAll()
также возвращает сущности $messageRepo->findAll()
. Но $ticketRepo->findAll()
просто вернет билеты. Вы можете легко проверить это, если создадите неуклюжий crontroller.
Что-то подобное сделает это. Но вы должны следовать комментарию @StuBez и читать https://doctrine-orm.readthedocs.org/en/latest/reference/inheritance-mapping.html
Это СОЕДИНЕННЫЙ пример, который имеет производительность в действии в определенном случае использования.
<?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
}