I’m working on an aggregate where certain behaviours can be performed by multiple roles within the application. But before that happens fairly complex validation occurs. It’s this validation that differs per role. Typically it means different configuration settings are checked to determine if the action can be performed.
So, as an example: lets say i have an Order to which i can add OrderLines. If i have role Employee i might be allowed to order up to € 100,- and if i have role Purchaser i might be allowed to order up to € 1000,-.
You could solve this by providing the user instance to the addOrderLine method but that leaks the user context into the ordering context. The next logical thing, and this is what I’ve been doing, is in to inject that validation logic into the method call. I’m calling those methods policies and instantiate the right policy in the application service as i have the relevant user info available there:
<?php
class Order {
public function addItem(OrderPolicy $policy, Item $item, int $amount) {
if (!$policy->canPurchase($item->getPrice() * $amount))
throw new LimitExceededException();
/* add item here */
}
class OrderService {
public function addItem(User $user, $orderId, $itemId, int $amount) {
$order = $this->orderRepo->getForUser($user, $orderId);
$item = $this->itemRepo->get($itemId);
$policy = $this->getOrderPolicyFor($user);
$order->addItem($policy, $item, $amount);
}
}
class PurchaserOrderPolicy
{
function canPurchase($amount) {
return ($amount <= 1000);
}
}
This seems fine, but now it seems to me my ordering context has logic based on user roles (the policy classes) its not supposed to know about.
Does DDD offer any other ways of dealing with this? Maybe Specification? Does this seem fine? Where do the policy classes belong?