Domain-specific operations
Similar to the previous rule, instead of creating setters to modify model properties or directly modifying public properties, encapsulate the logic in domain-specific methods. This way you can make sure that your models have a valid/consistent state at all times.
PHP
// GOOD
// Models\Member.php
public function confirmEmailAwaitingConfirmation(): void
{
$this->email = $this->email_awaiting_confirmation;
$this->email_awaiting_confirmation = null;
}
// Controllers\MemberEmailConfirmationController.php
public function store(): void
{
$member = Auth::guard('member')->user();
$member->confirmEmailWaitingConfirmation();
$member->save();
}
// BAD =====================================
// Models\Member.php
public function setEmail(string $email): Member;
public function setEmailWaitingConfirmation(string $email): Member;
// Controllers\MemberEmailConfirmationController.php
public function store(): void
{
$member = Auth::guard('member')->user();
$member->email = $member->emailWaitingConfirmation;
$member->emailWaitingConfirmation = null;
$member->save();
}
Note that this convention aligns with the idea of putting domain logic into services and not into controllers or models, hence having rich domain services and thin controllers/models.
Want to learn more?
"Cruddy by Design" by Adam Wathan, 40 mins.
Read more about class invariants for a better understanding of the dangers of modifying class properties from controllers/services.
