Redis service

This commit is contained in:
2023-10-19 20:46:52 -03:00
parent 742c0327c2
commit dc217d876a
10 changed files with 228 additions and 97 deletions

View File

@ -0,0 +1,15 @@
<?php
namespace Incoviba\Common\Implement\Exception;
use Throwable;
use Exception;
class EmptyRedis extends Exception
{
public function __construct(string $key, ?Throwable $previous = null)
{
$message = "Redis key {$key} not found in database.";
$code = 750;
parent::__construct($message, $code, $previous);
}
}

View File

@ -9,6 +9,7 @@
"nyholm/psr7-server": "^1.0", "nyholm/psr7-server": "^1.0",
"php-di/php-di": "^7.0", "php-di/php-di": "^7.0",
"php-di/slim-bridge": "^3.4", "php-di/slim-bridge": "^3.4",
"predis/predis": "^2.2",
"slim/slim": "^4.11" "slim/slim": "^4.11"
}, },
"require-dev": { "require-dev": {

View File

@ -19,4 +19,11 @@ return [
return (new Incoviba\Service\Money())->register('uf', $mindicador) return (new Incoviba\Service\Money())->register('uf', $mindicador)
->register('ipc', $mindicador); ->register('ipc', $mindicador);
}, },
Predis\Client::class => function(ContainerInterface $container) {
return new Predis\Client([
'scheme' => 'tcp',
'host' => $container->get('REDIS_HOST'),
'port' => $container->get('REDIS_PORT')
]);
}
]; ];

View File

@ -1,6 +1,8 @@
<?php <?php
namespace Incoviba\Controller\API; namespace Incoviba\Controller\API;
use DateTimeImmutable;
use Incoviba\Common\Implement\Exception\EmptyRedis;
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use Incoviba\Common\Implement\Exception\EmptyResult; use Incoviba\Common\Implement\Exception\EmptyResult;
@ -10,7 +12,7 @@ use Incoviba\Service;
class Ventas class Ventas
{ {
use withJson; use withJson, withRedis;
public function proyecto(ServerRequestInterface $request, ResponseInterface $response, Repository\Venta $service): ResponseInterface public function proyecto(ServerRequestInterface $request, ResponseInterface $response, Repository\Venta $service): ResponseInterface
{ {
@ -46,29 +48,40 @@ class Ventas
} }
return $this->withJson($response, $output); return $this->withJson($response, $output);
} }
public function porFirmar(ServerRequestInterface $request, ResponseInterface $response, Service\Venta $ventaService): ResponseInterface public function porFirmar(ServerRequestInterface $request, ResponseInterface $response, Service\Venta $ventaService, Service\Redis $redisService): ResponseInterface
{ {
$body = $request->getBody(); $body = $request->getBody();
$json = json_decode($body->getContents()); $json = json_decode($body->getContents());
$proyecto_id = $json->proyecto_id; $proyecto_id = $json->proyecto_id;
$today = new DateTimeImmutable();
$redisKey = "promesas_por_firmar-{$proyecto_id}-{$today->format('Y-m-d')}";
$output = [ $output = [
'proyecto_id' => $proyecto_id, 'proyecto_id' => $proyecto_id,
'promesas' => 0 'promesas' => 0
]; ];
try {
$output = $this->fetchRedis($redisService, $redisKey);
} catch (EmptyRedis) {
try { try {
$ventas = $ventaService->getByProyecto($proyecto_id); $ventas = $ventaService->getByProyecto($proyecto_id);
$promesas = array_filter($ventas, function(Model\Venta $venta) { $promesas = array_filter($ventas, function(Model\Venta $venta) {
return $venta->currentEstado()->tipoEstadoVenta->descripcion === 'vigente'; return $venta->currentEstado()->tipoEstadoVenta->descripcion === 'vigente';
}); });
$output['promesas'] = count($promesas); $output['promesas'] = count($promesas);
$this->saveRedis($redisService, $redisKey, $output);
} catch (EmptyResult) {} } catch (EmptyResult) {}
}
return $this->withJson($response, $output); return $this->withJson($response, $output);
} }
public function escrituras(ServerRequestInterface $request, ResponseInterface $response, Service\Venta $ventaService, Service\Venta\Pago $pagoService): ResponseInterface public function escrituras(ServerRequestInterface $request, ResponseInterface $response, Service\Venta $ventaService, Service\Venta\Pago $pagoService, Service\Redis $redisService): ResponseInterface
{ {
$body = $request->getBody(); $body = $request->getBody();
$json = json_decode($body->getContents()); $json = json_decode($body->getContents());
$proyecto_id = $json->proyecto_id; $proyecto_id = $json->proyecto_id;
$today = new DateTimeImmutable();
$redisKey = "escrituras-{$proyecto_id}-{$today->format('Y-m-d')}";
$output = [ $output = [
'proyecto_id' => $proyecto_id, 'proyecto_id' => $proyecto_id,
'escrituras' => [ 'escrituras' => [
@ -77,6 +90,9 @@ class Ventas
'abonar' => 0 'abonar' => 0
] ]
]; ];
try {
$output = $this->fetchRedis($redisService, $redisKey);
} catch (EmptyRedis) {
try { try {
$ventas = $ventaService->getEscriturasByProyecto($proyecto_id); $ventas = $ventaService->getEscriturasByProyecto($proyecto_id);
$porFirmar = array_filter($ventas, function(Model\Venta $venta) { $porFirmar = array_filter($ventas, function(Model\Venta $venta) {
@ -106,7 +122,9 @@ class Ventas
}); });
$output['escrituras']['abonar'] = count($porAbonar); $output['escrituras']['abonar'] = count($porAbonar);
unset($porAbonar); unset($porAbonar);
$this->saveRedis($redisService, $redisKey, $output);
} catch (EmptyResult) {} } catch (EmptyResult) {}
}
return $this->withJson($response, $output); return $this->withJson($response, $output);
} }
public function comentarios(ServerRequestInterface $request, ResponseInterface $response, Service\Venta $service, Repository\Venta\Comentario $comentarioRepository, int $venta_id): ResponseInterface public function comentarios(ServerRequestInterface $request, ResponseInterface $response, Service\Venta $service, Repository\Venta\Comentario $comentarioRepository, int $venta_id): ResponseInterface

