我有一个包含不同类型用户的应用程序。所有类型的用户都共享共同的属性,例如用户名、名字和姓氏。不同类型的用户是:
教师拥有用户的所有属性,还有电子邮件和电话号码。儿童和监护人同上,但这两个实体之间存在多对多关系。一个孩子可以有多个父母,一个父母可以有多个孩子。
我设计的模型有一个具有公共属性的父类
User
,并且每种类型都有一个类作为子类。这个想法是它会生成数据库表“用户”、“儿童”、“监护人”和“教师”。最后三个对用户来说是外键,因此当我检索例如教师时,我还可以检索它的名字和姓氏。
这些是我的模型: 用户.php
<?php
namespace App\Domain\Model\User;
use App\Domain\Model\Timestampable;
use App\Domain\Model\HasUuid;
class User
{
use Timestampable;
use HasUuid;
public function __construct(
private string $username,
private string $firstName,
private string $lastName,
private string $passcode,
)
{
$this->username = $username;
$this->firstName = $firstName;
$this->lastName = $lastName;
$this->passcode = $passcode;
}
public function getUsername(): string
{
return $this->username;
}
public function setUsername(string $username): void
{
$this->username = $username;
}
public function getFirstName(): string
{
return $this->firstName;
}
public function setFirstName(string $firstName): void
{
$this->firstName = $firstName;
}
public function getLastName(): string
{
return $this->lastName;
}
public function setLastName(string $lastName): void
{
$this->lastName = $lastName;
}
public function getFullName(): string
{
return $this->firstName . ' ' . $this->lastName;
}
public function getPasscode(): string
{
return $this->passcode;
}
public function setPasscode(string $passcode): void
{
$this->passcode = $passcode;
}
}
Child.php
<?php
namespace App\Domain\Model\User;
use App\Domain\Model\HasUuid;
use App\Domain\Model\User\User;
use App\Domain\Model\User\Guardian;
class Child extends User
{
use HasUuid;
public function __construct(
private string $username,
private string $firstName,
private string $lastName,
private string $passcode,
private array $guardians,
)
{
parent::__construct($username, $firstName, $lastName, $passcode);
}
public function getGuardians(): array
{
return $this->guardians;
}
public function addGuardian(Guardian $guardian): void
{
$this->guardians[] = $guardian;
}
}
守护者.php
<?php
namespace App\Domain\Model\User;
use App\Domain\Model\HasUuid;
use App\Domain\Model\User\User;
use App\Domain\Model\User\Child;
class Guardian extends User
{
use HasUuid;
public function __construct(
private string $username,
private string $firstName,
private string $lastName,
private string $passcode,
private string $email,
private string $telnr,
private array $children,
)
{
parent::__construct($username, $firstName, $lastName, $passcode);
}
public function getEmail(): string
{
return $this->email;
}
public function setEmail(string $email): void
{
$this->email = $email;
}
public function getTelnr(): string
{
return $this->telnr;
}
public function setTelnr(string $telnr): void
{
$this->telnr = $telnr;
}
public function getChildren(): array
{
return $this->children;
}
public function addChild(Child $child): void
{
$this->children[] = $child;
}
}
老师.php
<?php
namespace App\Domain\Model\User;
use App\Domain\Model\Timestampable;
use App\Domain\Model\HasUuid;
use App\Domain\Model\User\User;
class Teacher extends User
{
use HasUuid;
public function __construct(
private string $username,
private string $firstName,
private string $lastName,
private string $passcode,
private string $email,
private string $telnr,
)
{
parent::__construct($username, $firstName, $lastName, $passcode);
$this->email = $email;
$this->telnr = $telnr;
}
public function getEmail(): string
{
return $this->email;
}
public function setEmail(string $email): void
{
$this->email = $email;
}
public function getTelnr(): string
{
return $this->telnr;
}
public function setTelnr(string $telnr): void
{
$this->telnr = $telnr;
}
}
现在我使用 XML 格式的 Doctrine/ORM 来生成数据库方案。这是我当前的配置: 用户.orm.xml
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="App\Domain\Model\User\User" table="users" inheritance-type="JOINED">
<id name="id" type="guid" column="id">
<generator strategy="NONE"/>
</id>
<field name="username" type="string" length="255" nullable="false"/>
<field name="firstName" type="string" length="255" nullable="false"/>
<field name="lastName" type="string" length="255" nullable="false"/>
<field name="passcode" type="string" length="255" nullable="false"/>
<field name="createdAt" type="datetime" nullable="false"/>
<field name="updatedAt" type="datetime" nullable="false"/>
<field name="deletedAt" type="datetime" nullable="true"/>
<discriminator-column name="type" type="string" />
<discriminator-map>
<discriminator-mapping value="teacher" class="App\Domain\Model\User\Teacher" />
<discriminator-mapping value="guardian" class="App\Domain\Model\User\Guardian" />
<discriminator-mapping value="child" class="App\Domain\Model\User\Child" />
</discriminator-map>
</entity>
</doctrine-mapping>
Child.orm.xml
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="App\Domain\Model\User\Child" table="children">
<!-- Many-to-many relationship with Guardian -->
<many-to-many field="guardians" target-entity="App\Domain\Model\User\Guardian">
<join-table name="guardians_children">
<join-columns>
<join-column name="child_id" referenced-column-name="id" nullable="false"/>
</join-columns>
<inverse-join-columns>
<join-column name="guardian_id" referenced-column-name="id" nullable="false"/> <!-- Ensure NOT NULL -->
</inverse-join-columns>
</join-table>
</many-to-many>
</entity>
</doctrine-mapping>
Guardian.orm.xml
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="App\Domain\Model\User\Guardian" table="guardians">
<!-- Many-to-many relationship with Child -->
<many-to-many field="children" target-entity="App\Domain\Model\User\Child" inversed-by="guardians">
<join-table name="guardian_child">
<join-columns>
<join-column name="guardian_id" referenced-column-name="id" nullable="false"/> <!-- Ensure NOT NULL -->
</join-columns>
<inverse-join-columns>
<join-column name="child_id" referenced-column-name="id" nullable="false"/> <!-- Ensure NOT NULL -->
</inverse-join-columns>
</join-table>
</many-to-many>
</entity>
</doctrine-mapping>
教师.orm.xml
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="App\Domain\Model\User\Teacher" table="teachers">
<field name="email" type="string" length="255" nullable="false"/>
<field name="telnr" type="string" length="50" nullable="false"/>
</entity>
</doctrine-mapping>
由此生成迁移会创建以下表: [
如您所见,表包含正确的字段,并且用户包含用于确定用户类型的鉴别器。但是代表不同类型用户的表缺少一些东西。当我在这个数据库中检索教师时,我不知道他实际上是什么用户,并且不可能获得名字、姓氏……因为表 Teachers 没有与表 Users 的外键。
我想我可以通过在xml的子表中添加多对一来解决这个问题:
<entity name="App\Domain\Model\User\Teacher" table="teachers">
<field name="email" type="string" length="255" nullable="false"/>
<field name="telnr" type="string" length="50" nullable="false"/>
<many-to-one field="user" target-entity="App\Domain\Model\User\User" inversed-by="teachers">
<join-column name="id" referenced-column-name="id" nullable="false"/>
</many-to-one>
</entity>
但这会出现以下错误:
Property App\Domain\Model\User\Teacher::$user does not exist
这可以通过向教师类添加属性
$user
来解决。但老师已经从用户扩展,所以这对我来说似乎没有意义。
我认为我做错了什么,我如何成功实现不同类型的用户?