Milko Kosturkov
An experienced developer specializing in the web.
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
/**
* @Route("/contestants/notes/new", methods={"POST"}, name="contestant_note_new")
* @IsGranted("IS_CASTING_TEAM")
*
*/
public function noteNew(Request $request, Contestant $contestant, EventDispatcherInterface $eventDispatcher): Response
{
$note = new Note();
$note->setAuthor($this->getUser());
$contestant->addNote($note);
$form = $this->createForm(NoteType::class, $note);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($note);
$em->flush();
$event = new GenericEvent($note);
$eventDispatcher->dispatch(Events::CONTESTANT_NOTE_CREATED, $event);
return $this->redirectToRoute('contestang', ['id' => $contestant->getId()]);
}
return $this->render('contestant/contestant_form_error.html.twig', [
'contestant' => $contestant,
'form' => $form->createView(),
]);
}
Authorization
Validation
Business logic
namespace \MusicIdol\Domain\Contestants;
class NewNote {
private $em;
private $ed;
public function __construct(EntityManagerInterface $em, EventDispatcherInterface $ed) {
$this->em = $em;
$this->ed = $ed;
}
public function __invoke(User $user, int $contestantId, string $noteText) {
if (empty ($noteText)) {
throw new InvalidArgumentException('The note can not be empty');
}
$contestant = $this->em->find(Contestant::class, $contestantId);
if (!$contestant) {
throw new EntityNotFoundException('Contestant does not exist');
}
if (!$user->isGranted('IS_CASTING_TEAM')) {
throw new UnauthorizedException('User is not authorized to add notes');
}
$note = new Note();
$note->setText($noteText);
$note->setAuthor($user);
$contestant->addNote($note);
$this->em->persist($note);
$this->em->flush();
$event = new GenericEvent($note);
$this->ed->dispatch(Events::CONTESTANT_NOTE_CREATED, $event);
return true;
}
}
/**
* @Route("/contestants/{id}/notes/new", methods={"POST"}, name="contestant_note_new")
*
*/
public function noteNew(Request $request, Contestant $contestant, EntityManagerInterface $em,
EventDispatcherInterface $ed): Response
{
$appService = new NewNote($em, $ed);
try {
if ($appService($this->getUser(), $contestant, $request->request->get('note'))) {
return $this->redirectToRoute('contestang', ['id' => $contestant->getId()]);
}
} catch (...) {
/* handle error here */
}
return $this->render('contestant/contestant_form_error.html.twig', [
'contestant' => $contestant,
'form' => $form->createView(),
]);
}
[
'match' => [
'method' => 'GET',
'path' => '/contestants/{id}/notes/new'
],
'service' => [
'className' => MusicIdol\ContestantsManagement\AddNote::class,
'parametersMapping' => [
'contestantId' => 'parameters.id',
'textNote' => 'post.note'
],
'responder' => \UI\JsonResponder::class
]
],
...
[
'match' => [
'command' => 'add-note'
],
'service' => [
'className' => MusicIdol\ContestantsManagement\AddNote::class,
'parametersMapping' => [
'contestantId' => '--contestant-id',
'textNote' => '--note'
],
'responder' => \UI\ConsoleResponder::class
]
],
...
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-framework
By Milko Kosturkov
By now we've all heard what Domain Driven Design is about. Some of us have actually tried it. When we did, we stumbled upon the fact that the frameworks we use do not help us a lot with shaping our code in a domain driven manner. Actually, they were in the way. DDD and the generic MVC frameworks we use are an oxymoron. Still, we don't want to loose all the sweet tools that help us deal with the HTTP and the Console. In this talk I'll tell you how we changed our view perspective on input/output/request/response, pushed the framework in the infrastructure corner and cleaned ourselves some space for sweet DDD.