From 212cd50778f8b2f729d405287c283a66c3f4cf2e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miguel=20=C3=81ngel=20S=C3=A1nchez=20Palafox?=
 <pala_fox044@hotmail.com>
Date: Thu, 19 Aug 2021 02:03:28 -0500
Subject: [PATCH] First practice with adapter and ports

---
 .../backend/config/routes/courses.yaml        |  6 ++++
 apps/backoffice/backend/config/services.yaml  |  1 +
 .../Courses/LastVideoController.php           | 21 ++++++++++++++
 .../LastBackofficeCourseSearcher.php          | 28 +++++++++++++++++++
 ...earchLastBackofficeCoursesQueryHandler.php | 20 +++++++++++++
 .../Domain/BackofficeCourseRepository.php     |  3 ++
 ...lasticsearchBackofficeCourseRepository.php |  7 +++++
 ...nMemoryCacheBackofficeCourseRepository.php |  9 ++++++
 .../MySqlBackofficeCourseRepository.php       |  7 +++++
 .../Elasticsearch/ElasticsearchRepository.php | 10 +++++--
 10 files changed, 110 insertions(+), 2 deletions(-)
 create mode 100644 apps/backoffice/backend/src/Controller/Courses/LastVideoController.php
 create mode 100644 src/Backoffice/Courses/Application/LastVideo/LastBackofficeCourseSearcher.php
 create mode 100644 src/Backoffice/Courses/Application/LastVideo/SearchLastBackofficeCoursesQueryHandler.php

diff --git a/apps/backoffice/backend/config/routes/courses.yaml b/apps/backoffice/backend/config/routes/courses.yaml
index 06ae46ee8..9d19a9780 100644
--- a/apps/backoffice/backend/config/routes/courses.yaml
+++ b/apps/backoffice/backend/config/routes/courses.yaml
@@ -3,3 +3,9 @@ courses_get:
   controller: CodelyTv\Apps\Backoffice\Backend\Controller\Courses\CoursesGetController
   defaults: { auth: false }
   methods:  [GET]
+
+course_last:
+  path: /last-course
+  controller: CodelyTv\Apps\Backoffice\Backend\Controller\Courses\LastVideoController
+  defaults: { auth: false }
+  methods:  [GET]
\ No newline at end of file
diff --git a/apps/backoffice/backend/config/services.yaml b/apps/backoffice/backend/config/services.yaml
index d0e25db62..2b6a3b7b7 100644
--- a/apps/backoffice/backend/config/services.yaml
+++ b/apps/backoffice/backend/config/services.yaml
@@ -96,3 +96,4 @@ services:
   # -- IMPLEMENTATIONS SELECTOR --
   CodelyTv\Shared\Domain\Bus\Event\EventBus: '@CodelyTv\Shared\Infrastructure\Bus\Event\WithMonitoring\WithPrometheusMonitoringEventBus'
   CodelyTv\Backoffice\Courses\Domain\BackofficeCourseRepository: '@CodelyTv\Backoffice\Courses\Infrastructure\Persistence\ElasticsearchBackofficeCourseRepository'
