Timeline 👉 2nd MVP

This commit is contained in:
theUniC
2021-11-15 15:53:31 +01:00
parent ae4f371462
commit 7362cce29a
7 changed files with 115 additions and 56 deletions

View File

@@ -1,54 +0,0 @@
<?php
declare(strict_types=1);
namespace App\API\DataProvider;
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
use App\API\Resources\Timeline;
use Elasticsearch\Client as Elasticsearch;
use Ramsey\Uuid\Uuid;
final class TimelineDataProvider implements ItemDataProviderInterface, RestrictedDataProviderInterface
{
public function __construct(
private Elasticsearch $elasticsearch
) {
}
/** @inheritDoc */
public function getItem(string $resourceClass, $id, string $operationName = null, array $context = []): Timeline
{
$timeline = new Timeline();
$timeline->id = Uuid::fromString($id);
$timeline->cheeps = [];
$indexName = 'timelines_' . (string)$id;
if (!$this->elasticsearch->indices()->exists(['index' => $indexName])) {
return $timeline;
}
$result = $this->elasticsearch->search([
'index' => $indexName,
'body' => [
'sort' => [
'cheep_date' => ['order' => 'desc']
],
'query' => [
'match_all' => new \stdClass()
]
]
]);
$timeline->cheeps = $result['hits']['hits'];
return $timeline;
}
public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
{
return Timeline::class === $resourceClass;
}
}

View File

@@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
namespace App\Controller;
use Cheeper\Application\Query\Timeline\Timeline;
use Cheeper\Chapter6\Application\Query\QueryBus;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\SerializerInterface;
final class GetTimelineController extends AbstractController
{
#[Route(path: "/api/timelines/{id}", methods: ["GET"])]
public function __invoke(string $id, QueryBus $queryBus, SerializerInterface $serializer): Response
{
$timeline = $queryBus->query(
Timeline::fromArray(['authorId' => $id])
);
return new JsonResponse(
$serializer->serialize($timeline, 'json'),
json: true
);
}
}

View File

@@ -2,10 +2,12 @@
declare(strict_types=1);
namespace Cheeper\Application\Query;
namespace Cheeper\Application\Query\Timeline;
use Cheeper\Chapter6\Application\Query\Query;
//snippet timeline-query
final class Timeline
final class Timeline implements Query
{
public static function fromArray(array $array): self
{

View File

@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace Cheeper\Application\Query\Timeline;
final class TimelineHandler
{
public function __construct(
private TimelineReadLayer $timelineReadLayer
) {
}
public function __invoke(Timeline $query): TimelineResponse
{
return new TimelineResponse(
$this->timelineReadLayer->byAuthorId($query->authorId())
);
}
}

View File

@@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace Cheeper\Application\Query\Timeline;
interface TimelineReadLayer
{
public function byAuthorId(string $authorId): array;
}

View File

@@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Cheeper\Application\Query\Timeline;
final class TimelineResponse
{
public function __construct(
public array $cheeps
) {
}
}

View File

@@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace Cheeper\Infrastructure\Query;
use Elasticsearch\Client;
use Cheeper\Application\Query\Timeline\TimelineReadLayer;
final class ElasticsearchTimelineReadLayer implements TimelineReadLayer
{
public function __construct(
private Client $elasticsearch
) {
}
public function byAuthorId(string $authorId): array
{
$indexName = 'timelines_' . $authorId;
if (!$this->elasticsearch->indices()->exists(['index' => $indexName])) {
return [];
}
$result = $this->elasticsearch->search([
'index' => $indexName,
'body' => [
'sort' => [
'cheep_date' => ['order' => 'desc']
],
'query' => [
'match_all' => new \stdClass()
]
]
]);
return $result['hits']['hits'] ?? [];
}
}