Php Symfony:服务和富域模型
对于使用条令ORM的Symfony项目,我习惯于使用贫乏的领域模型,在Symfony服务中处理业务逻辑。对于涉及大量业务逻辑的项目,我想知道使用富域模型(我不熟悉)是否不是一个更好的解决方案我不想比较RDM和ADM,因为已经有很多在线资源可以用来找出每个解决方案的优缺点。我很想知道RDM是否适合Symfony项目。为了下定决心,我想了解一下我应该如何在实际应用程序中实现RMD 我的主要问题是:Php Symfony:服务和富域模型,php,symfony,dependency-injection,domain-driven-design,Php,Symfony,Dependency Injection,Domain Driven Design,对于使用条令ORM的Symfony项目,我习惯于使用贫乏的领域模型,在Symfony服务中处理业务逻辑。对于涉及大量业务逻辑的项目,我想知道使用富域模型(我不熟悉)是否不是一个更好的解决方案我不想比较RDM和ADM,因为已经有很多在线资源可以用来找出每个解决方案的优缺点。我很想知道RDM是否适合Symfony项目。为了下定决心,我想了解一下我应该如何在实际应用程序中实现RMD 我的主要问题是: RDM真的适合Symfony的理念和最佳实践吗 RDM让模型做了太多的工作,这难道没有打破坚实的原则
- RDM真的适合Symfony的理念和最佳实践吗
- RDM让模型做了太多的工作,这难道没有打破坚实的原则吗
- 模型如何管理依赖关系
<?php
// src/Entity/User.php
namespace App\Entity;
class User
{
private $id;
private $externalId;
private $email;
private $plainPassword;
private $password;
private $lastName;
private $firstName;
// Include more properties, getters and setters, ...
}
<?php
// src/Entity/User.php
namespace App\Entity;
class User
{
private $id;
private $externalId;
private $email;
private $plainPassword;
private $password;
private $lastName;
private $firstName;
// Include more properties, getters and setters, ...
}
我希望您知道,这(显然)主要是基于意见,因此您可能同意或不同意它
我认为你对什么是富域模型和贫血症域模型有很大的误解。但让我们从几个假设开始:
在我的理解中,symfony中的实体(更准确地说,在学说的ORM中)在大多数情况下已经是模型。因此,不需要额外的用户
模型。即使您想要拆分,我也不会将完全相同的字段放入模型中,而是将实体作为字段。如果您碰巧将所有实体函数复制到模型中,那么您就做错了。由于默认情况下,实体的所有字段都应该是私有的,因此没有理由不将其视为模型。(我的意思是,它已经可以处理对象,而不是它们在关系中的ID…)
用户
模型/实体永远不应该关心发送电子邮件,因为它打破了关注点的分离。相反,应该有一些东西来模拟发送电子邮件的过程。我发现这是如何工作的,描述得相当清楚。注意对装运和CheckoutService->Checkout的更改
具有讽刺意味的是,您的“贫血域模型”的用户注册服务相当不错。尽管用户实体在该实现中有点不足,它可能会验证用户实体,但除此之外,该服务可以重命名为UserRegistration
,并且非常适合RDM。(我同意,表单已经在进行验证(这真的很方便),但是可能存在一些验证,这些验证不是关于用户本身的一致性,而是关于作为数据库/模型中用户集合的一部分的用户,或者其他东西)
总而言之:在我看来,Symfony可以很好地完成RDM。但真正的关键(一如既往)是实际选择/设计最好的模型
本质上说:贫血意味着你没有一个地方所有的事情都是一致的,而是以一种风险的方式进行分割,即一致性/完整性或将关注点分离给独立的单位。相反,RDM使它聚集在语义上合理的地方。这并没有改变事实,你仍然想要分离关注点
现在回答您的问题:
RDM真的适合Symfony的理念和最佳实践吗
为什么不呢。但这取决于建模,可能会根据Symfony的最佳实践进行调整
RDM让模型做了太多的工作,这难道没有打破坚实的原则吗
如果做得好,一般不会。您的实现肯定会打破稳定,但RDM不必这样做。没有人说拥有UserRegister、UserCancel和UserUpdate服务/模型是错误的。RDM是关于将语义上属于业务流程/单元的内容在代码中保持在一起(这并不否定关注点分离或单一目的)
模型如何管理依赖关系
因为在我看来,业务流程是模型,将充当服务,所以依赖关系就像它们在服务中处理一样。另一方面,实体永远不应该需要服务*。(可能存在一些非常特殊的情况,在这种情况下,您可能希望实际拥有一个管理实体创建/更新的服务(可能是工厂)
你对此有何看法?我做错什么了吗
我们可以说,您的实现是“不幸的”,因为在我的理解中,它不是RDM,并且(正如您自己所意识到的)到处都是不可靠的。因此,问题的第二部分是肯定的 谢谢你详细的回答!基于此,我可以说我的一个困难是,我很难将模型视为数据持有者以外的东西:据我所知,模型永远不应该是服务,因此属性和依赖关系混乱不堪。我可能也混淆和混合了模型和实体的概念(对我来说不是这样)
<?php
// src/Controller/UserController.php
namespace App\Controller;
class UserController
{
public function registerAction(Request $request, UserRegistrationService $userRegistrationService, Serializer $serializer)
{
$user = new User();
$form = $this->createForm(UserType::class, $user);
$form->handleRequest($request);
if (!$form->isValid()) {
// Process errors
}
$userRegistrationService->register($user);
return $this->serializer->serialize($user);
}
}
<?php
// src/Entity/User.php
namespace App\Entity;
class User
{
private $id;
private $externalId;
private $email;
private $plainPassword;
private $password;
private $lastName;
private $firstName;
// Include more properties, getters and setters, ...
}
<?php
// src/Model/UserRegistration.php
namespace App\Model;
class UserRegistration
{
private $email;
private $plainPassword;
private $lastName;
private $firstName;
private function __construct(string $email, string $plainPassword, string $lastName, string $firstName)
{
$this->email = $email;
$this->plainPassword = $plainPassword;
$this->lastName = $lastName;
$this->firstName = $firstName;
}
// Getters
public static function createFromRequest(Validator $validator, Request $request)
{
$requestData = $request->request->all();
$userRegistration = new self(requestData['email'], $requestData['plainPassword'], $requestData['lastName'], $requestData['firstName']);
$violations = $validator->validate($userRegistration);
if (count($violations) > 0) {
throw new \Exception(); // handle errors
}
return $userRegistration;
}
}
<?php
// src/Model/User.php
namespace App\Model;
class User
{
private $id;
private $externalId;
private $email;
private $oassword;
private $lastName;
private $lastName;
private function __construct(string $id, string $externalId, string $email, string $password, string $lastName, string $firstName)
{
$this->id = $id;
$this->externalId = $externalId;
$this->email = $email;
$this->password = $password;
$this->lastName = $lastName;
$this->firstName = $firstName;
}
// Getters
public static function createFromUserRegistration(Validator $validator, PasswordEncoder $passwordEncoder, ExternalProviderClient $externalProviderClient, EntityManager $em, MessageBusInterface $bus, UserRegistration $userRegistration)
{
$password = $passwordEncoder->encodePassword($userRegistration->getPlainPassword());
$externalId = $externalProviderClient->registerUser([
'email' => $userRegistration->getEmail(),
'firstName' => $userRegistration->getFirstName(),
'lastName' => $userRegistration->getLastName(),
]);
$userEntity = (new \App\Entity\User())
->setExternalId($externalId)
->setEmail($userRegistration->getEmail())
->setPassword($password)
->setLastName($userRegistration->getLastName())
->setFirstName($userRegistration->getFirstName())
;
$em->persist($userEntity);
$em->flush();
$id = ;
$user = self::buildFromUserEntity($validator, $userEntity);
$bus->dispatch(new UserMessage($user));
return $user;
}
public static function buildFromUserEntity(Validator $validator, \App\Entity\User $userEntity)
{
$user = new self(
$userEntity->getId(),
$userEntity->getExternalId(),
$userEntity->getEmail(),
$userEntity->getPassword(),
$userEntity->getLastName(),
$userEntity->getFirstName()
);
$violations = $validator->validate($user);
if (count($violations) > 0) {
throw new \Exception(); // handle errors
}
return $user;
}
public function completeRegistration(EntityManager $em, ElasticSearch $elasticSearch, Mailer $mailer)
{
$dummy = new Dummy($this);
$dummy->save($em);
$this->populateElasticSearch($elasticSearch);
$dummy->populateElasticSearch($elasticSearch);
$this->sendConfirmationEmail($mailer);
}
public function populateElasticSearch(ElasticSearch $elasticSearch)
{
$this->elasticSearch->populate($this);
}
public function sendConfirmationEmail(Mailer $mailer)
{
$this->mailer->sendConfirmationEmail($this);
}
public function serialize(Serializer $serializer)
{
return $serializer->serialize($user);
}
}
<?php
// src/Controller/UserController.php
namespace App\Controller;
class UserController
{
public function registerAction(Request $request, Validator $validator, PasswordEncoder $passwordEncoder, ExternalProviderClient $externalProviderClient, EntityManager $em, MessageBusInterface $bus, Serializer $serializer)
{
$userRegistration = UserRegistration::createFromRequest($validator, $request);
$user = User::createFromUserRegistration($validator, $passwordEncoder, $externalProviderClient, $em, $bus, $userRegistration);
return $user->serialize($serializer);
}
}