Eu li sobre DDD há dias e preciso de ajuda com este design de exemplo. Todas as regras do DDD me deixam muito confuso sobre como eu devo criar alguma coisa quando objetos de domínio não têm permissão para mostrar métodos para a camada de aplicativo; onde mais para orquestrar o comportamento? Repositórios não podem ser injetados em entidades e as próprias entidades devem, portanto, trabalhar no estado. Então, uma entidade precisa saber mais alguma coisa do domínio, mas também não é permitido que outros objetos de entidade sejam injetados? Algumas dessas coisas fazem sentido para mim, mas outras não. Ainda não encontrei bons exemplos de como criar um recurso completo, pois todos os exemplos são sobre pedidos e produtos, repetindo os outros exemplos várias vezes. Aprendo melhor lendo exemplos e tentei criar um recurso usando as informações que adquiri sobre DDD até agora.
Preciso da sua ajuda para apontar o que eu faço de errado e como corrigi-lo, de preferência com código como "Eu não recomendo fazer X e Y" é muito difícil de entender em um contexto em que tudo já está vagamente definido. Se eu não puder injetar uma entidade em outra, seria mais fácil ver como fazê-lo corretamente.
No meu exemplo, existem usuários e moderadores. Um moderador pode banir usuários, mas com uma regra de negócios: apenas 3 por dia. Fiz uma tentativa de configurar um diagrama de classes para mostrar os relacionamentos (código abaixo):
interface iUser
{
public function getUserId();
public function getUsername();
}
class User implements iUser
{
protected $_id;
protected $_username;
public function __construct(UserId $user_id, Username $username)
{
$this->_id = $user_id;
$this->_username = $username;
}
public function getUserId()
{
return $this->_id;
}
public function getUsername()
{
return $this->_username;
}
}
class Moderator extends User
{
protected $_ban_count;
protected $_last_ban_date;
public function __construct(UserBanCount $ban_count, SimpleDate $last_ban_date)
{
$this->_ban_count = $ban_count;
$this->_last_ban_date = $last_ban_date;
}
public function banUser(iUser &$user, iBannedUser &$banned_user)
{
if (! $this->_isAllowedToBan()) {
throw new DomainException('You are not allowed to ban more users today.');
}
if (date('d.m.Y') != $this->_last_ban_date->getValue()) {
$this->_ban_count = 0;
}
$this->_ban_count++;
$date_banned = date('d.m.Y');
$expiration_date = date('d.m.Y', strtotime('+1 week'));
$banned_user->add($user->getUserId(), new SimpleDate($date_banned), new SimpleDate($expiration_date));
}
protected function _isAllowedToBan()
{
if ($this->_ban_count >= 3 AND date('d.m.Y') == $this->_last_ban_date->getValue()) {
return false;
}
return true;
}
}
interface iBannedUser
{
public function add(UserId $user_id, SimpleDate $date_banned, SimpleDate $expiration_date);
public function remove();
}
class BannedUser implements iBannedUser
{
protected $_user_id;
protected $_date_banned;
protected $_expiration_date;
public function __construct(UserId $user_id, SimpleDate $date_banned, SimpleDate $expiration_date)
{
$this->_user_id = $user_id;
$this->_date_banned = $date_banned;
$this->_expiration_date = $expiration_date;
}
public function add(UserId $user_id, SimpleDate $date_banned, SimpleDate $expiration_date)
{
$this->_user_id = $user_id;
$this->_date_banned = $date_banned;
$this->_expiration_date = $expiration_date;
}
public function remove()
{
$this->_user_id = '';
$this->_date_banned = '';
$this->_expiration_date = '';
}
}
// Gathers objects
$user_repo = new UserRepository();
$evil_user = $user_repo->findById(123);
$moderator_repo = new ModeratorRepository();
$moderator = $moderator_repo->findById(1337);
$banned_user_factory = new BannedUserFactory();
$banned_user = $banned_user_factory->build();
// Performs ban
$moderator->banUser($evil_user, $banned_user);
// Saves objects to database
$user_repo->store($evil_user);
$moderator_repo->store($moderator);
$banned_user_repo = new BannedUserRepository();
$banned_user_repo->store($banned_user);
A entidade Usuário deve ter um 'is_banned'
campo que possa ser verificado $user->isBanned();
? Como remover uma proibição? Eu não faço ideia.