+  CodelyTv\Shared\Domain\Bus\Query\QueryHandler: '@CodelyTv\Backoffice\Courses\Application\LastVideo\SearchLastBackofficeCoursesQueryHandler'
\ No newline at end of file
diff --git a/apps/backoffice/backend/src/Controller/Courses/LastVideoController.php b/apps/backoffice/backend/src/Controller/Courses/LastVideoController.php
new file mode 100644
index 000000000..507ca2929
--- /dev/null
+++ b/apps/backoffice/backend/src/Controller/Courses/LastVideoController.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace CodelyTv\Apps\Backoffice\Backend\Controller\Courses;
+
+use CodelyTv\Shared\Domain\Bus\Query\QueryHandler;
+use Symfony\Component\HttpFoundation\JsonResponse;
+use Symfony\Component\HttpFoundation\Request;
+
+class LastVideoController
+{
+    public function __construct(private QueryHandler $queryBus)
+    {
+    }
+
+    public function __invoke(Request $request): JsonResponse
+    {
+        return new JsonResponse(
+            $this->queryBus->__invoke()
+        );
+    }
+}
diff --git a/src/Backoffice/Courses/Application/LastVideo/LastBackofficeCourseSearcher.php b/src/Backoffice/Courses/Application/LastVideo/LastBackofficeCourseSearcher.php
new file mode 100644
index 000000000..95fc6084a
--- /dev/null
+++ b/src/Backoffice/Courses/Application/LastVideo/LastBackofficeCourseSearcher.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace CodelyTv\Backoffice\Courses\Application\LastVideo;
+
+use CodelyTv\Backoffice\Courses\Application\BackofficeCourseResponse;
+use CodelyTv\Backoffice\Courses\Domain\BackofficeCourseRepository;
+
+class LastBackofficeCourseSearcher
+{
+    public function __construct(private BackofficeCourseRepository $repository)
+    {
+    }
+
+    public function __invoke(): ?BackofficeCourseResponse
+    {
+        $lastCourse = $this->repository->lastCourse();
+
+        if (!$lastCourse) {
+            return null;
+        }
+
+        return new BackofficeCourseResponse(
+            $lastCourse->id(),
+            $lastCourse->name(),
+            $lastCourse->duration()
+        );
+    }
+}
diff --git a/src/Backoffice/Courses/Application/LastVideo/SearchLastBackofficeCoursesQueryHandler.php b/src/Backoffice/Courses/Application/LastVideo/SearchLastBackofficeCoursesQueryHandler.php
new file mode 100644
index 000000000..398ff9741
--- /dev/null
+++ b/src/Backoffice/Courses/Application/LastVideo/SearchLastBackofficeCoursesQueryHandler.php
@@ -0,0 +1,20 @@
+<?php
+
+declare(strict_types=1);
+
+namespace CodelyTv\Backoffice\Courses\Application\LastVideo;
+
+use CodelyTv\Backoffice\Courses\Application\BackofficeCoursesResponse;
+use CodelyTv\Shared\Domain\Bus\Query\QueryHandler;
+
+final class SearchLastBackofficeCoursesQueryHandler implements QueryHandler
+{
+    public function __construct(private LastBackofficeCourseSearcher $searcher)
+    {
+    }
+
+    public function __invoke(): ?BackofficeCoursesResponse
+    {
+        return $this->searcher->__invoke();
+    }
+}
diff --git a/src/Backoffice/Courses/Domain/BackofficeCourseRepository.php b/src/Backoffice/Courses/Domain/BackofficeCourseRepository.php
index 1f8d82c40..1c4ab0cc4 100644
--- a/src/Backoffice/Courses/Domain/BackofficeCourseRepository.php
+++ b/src/Backoffice/Courses/Domain/BackofficeCourseRepository.php
@@ -4,6 +4,7 @@
 
 namespace CodelyTv\Backoffice\Courses\Domain;
 
+use CodelyTv\Mooc\Courses\Domain\Course;
 use CodelyTv\Shared\Domain\Criteria\Criteria;
 
 interface BackofficeCourseRepository
@@ -13,4 +14,6 @@ public function save(BackofficeCourse $course): void;
     public function searchAll(): array;
 
     public function matching(Criteria $criteria): array;
+
+    public function lastCourse(): ?Course;
 }
diff --git a/src/Backoffice/Courses/Infrastructure/Persistence/ElasticsearchBackofficeCourseRepository.php b/src/Backoffice/Courses/Infrastructure/Persistence/ElasticsearchBackofficeCourseRepository.php
index bc06eced7..082e19e9f 100644
--- a/src/Backoffice/Courses/Infrastructure/Persistence/ElasticsearchBackofficeCourseRepository.php
+++ b/src/Backoffice/Courses/Infrastructure/Persistence/ElasticsearchBackofficeCourseRepository.php
@@ -6,6 +6,7 @@
 
 use CodelyTv\Backoffice\Courses\Domain\BackofficeCourse;
 use CodelyTv\Backoffice\Courses\Domain\BackofficeCourseRepository;
+use CodelyTv\Mooc\Courses\Domain\Course;
 use CodelyTv\Shared\Domain\Criteria\Criteria;
 use CodelyTv\Shared\Infrastructure\Persistence\Elasticsearch\ElasticsearchRepository;
 use function Lambdish\Phunctional\map;
@@ -27,6 +28,12 @@ public function matching(Criteria $criteria): array
         return map($this->toCourse(), $this->searchByCriteria($criteria));
     }
 
