He leído sobre DDD desde hace días y necesito ayuda con este diseño de muestra. Todas las reglas de DDD me confunden mucho sobre cómo se supone que debo construir algo cuando los objetos de dominio no pueden mostrar métodos en la capa de aplicación; ¿Dónde más orquestar el comportamiento? Los repositorios no pueden inyectarse en entidades y las entidades mismas deben trabajar en estado. ¿Entonces una entidad necesita saber algo más del dominio, pero tampoco se permite inyectar otros objetos de entidad? Algunas de estas cosas tienen sentido para mí, pero otras no. Todavía tengo que encontrar buenos ejemplos de cómo construir una función completa, ya que cada ejemplo trata de Pedidos y Productos, repitiendo los otros ejemplos una y otra vez. Aprendo mejor leyendo ejemplos y he intentado crear una función utilizando la información que he obtenido sobre DDD hasta ahora.
Necesito su ayuda para señalar lo que hago mal y cómo solucionarlo, lo más preferiblemente con el código, ya que "No recomendaría hacer X e Y" es muy difícil de entender en un contexto donde todo ya está vagamente definido. Si no puedo inyectar una entidad en otra, sería más fácil ver cómo hacerlo correctamente.
En mi ejemplo hay usuarios y moderadores. Un moderador puede prohibir a los usuarios, pero con una regla comercial: solo 3 por día. Intenté configurar un diagrama de clase para mostrar las relaciones (código a continuación):

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);
¿La titularidad del usuario debe tener un 'is_banned'campo con el que se pueda verificar $user->isBanned();? ¿Cómo eliminar una prohibición? No tengo idea.