From aeeca65d94db44d36b6a100383e3f0229b3b2077 Mon Sep 17 00:00:00 2001 From: Juan Pablo Vial Date: Mon, 3 Mar 2025 21:41:43 -0300 Subject: [PATCH] Correcciones --- app/common/Ideal/Repository.php | 4 +- .../Implement/Repository/Mapper/DateTime.php | 13 ++++- app/setup/setups/logs.php | 12 +++-- app/src/Controller/API/withJson.php | 47 ++++++++++++++++++- app/src/Model/Proyecto/Broker/Contract.php | 14 ++++-- .../Model/Proyecto/Broker/Contract/State.php | 8 ++-- .../Repository/Proyecto/Broker/Contract.php | 36 +++++++------- .../Proyecto/Broker/Contract/State.php | 21 +++++++-- app/src/Service/Proyecto/Broker/Contract.php | 10 ++-- 9 files changed, 122 insertions(+), 43 deletions(-) diff --git a/app/common/Ideal/Repository.php b/app/common/Ideal/Repository.php index e8f9bee..9a46692 100644 --- a/app/common/Ideal/Repository.php +++ b/app/common/Ideal/Repository.php @@ -204,9 +204,11 @@ abstract class Repository implements Define\Repository { try { $result = $this->connection->execute($query, $data)->fetch(PDO::FETCH_ASSOC); + if ($result === false) { + throw new EmptyResult($query); + } } catch (PDOException $exception) { throw new EmptyResult($query, $exception); - } return $this->load($result); } diff --git a/app/common/Implement/Repository/Mapper/DateTime.php b/app/common/Implement/Repository/Mapper/DateTime.php index bbeb388..10c851d 100644 --- a/app/common/Implement/Repository/Mapper/DateTime.php +++ b/app/common/Implement/Repository/Mapper/DateTime.php @@ -2,6 +2,7 @@ namespace Incoviba\Common\Implement\Repository\Mapper; use DateTimeImmutable; +use DateMalformedStringException; use Incoviba\Common\Implement\Repository\Mapper; class DateTime extends Mapper @@ -9,7 +10,17 @@ class DateTime extends Mapper public function __construct(string $column, ?string $property = null) { $this->setFunction(function($data) use ($column) { - return new DateTimeImmutable($data[$column] ?? ''); + if (!isset($data[$column])) { + return null; + } + if (is_a($data[$column], DateTimeImmutable::class)) { + return $data[$column]; + } + try { + return new DateTimeImmutable($data[$column] ?? ''); + } catch (DateMalformedStringException) { + return new DateTimeImmutable(); + } }); if ($property !== null) { $this->setProperty($property); diff --git a/app/setup/setups/logs.php b/app/setup/setups/logs.php index fe62d82..217d91c 100644 --- a/app/setup/setups/logs.php +++ b/app/setup/setups/logs.php @@ -2,23 +2,27 @@ use Psr\Container\ContainerInterface; return [ + Monolog\Formatter\LineFormatter::class => function(ContainerInterface $container) { + return (new Monolog\Formatter\LineFormatter(null, null, false, false, true)) + ->setBasePath('/code/'); + }, Psr\Log\LoggerInterface::class => function(ContainerInterface $container) { return new Monolog\Logger('incoviba', [ new Monolog\Handler\FilterHandler( (new Monolog\Handler\RotatingFileHandler('/logs/error.log', 10)) - ->setFormatter(new Monolog\Formatter\LineFormatter(null, null, false, false, true)), + ->setFormatter($container->get(Monolog\Formatter\LineFormatter::class)), Monolog\Level::Error, Monolog\Level::Error ), new Monolog\Handler\FilterHandler( (new Monolog\Handler\RotatingFileHandler('/logs/critical.log', 10)) - ->setFormatter(new Monolog\Formatter\LineFormatter(null, null, false, false, true)), + ->setFormatter($container->get(Monolog\Formatter\LineFormatter::class)), Monolog\Level::Critical ), new Monolog\Handler\FilterHandler( ($container->has('ENVIRONMENT') and $container->get('ENVIRONMENT') === 'development') ? (new Monolog\Handler\RotatingFileHandler('/logs/debug.log', 10)) - ->setFormatter(new Monolog\Formatter\LineFormatter(null, null, false, false, true)) + ->setFormatter($container->get(Monolog\Formatter\LineFormatter::class)) : new Monolog\Handler\RedisHandler($container->get(Predis\ClientInterface::class), 'logs:notices'), Monolog\Level::Debug, Monolog\Level::Info @@ -26,7 +30,7 @@ return [ new Monolog\Handler\FilterHandler( ($container->has('ENVIRONMENT') and $container->get('ENVIRONMENT') === 'development') ? (new Monolog\Handler\RotatingFileHandler('/logs/notices.log', 10)) - ->setFormatter(new Monolog\Formatter\LineFormatter(null, null, false, false, true)) + ->setFormatter($container->get(Monolog\Formatter\LineFormatter::class)) : (new Incoviba\Common\Implement\Log\MySQLHandler($container->get(Incoviba\Common\Define\Connection::class))) ->setFormatter(new Incoviba\Common\Implement\Log\PDOFormatter()), Monolog\Level::Notice, diff --git a/app/src/Controller/API/withJson.php b/app/src/Controller/API/withJson.php index 3d769ea..35a91f9 100644 --- a/app/src/Controller/API/withJson.php +++ b/app/src/Controller/API/withJson.php @@ -16,9 +16,10 @@ trait withJson return [ 'code' => $exception->getCode(), 'message' => $exception->getMessage(), - 'file' => $exception->getFile(), + 'file' => $this->parseFilename($exception->getFile()), 'line' => $exception->getLine(), - 'trace' => $exception->getTraceAsString() + 'trace' => $this->parseStack($exception->getTraceAsString()), + 'previous' => ($exception->getPrevious() instanceof Throwable) ? $this->parseError($exception->getPrevious()) : '' ]; } public function withError(ResponseInterface $response, Throwable $exception): ResponseInterface @@ -37,4 +38,46 @@ trait withJson return $response; } + protected function parseFilename(string $filename): string + { + return str_replace('/code/', '', $filename); + } + protected function parseStack(string|array $stack): array + { + if (is_string($stack)) { + $stack = explode(PHP_EOL, $stack); + } + $output = []; + foreach ($stack as $line) { + $index = substr($line, 1, strpos($line, ' ') - 1); + $content = substr($line, strpos($line, ' ') + 1); + if (str_contains($line, '{main}')) { + $output [] = [ + 'stack' => $index, + 'message' => $content + ]; + continue; + } + if (str_starts_with($content, '[internal function]')) { + $content = substr($content, strlen('[internal function]: ')); + $output [] = [ + 'stack' => $index, + 'type' => 'internal function', + 'message' => $content + ]; + continue; + } + $fileData = substr($content, 0, strpos($content, ' ')); + $file = substr($fileData, 0, strrpos($fileData, '(')); + $fileLine = (int) substr($fileData, strrpos($fileData, '(') + 1, -2); + $error = substr($content, strlen($fileData) + 1); + $output []= [ + 'stack' => $index, + 'file' => $this->parseFilename($file), + 'line' => $fileLine, + 'error' => $error + ]; + } + return $output; + } } diff --git a/app/src/Model/Proyecto/Broker/Contract.php b/app/src/Model/Proyecto/Broker/Contract.php index e064694..3d63ed3 100644 --- a/app/src/Model/Proyecto/Broker/Contract.php +++ b/app/src/Model/Proyecto/Broker/Contract.php @@ -13,17 +13,21 @@ class Contract extends Common\Ideal\Model public function states(): array { - if (!isset($this->states)) { + if (!isset($this->states) or count($this->states) === 0) { $this->states = $this->runFactory('states'); } return $this->states; } - protected Contract\State $current; - public function currentState(): Contract\State + protected ?Contract\State $current; + public function currentState(): ?Contract\State { if (!isset($this->current)) { - $this->current = last($this->states()); + try { + $this->current = last($this->states()); + } catch (\TypeError $error) { + $this->current = null; + } } return $this->current; } @@ -38,4 +42,4 @@ class Contract extends Common\Ideal\Model 'current' => $this->currentState(), ]; } -} \ No newline at end of file +} diff --git a/app/src/Model/Proyecto/Broker/Contract/State.php b/app/src/Model/Proyecto/Broker/Contract/State.php index f684d60..c773d6d 100644 --- a/app/src/Model/Proyecto/Broker/Contract/State.php +++ b/app/src/Model/Proyecto/Broker/Contract/State.php @@ -9,7 +9,7 @@ class State extends Common\Ideal\Model { public Model\Proyecto\Broker\Contract $contract; public DateTimeInterface $date; - public int $type; + public State\Type $type; protected function jsonComplement(): array { @@ -17,9 +17,9 @@ class State extends Common\Ideal\Model 'contract_id' => $this->contract->id, 'date' => $this->date->format('Y-m-d'), 'type' => [ - 'id' => $this->type, - 'description' => State\Type::name($this->type) + 'id' => $this->type->value, + 'description' => $this->type->name ] ]; } -} \ No newline at end of file +} diff --git a/app/src/Repository/Proyecto/Broker/Contract.php b/app/src/Repository/Proyecto/Broker/Contract.php index 8e6b8c2..66d1bd5 100644 --- a/app/src/Repository/Proyecto/Broker/Contract.php +++ b/app/src/Repository/Proyecto/Broker/Contract.php @@ -27,10 +27,10 @@ class Contract extends Common\Ideal\Repository return $this->brokerRepository->fetchById($data['broker_rut']); }) ) - ->register('proyecto_id', (new Common\Implement\Repository\Mapper()) - ->setProperty('proyecto') + ->register('project_id', (new Common\Implement\Repository\Mapper()) + ->setProperty('project') ->setFunction(function($data) { - return $this->proyectoRepository->fetchById($data['proyecto_id']); + return $this->proyectoRepository->fetchById($data['project_id']); }) ); return $this->parseData(new Model\Proyecto\Broker\Contract(), $data, $map); @@ -38,8 +38,8 @@ class Contract extends Common\Ideal\Repository public function save(Common\Define\Model $model): Model\Proyecto\Broker\Contract { $model->id = $this->saveNew( - ['broker_rut', 'proyecto_id', 'commission'], - [$model->broker->rut, $model->proyecto->id, $model->commission]); + ['broker_rut', 'project_id', 'commission'], + [$model->broker->rut, $model->project->id, $model->commission]); return $model; } @@ -51,7 +51,7 @@ class Contract extends Common\Ideal\Repository */ public function edit(Common\Define\Model $model, array $new_data): Model\Proyecto\Broker\Contract { - return $this->update($model, ['broker_rut', 'proyecto_id', 'commission'], $new_data); + return $this->update($model, ['broker_rut', 'project_id', 'commission'], $new_data); } /** @@ -69,17 +69,17 @@ class Contract extends Common\Ideal\Repository } /** - * @param int $proyecto_id + * @param int $projectId * @return array * @throws Common\Implement\Exception\EmptyResult */ - public function fetchByProject(int $proyecto_id): array + public function fetchByProject(int $projectId): array { $query = $this->connection->getQueryBuilder() ->select() ->from($this->getTable()) - ->where('proyecto_id = :proyecto_id'); - return $this->fetchMany($query, ['proyecto_id' => $proyecto_id]); + ->where('project_id = :project_id'); + return $this->fetchMany($query, ['project_id' => $projectId]); } /** @@ -98,38 +98,38 @@ class Contract extends Common\Ideal\Repository } /** - * @param int $proyecto_id + * @param int $projectId * @return array * @throws Common\Implement\Exception\EmptyResult */ - public function fetchActiveByProject(int $proyecto_id): array + public function fetchActiveByProject(int $projectId): array { $query = $this->connection->getQueryBuilder() ->select('a.*') ->from("{$this->getTable()} a") ->joined($this->statusJoin()) ->where('a.proyecto_id = :proyecto_id AND bcs.state = :state'); - return $this->fetchMany($query, ['proyecto_id' => $proyecto_id, 'state' => Model\Proyecto\Broker\Contract\Type::ACTIVE]); + return $this->fetchMany($query, ['proyecto_id' => $projectId, 'state' => Model\Proyecto\Broker\Contract\State\Type::ACTIVE->value]); } /** - * @param int $proyecto_id + * @param int $projectId * @param int $brokerRut * @return Model\Proyecto\Broker\Contract * @throws Common\Implement\Exception\EmptyResult */ - public function fetchActiveByProjectAndBroker(int $proyecto_id, int $brokerRut): Model\Proyecto\Broker\Contract + public function fetchActiveByProjectAndBroker(int $projectId, int $brokerRut): Model\Proyecto\Broker\Contract { $query = $this->connection->getQueryBuilder() ->select('a.*') ->from("{$this->getTable()} a") ->joined($this->statusJoin()) - ->where('a.proyecto_id = :proyecto_id AND a.broker_rut = :broker_rut AND bcs.state = :state'); - return $this->fetchOne($query, ['proyecto_id' => $proyecto_id, 'broker_rut' => $brokerRut, 'state' => Model\Proyecto\Broker\Contract\Type::ACTIVE]); + ->where('a.project_id = :project_id AND a.broker_rut = :broker_rut AND bcs.type = :state'); + return $this->fetchOne($query, ['project_id' => $projectId, 'broker_rut' => $brokerRut, 'state' => Model\Proyecto\Broker\Contract\State\Type::ACTIVE->value]); } protected function statusJoin(): string { - return 'INNER JOIN (SELECT bcs1.* FROM broker_contract_states bcs1 INNER JOIN (SELECT MAX(id) AS id, contract_id FROM broker_contract_states GROUP BY contract_id) bcs0 ON bcs0.id = bcs1.id) bcs ON bcs.contract = a.id'; + return 'INNER JOIN (SELECT bcs1.* FROM broker_contract_states bcs1 INNER JOIN (SELECT MAX(id) AS id, contract_id FROM broker_contract_states GROUP BY contract_id) bcs0 ON bcs0.id = bcs1.id) bcs ON bcs.contract_id = a.id'; } } diff --git a/app/src/Repository/Proyecto/Broker/Contract/State.php b/app/src/Repository/Proyecto/Broker/Contract/State.php index 89536b3..1fab483 100644 --- a/app/src/Repository/Proyecto/Broker/Contract/State.php +++ b/app/src/Repository/Proyecto/Broker/Contract/State.php @@ -14,23 +14,27 @@ class State extends Common\Ideal\Repository public function getTable(): string { - return 'brokers_contract_states'; + return 'broker_contract_states'; } public function create(?array $data = null): Model\Proyecto\Broker\Contract\State { - $map = (new Common\Implement\Repository\MapperParser(['type'])) + $map = (new Common\Implement\Repository\MapperParser()) ->register('contract_id', (new Common\Implement\Repository\Mapper()) ->setProperty('contract') ->setFunction(function($data) { return $this->contractRepository->fetchById($data['contract_id']); })) + ->register('type', (new Common\Implement\Repository\Mapper()) + ->setFunction(function($data) { + return Model\Proyecto\Broker\Contract\State\Type::from($data['type']); + })) ->register('date', new Common\Implement\Repository\Mapper\DateTime('date')); return $this->parseData(new Model\Proyecto\Broker\Contract\State(), $data, $map); } public function save(Common\Define\Model $model): Model\Proyecto\Broker\Contract\State { - $model->id = $this->saveNew(['contract_id', 'date', 'type'], [$model->contract->id, $model->date->format('Y-m-d'), $model->type]); + $model->id = $this->saveNew(['contract_id', 'date', 'type'], [$model->contract->id, $model->date->format('Y-m-d'), $model->type->value]); return $model; } public function edit(Common\Define\Model $model, array $new_data): Model\Proyecto\Broker\Contract\State @@ -38,6 +42,11 @@ class State extends Common\Ideal\Repository return $this->update($model, ['contract_id', 'date', 'type'], $new_data); } + /** + * @param int $contract_id + * @return array + * @throws Common\Implement\Exception\EmptyResult + */ public function fetchByContract(int $contract_id): array { $query = $this->connection->getQueryBuilder() @@ -46,6 +55,12 @@ class State extends Common\Ideal\Repository ->where('contract_id = :contract_id'); return $this->fetchMany($query, ['contract_id' => $contract_id]); } + + /** + * @param int $contract_id + * @return Model\Proyecto\Broker\Contract\State + * @throws Common\Implement\Exception\EmptyResult + */ public function fetchActiveByContract(int $contract_id): Model\Proyecto\Broker\Contract\State { $query = $this->connection->getQueryBuilder() diff --git a/app/src/Service/Proyecto/Broker/Contract.php b/app/src/Service/Proyecto/Broker/Contract.php index 15e6959..c23e3b8 100644 --- a/app/src/Service/Proyecto/Broker/Contract.php +++ b/app/src/Service/Proyecto/Broker/Contract.php @@ -32,7 +32,7 @@ class Contract extends Ideal\Service public function getByBroker(int $broker_rut): array { try { - return array_map([$this, 'broker'], $this->contractRepository->fetchByBroker($broker_rut)); + return array_map([$this, 'process'], $this->contractRepository->fetchByBroker($broker_rut)); } catch (Implement\Exception\EmptyResult $exception) { throw new ServiceAction\Read(__CLASS__, $exception); } @@ -56,14 +56,14 @@ class Contract extends Ideal\Service public function add(array $data): Model\Proyecto\Broker\Contract { try { - return $this->process($this->contractRepository->fetchActiveByProjectAndBroker($data['proyecto_id'], $data['broker_rut'])); + return $this->process($this->contractRepository->fetchActiveByProjectAndBroker($data['project_id'], $data['broker_rut'])); } catch (Implement\Exception\EmptyResult) {} try { $filteredData = $this->contractRepository->filterData($data); $contract = $this->contractRepository->create($filteredData); $contract = $this->contractRepository->save($contract); - $type = Model\Proyecto\Broker\Contract\State\Type::ACTIVE; + $type = Model\Proyecto\Broker\Contract\State\Type::ACTIVE->value; $date = new DateTimeImmutable(); if (isset($data['date'])) { try { @@ -125,9 +125,9 @@ class Contract extends Ideal\Service $contract->addFactory('states', (new Implement\Repository\Factory()) ->setCallable([$this->stateRepository, 'fetchByContract']) ->setArgs(['contract_id' => $contract->id])); - $contract->addFactory('currentState', (new Implement\Repository\Factory()) + /*$contract->addFactory('currentState', (new Implement\Repository\Factory()) ->setCallable([$this->stateRepository, 'fetchActiveByContract']) - ->setArgs(['contract_id' => $contract->id])); + ->setArgs(['contract_id' => $contract->id]));*/ return $contract; } }