SMS and Voice services
MMO Games
local positioning systems
TV productions
Healthcare
e-commerce
websites
SEO
online video
Help all the teams involved in the production do their job quicker, easier and with better quality...
We didn't really know what we were supposed to create
"Your architectures should tell readers about the system, not about the frameworks you used in your system."
"Uncle" Bob Martin
<?php
use App\Http\Controllers;
class ContestantController extends Controller {
.
.
.
public function advanceToRound(Request $request) {
Gate::authorize('contestant-advancement');
$params = $request->validate([
'contestantId' => 'required|int',
'round' => 'required|in:casting,competition',
'signedContract' => 'required|file',
]);
$contestant = Contestant::findOrFail($params['contestantId']);
if ($contestant->jurryApprovals()->doesntExist()) {
throw new RuntimeException(t('Not approved for advancement!'));
}
$contestant->round = $params['round'];
$contastant->advancedByUserId = Auth::id();
$contestant->save();
$request->file('signedContract')->store('contestants/docs');
return redirect(route('contestant-profile', $params['contenstantId']));
}
.
.
.
}
<?php
namespace MusicIdol\Domain\Contestants;
use Exceptions\ContestantNotApprovedForAdvancement;
class AdvanceToRound {
public function __construct(
private ActorProvider $ap,
private ContestantAuthorizations $auth,
private ContestantsRepository $repo,
private Transaction $tr
) {}
public function __invoke(AdvanceToRoundParams $params): void
{
$this->auth->authorizeContestantAdvancement($this->ap->actor());
$contestant = $this->repo->findById($params->contestantId());
if ($contestant->isNotApproved()) {
throw new ContestantNotApprovedForAdvancement();
}
$contestant->round = $params->round();
$contestant->advancedByUser = $this->ap->actor();
$contestant->signedContract = $params->signedContract();
$tr->persist($contestant);
}
}
<?php
namespace MusicIdol\Domain\Contestants;
class AdvanceToRoundParams {
private int $contestantId;
private string $round;
private File $signedContract;
private function __construct() {}
public function contestantId(): int {
return $this->contestantId;
}
.
.
.
public static function fromArray(array $params): self
{
$validated = Validator::make($params, [
'contestantId' => 'required|int',
'round' => 'required|in:casting,competition',
'signedContract' => 'required|file',
])->validate();
$instance = new self();
$instance->contestantId = $validated['contestantId'];
$instance->round = $validated['round'];
$instance->signedContract = $validated['signedContract'];
return $instance;
}
}
<?php
namespace MusicIdol\Domain\Contestants;
use Excepttions\UnauthorizedToAdvanceUser;
class ContestantAuthorizations {
public function authorizeContestantAdvancement(User $actor): void {
if ($user->role !== User::ROLE_CASTING_TEAM) {
throw new UnauthorizedToAdvanceUser();
}
}
}
<?php
namespace MusicIdol\Domain\Users;
interface ActorProvider {
public function actor(): User;
}
<?php
namespace MusicIdol\Domain\Transaction;
interface Transaction {
public function persist(): void;
}
<?php
namespace MusicIdol\Domain\Contestants;
interface ContestantsRepository {
public function findById(): Contestant;
}
<?php
class AdvanceToRoundController extends Controller {
public function __contructor(
private AdvanceToRound $action;
) {}
public function __invoke(Request $request) {
$params = AdvanceToRoundParams::fromArray($request->post());
($this->action)($params);
return redirect(route('contestant-profile', $request->post('contenstantId')));
}
}
[
'match' => [
'method' => 'GET',
'path' => '/contestants/{id}/notes/new'
],
'service' => [
'className' => MusicIdol\ContestantsManagement\AdvanceToRound::class,
'parametersFactory' => fn (R $r) => AdvanceToRoundParams::fromArray($r->post()),
'responder' => fn (R $r, $result) => redirect(
route('contestant-profile', $r->post('contestantId'))
);
]
],
...
[
'match' => [
'command' => 'advanceToRound'
],
'service' => [
'className' => MusicIdol\ContestantsManagement\AdvanceToRound::class,
'parametersFactory' => fn (Command $c) =>
AdvanceToRoundParams::fromArray($c->arguments()),
'responder' => fn (Command $c, $result) => $c->info('Done');
]
],
...
Domain Driven Design: Tackling Complexity in the Heart of Software
Eric Evans
Clean Architecture Talk
https://www.youtube.com/watch?v=Nsjsiz2A9mg
"Uncle" Bob Martin
Action Domain Responder
https://github.com/pmjones/adr
Paul Jones
Milko Kosturkov
@mkosturkov
linkedin.com/in/milko-kosturkov
mailto: mkosturkov@gmail.com
These slides:
https://slides.com/milkokosturkov/minimize-the-framework-and-allow-yourself-some-ddd-v2