Ho letto su DDD per giorni e ho bisogno di aiuto con questo progetto di esempio. Tutte le regole di DDD mi rendono molto confuso su come dovrei costruire qualcosa quando gli oggetti di dominio non sono autorizzati a mostrare metodi a livello di applicazione; dove altro orchestrare il comportamento? I repository non possono essere iniettati in entità e le entità stesse devono quindi lavorare sullo stato. Quindi un'entità deve sapere qualcos'altro dal dominio, ma non è consentito iniettare altri oggetti entità? Alcune di queste cose hanno senso per me, ma altre no. Devo ancora trovare buoni esempi di come creare un'intera funzionalità poiché ogni esempio riguarda ordini e prodotti, ripetendo gli altri esempi più e più volte. Imparo meglio leggendo esempi e ho provato a creare una funzionalità utilizzando le informazioni che ho acquisito su DDD finora.
Ho bisogno del tuo aiuto per sottolineare cosa faccio di sbagliato e come risolverlo, preferibilmente con il codice come "Non consiglierei di fare X e Y" è molto difficile da capire in un contesto in cui tutto è già vagamente definito. Se non riesco a iniettare un'entità in un'altra, sarebbe più facile vedere come farlo correttamente.
Nel mio esempio ci sono utenti e moderatori. Un moderatore può vietare gli utenti, ma con una regola aziendale: solo 3 al giorno. Ho fatto un tentativo di impostare un diagramma di classe per mostrare le relazioni (codice sotto):
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);
L'entità utente dovrebbe avere un 'is_banned'
campo che può essere verificato con $user->isBanned();
? Come rimuovere un divieto? Non ne ho idea.