View File

@ -3,38 +3,59 @@ namespace Incoviba\Controller\API\Ventas;
use DateTimeImmutable; use DateTimeImmutable;
use DateInterval; use DateInterval;
use Incoviba\Common\Implement\Exception\EmptyResult; use Incoviba\Controller\API\withRedis;
use Incoviba\Controller\API\withJson;
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use Incoviba\Common\Implement\Exception\EmptyRedis;
use Incoviba\Common\Implement\Exception\EmptyResult;
use Incoviba\Controller\API\withJson;
use Incoviba\Repository; use Incoviba\Repository;
use Incoviba\Service; use Incoviba\Service;
class Cuotas class Cuotas
{ {
use withJson; use withJson, withRedis;
public function hoy(ServerRequestInterface $request, ResponseInterface $response, Repository\Venta\Cuota $cuotaRepository): ResponseInterface public function hoy(ServerRequestInterface $request, ResponseInterface $response, Repository\Venta\Cuota $cuotaRepository, Service\Redis $redisService): ResponseInterface
{ {
$today = new DateTimeImmutable();
$redisKey = "cuotas_hoy-{$today->format('Y-m-d')}";
$output = [ $output = [
'cuotas' => 0 'cuotas' => 0
]; ];
try {
$output['cuotas'] = $this->fetchRedis($redisService, $redisKey);
} catch (EmptyRedis) {
try { try {
$output['cuotas'] = count($cuotaRepository->fetchHoy()); $output['cuotas'] = count($cuotaRepository->fetchHoy());
$this->saveRedis($redisService, $redisKey, $output['cuotas']);
} catch (EmptyResult) {} } catch (EmptyResult) {}
}
return $this->withJson($response, $output); return $this->withJson($response, $output);
} }
public function pendiente(ServerRequestInterface $request, ResponseInterface $response, Repository\Venta\Cuota $cuotaRepository): ResponseInterface public function pendiente(ServerRequestInterface $request, ResponseInterface $response, Repository\Venta\Cuota $cuotaRepository, Service\Redis $redisService): ResponseInterface
{ {
$today = new DateTimeImmutable();
$redisKey = "cuotas_pendientes-{$today->format('Y-m-d')}";
$output = [ $output = [
'cuotas' => 0 'cuotas' => 0
]; ];
try {
$output['cuotas'] = $this->fetchRedis($redisService, $redisKey);
} catch (EmptyRedis) {
try { try {
$output['cuotas'] = count($cuotaRepository->fetchPendientes()); $output['cuotas'] = count($cuotaRepository->fetchPendientes());
$this->saveRedis($redisService, $redisKey, $output['cuotas']);
} catch (EmptyResult) {} } catch (EmptyResult) {}
}
return $this->withJson($response, $output); return $this->withJson($response, $output);
} }
public function porVencer(ServerRequestInterface $request, ResponseInterface $response, Repository\Venta\Cuota $cuotaRepository, Service\Format $formatService): ResponseInterface public function porVencer(ServerRequestInterface $request, ResponseInterface $response, Repository\Venta\Cuota $cuotaRepository, Service\Redis $redisService, Service\Format $formatService): ResponseInterface
{ {
$today = new DateTimeImmutable();
$redisKey = "cuotas_por_vencer-{$today->format('Y-m-d')}";
try {
$output = $this->fetchRedis($redisService, $redisKey);
} catch (EmptyRedis) {
$output = []; $output = [];
try { try {
$benchmark = [ $benchmark = [
@ -67,7 +88,9 @@ class Cuotas
} }
$benchmark['run'] = microtime(true) - $benchmark['start']; $benchmark['run'] = microtime(true) - $benchmark['start'];
error_log(var_export($benchmark,true)); error_log(var_export($benchmark,true));
$this->saveRedis($redisService, $redisKey, $output);
} catch (EmptyResult) {} } catch (EmptyResult) {}
}
return $this->withJson($response, ['cuotas' => $output]); return $this->withJson($response, ['cuotas' => $output]);
} }
} }