+    public function lastCourse(): ?Course
+    {
+        $courseInPrimitive = $this->searchlastInelastic();
+        return $courseInPrimitive ? BackofficeCourse::fromPrimitives($courseInPrimitive) : null;
+    }
+
     protected function aggregateName(): string
     {
         return 'courses';
diff --git a/src/Backoffice/Courses/Infrastructure/Persistence/InMemoryCacheBackofficeCourseRepository.php b/src/Backoffice/Courses/Infrastructure/Persistence/InMemoryCacheBackofficeCourseRepository.php
index 70498e140..4ad27d7be 100644
--- a/src/Backoffice/Courses/Infrastructure/Persistence/InMemoryCacheBackofficeCourseRepository.php
+++ b/src/Backoffice/Courses/Infrastructure/Persistence/InMemoryCacheBackofficeCourseRepository.php
@@ -6,6 +6,7 @@
 
 use CodelyTv\Backoffice\Courses\Domain\BackofficeCourse;
 use CodelyTv\Backoffice\Courses\Domain\BackofficeCourseRepository;
+use CodelyTv\Mooc\Courses\Domain\Course;
 use CodelyTv\Shared\Domain\Criteria\Criteria;
 use function Lambdish\Phunctional\get;
 
@@ -33,6 +34,14 @@ public function matching(Criteria $criteria): array
         return get($criteria->serialize(), self::$matchingCache) ?: $this->searchMatchingAndFillCache($criteria);
     }
 
+    public function lastCourse(): Course
+    {
+        $lastCourse = end(self::$allCoursesCache);
+        reset(self::$allCoursesCache);
+
+        return $lastCourse;
+    }
+
     private function searchAllAndFillCache(): array
     {
         return self::$allCoursesCache = $this->repository->searchAll();
diff --git a/src/Backoffice/Courses/Infrastructure/Persistence/MySqlBackofficeCourseRepository.php b/src/Backoffice/Courses/Infrastructure/Persistence/MySqlBackofficeCourseRepository.php
index 8203a7fee..35bc9286f 100644
--- a/src/Backoffice/Courses/Infrastructure/Persistence/MySqlBackofficeCourseRepository.php
+++ b/src/Backoffice/Courses/Infrastructure/Persistence/MySqlBackofficeCourseRepository.php
@@ -6,6 +6,7 @@
 
 use CodelyTv\Backoffice\Courses\Domain\BackofficeCourse;
 use CodelyTv\Backoffice\Courses\Domain\BackofficeCourseRepository;
+use CodelyTv\Mooc\Courses\Domain\Course;
 use CodelyTv\Shared\Domain\Criteria\Criteria;
 use CodelyTv\Shared\Infrastructure\Persistence\Doctrine\DoctrineCriteriaConverter;
 use CodelyTv\Shared\Infrastructure\Persistence\Doctrine\DoctrineRepository;
@@ -28,4 +29,10 @@ public function matching(Criteria $criteria): array
 
         return $this->repository(BackofficeCourse::class)->matching($doctrineCriteria)->toArray();
     }
+
+    public function lastCourse(): ?Course
+    {
+        return $this->repository(BackofficeCourse::class)
+            ->findOneBy([],  ['id' => 'DESC']);
+    }
 }
diff --git a/src/Shared/Infrastructure/Persistence/Elasticsearch/ElasticsearchRepository.php b/src/Shared/Infrastructure/Persistence/Elasticsearch/ElasticsearchRepository.php
index c6b5a5cd1..2cdb77055 100644
--- a/src/Shared/Infrastructure/Persistence/Elasticsearch/ElasticsearchRepository.php
+++ b/src/Shared/Infrastructure/Persistence/Elasticsearch/ElasticsearchRepository.php
@@ -32,9 +32,15 @@ protected function persist(string $id, array $plainBody): void
         $this->client->persist($this->aggregateName(), $id, $plainBody);
     }
 
-    protected function searchAllInElastic(): array
+    protected function searchlastInelastic(): array
     {
-        return $this->searchRawElasticsearchQuery([]);
+        $courses = $this->searchRawElasticsearchQuery([
+            'body' => [
+                'size' => 1
+            ]
+        ]);
+
+        return $courses ? end($courses): [];
     }
 
     protected function searchRawElasticsearchQuery(array $params): array