View File

@ -1,22 +1,29 @@
<?php <?php
namespace Incoviba\Controller\API\Ventas; namespace Incoviba\Controller\API\Ventas;
use DateTimeImmutable;
use Incoviba\Common\Implement\Exception\EmptyRedis;
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use Incoviba\Common\Implement\Exception\EmptyResult; use Incoviba\Common\Implement\Exception\EmptyResult;
use Incoviba\Controller\API\withJson; use Incoviba\Controller\API\withJson;
use Incoviba\Controller\API\withRedis;
use Incoviba\Model; use Incoviba\Model;
use Incoviba\Repository; use Incoviba\Repository;
use Incoviba\Service;
class Unidades class Unidades
{ {
use withJson; use withJson, withRedis;
public function disponibles(ServerRequestInterface $request, ResponseInterface $response, Repository\Venta\Unidad $unidadRepository, Repository\Proyecto\TipoUnidad $tipoUnidadRepository): ResponseInterface public function disponibles(ServerRequestInterface $request, ResponseInterface $response, Repository\Venta\Unidad $unidadRepository, Repository\Proyecto\TipoUnidad $tipoUnidadRepository, Service\Redis $redisService): ResponseInterface
{ {
$body = $request->getBody(); $body = $request->getBody();
$json = json_decode($body->getContents()); $json = json_decode($body->getContents());
$proyecto_id = $json->proyecto_id; $proyecto_id = $json->proyecto_id;
$today = new DateTimeImmutable();
$redisKey = "unidades_disponibles-{$proyecto_id}-{$today->format('Y-m-d')}";
$output = [ $output = [
'proyecto_id' => $proyecto_id, 'proyecto_id' => $proyecto_id,
'unidades' => [ 'unidades' => [
@ -30,6 +37,9 @@ class Unidades
'bodegas' => 0, 'bodegas' => 0,
] ]
]; ];
try {
$output = $this->fetchRedis($redisService, $redisKey);
} catch (EmptyRedis) {
try { try {
$totalUnidades = $unidadRepository->fetchByProyecto($proyecto_id); $totalUnidades = $unidadRepository->fetchByProyecto($proyecto_id);
$unidades = $unidadRepository->fetchDisponiblesByProyecto($proyecto_id); $unidades = $unidadRepository->fetchDisponiblesByProyecto($proyecto_id);
@ -50,7 +60,9 @@ class Unidades
} }
$output['unidades']["{$tipoUnidad->descripcion}s"] = count($tempUnidades); $output['unidades']["{$tipoUnidad->descripcion}s"] = count($tempUnidades);
} }
$this->saveRedis($redisService, $redisKey, $output);
} catch (EmptyResult) {} } catch (EmptyResult) {}
}
return $this->withJson($response, $output); return $this->withJson($response, $output);
} }
} }

View File

@ -5,7 +5,7 @@ use Psr\Http\Message\ResponseInterface;
trait withJson trait withJson
{ {
public function withJson(ResponseInterface $response, array $data = []): ResponseInterface public function withJson(ResponseInterface $response, array|object $data = []): ResponseInterface
{ {
$response->getBody()->write(json_encode($data)); $response->getBody()->write(json_encode($data));
return $response->withHeader('Content-Type', 'application/json'); return $response->withHeader('Content-Type', 'application/json');

View File

@ -0,0 +1,24 @@
<?php
namespace Incoviba\Controller\API;
use Incoviba\Common\Implement\Exception\EmptyRedis;
use Incoviba\Service;
trait withRedis
{
public function fetchRedis(Service\Redis $redisService, string $redisKey): mixed
{
$jsonString = $redisService->get($redisKey);
if ($jsonString === null) {
throw new EmptyRedis($redisKey);
}
return json_decode($jsonString);
}
public function saveRedis(Service\Redis $redisService, string $redisKey, mixed $value): void
{
if (is_array($value) or is_object($value)) {
$value = json_encode($value);
}
$redisService->set($redisKey, $value);
}
}

18
app/src/Service/Redis.php Normal file
View File

@ -0,0 +1,18 @@
<?php
namespace Incoviba\Service;
use Predis\Client;
class Redis
{
public function __construct(protected Client $client) {}
public function get(string $name): mixed
{
return $this->client->get($name);
}
public function set(string $name, mixed $value): void
{
$this->client->set($name, $value);
}
}

View File

@ -47,6 +47,18 @@ services:
- default - default
- adminer_network - adminer_network
redis:
profiles:
- cache
image: redis
container_name: incoviba_redis
<<: *restart
env_file: ${APP_PATH:-.}/.redis.env
volumes:
- incoviba_redis:/data
ports:
- "63790:6379"
python: python:
profiles: profiles:
- python - python
@ -74,6 +86,7 @@ services:
volumes: volumes:
dbdata: {} dbdata: {}
incoviba_redis: {}
networks: networks:
adminer_network: {} adminer_network: {}