Correcciones

This commit is contained in:
Juan Pablo Vial
2025-03-03 21:41:43 -03:00
parent 5f69069aa0
commit aeeca65d94
9 changed files with 122 additions and 43 deletions

View File

@ -204,9 +204,11 @@ abstract class Repository implements Define\Repository
{ {
try { try {
$result = $this->connection->execute($query, $data)->fetch(PDO::FETCH_ASSOC); $result = $this->connection->execute($query, $data)->fetch(PDO::FETCH_ASSOC);
if ($result === false) {
throw new EmptyResult($query);
}
} catch (PDOException $exception) { } catch (PDOException $exception) {
throw new EmptyResult($query, $exception); throw new EmptyResult($query, $exception);
} }
return $this->load($result); return $this->load($result);
} }

View File

@ -2,6 +2,7 @@
namespace Incoviba\Common\Implement\Repository\Mapper; namespace Incoviba\Common\Implement\Repository\Mapper;
use DateTimeImmutable; use DateTimeImmutable;
use DateMalformedStringException;
use Incoviba\Common\Implement\Repository\Mapper; use Incoviba\Common\Implement\Repository\Mapper;
class DateTime extends Mapper class DateTime extends Mapper
@ -9,7 +10,17 @@ class DateTime extends Mapper
public function __construct(string $column, ?string $property = null) public function __construct(string $column, ?string $property = null)
{ {
$this->setFunction(function($data) use ($column) { $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) { if ($property !== null) {
$this->setProperty($property); $this->setProperty($property);

View File

@ -2,23 +2,27 @@
use Psr\Container\ContainerInterface; use Psr\Container\ContainerInterface;
return [ 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) { Psr\Log\LoggerInterface::class => function(ContainerInterface $container) {
return new Monolog\Logger('incoviba', [ return new Monolog\Logger('incoviba', [
new Monolog\Handler\FilterHandler( new Monolog\Handler\FilterHandler(
(new Monolog\Handler\RotatingFileHandler('/logs/error.log', 10)) (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,
Monolog\Level::Error Monolog\Level::Error
), ),
new Monolog\Handler\FilterHandler( new Monolog\Handler\FilterHandler(
(new Monolog\Handler\RotatingFileHandler('/logs/critical.log', 10)) (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 Monolog\Level::Critical
), ),
new Monolog\Handler\FilterHandler( new Monolog\Handler\FilterHandler(
($container->has('ENVIRONMENT') and $container->get('ENVIRONMENT') === 'development') ($container->has('ENVIRONMENT') and $container->get('ENVIRONMENT') === 'development')
? (new Monolog\Handler\RotatingFileHandler('/logs/debug.log', 10)) ? (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'), : new Monolog\Handler\RedisHandler($container->get(Predis\ClientInterface::class), 'logs:notices'),
Monolog\Level::Debug, Monolog\Level::Debug,
Monolog\Level::Info Monolog\Level::Info
@ -26,7 +30,7 @@ return [
new Monolog\Handler\FilterHandler( new Monolog\Handler\FilterHandler(
($container->has('ENVIRONMENT') and $container->get('ENVIRONMENT') === 'development') ($container->has('ENVIRONMENT') and $container->get('ENVIRONMENT') === 'development')
? (new Monolog\Handler\RotatingFileHandler('/logs/notices.log', 10)) ? (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))) : (new Incoviba\Common\Implement\Log\MySQLHandler($container->get(Incoviba\Common\Define\Connection::class)))
->setFormatter(new Incoviba\Common\Implement\Log\PDOFormatter()), ->setFormatter(new Incoviba\Common\Implement\Log\PDOFormatter()),
Monolog\Level::Notice, Monolog\Level::Notice,

View File

@ -16,9 +16,10 @@ trait withJson
return [ return [
'code' => $exception->getCode(), 'code' => $exception->getCode(),
'message' => $exception->getMessage(), 'message' => $exception->getMessage(),
'file' => $exception->getFile(), 'file' => $this->parseFilename($exception->getFile()),
'line' => $exception->getLine(), '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 public function withError(ResponseInterface $response, Throwable $exception): ResponseInterface
@ -37,4 +38,46 @@ trait withJson
return $response; 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;
}
} }

View File

@ -13,17 +13,21 @@ class Contract extends Common\Ideal\Model
public function states(): array public function states(): array
{ {
if (!isset($this->states)) { if (!isset($this->states) or count($this->states) === 0) {
$this->states = $this->runFactory('states'); $this->states = $this->runFactory('states');
} }
return $this->states; return $this->states;
} }
protected Contract\State $current; protected ?Contract\State $current;
public function currentState(): Contract\State public function currentState(): ?Contract\State
{ {
if (!isset($this->current)) { if (!isset($this->current)) {
$this->current = last($this->states()); try {
$this->current = last($this->states());
} catch (\TypeError $error) {
$this->current = null;
}
} }
return $this->current; return $this->current;
} }
@ -38,4 +42,4 @@ class Contract extends Common\Ideal\Model
'current' => $this->currentState(), 'current' => $this->currentState(),
]; ];
} }
} }

View File

@ -9,7 +9,7 @@ class State extends Common\Ideal\Model
{ {
public Model\Proyecto\Broker\Contract $contract; public Model\Proyecto\Broker\Contract $contract;
public DateTimeInterface $date; public DateTimeInterface $date;
public int $type; public State\Type $type;
protected function jsonComplement(): array protected function jsonComplement(): array
{ {
@ -17,9 +17,9 @@ class State extends Common\Ideal\Model
'contract_id' => $this->contract->id, 'contract_id' => $this->contract->id,
'date' => $this->date->format('Y-m-d'), 'date' => $this->date->format('Y-m-d'),
'type' => [ 'type' => [
'id' => $this->type, 'id' => $this->type->value,
'description' => State\Type::name($this->type) 'description' => $this->type->name
] ]
]; ];
} }
} }

View File

@ -27,10 +27,10 @@ class Contract extends Common\Ideal\Repository
return $this->brokerRepository->fetchById($data['broker_rut']); return $this->brokerRepository->fetchById($data['broker_rut']);
}) })
) )
->register('proyecto_id', (new Common\Implement\Repository\Mapper()) ->register('project_id', (new Common\Implement\Repository\Mapper())
->setProperty('proyecto') ->setProperty('project')
->setFunction(function($data) { ->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); 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 public function save(Common\Define\Model $model): Model\Proyecto\Broker\Contract
{ {
$model->id = $this->saveNew( $model->id = $this->saveNew(
['broker_rut', 'proyecto_id', 'commission'], ['broker_rut', 'project_id', 'commission'],
[$model->broker->rut, $model->proyecto->id, $model->commission]); [$model->broker->rut, $model->project->id, $model->commission]);
return $model; 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 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 * @return array
* @throws Common\Implement\Exception\EmptyResult * @throws Common\Implement\Exception\EmptyResult
*/ */
public function fetchByProject(int $proyecto_id): array public function fetchByProject(int $projectId): array
{ {
$query = $this->connection->getQueryBuilder() $query = $this->connection->getQueryBuilder()
->select() ->select()
->from($this->getTable()) ->from($this->getTable())
->where('proyecto_id = :proyecto_id'); ->where('project_id = :project_id');
return $this->fetchMany($query, ['proyecto_id' => $proyecto_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 * @return array
* @throws Common\Implement\Exception\EmptyResult * @throws Common\Implement\Exception\EmptyResult
*/ */
public function fetchActiveByProject(int $proyecto_id): array public function fetchActiveByProject(int $projectId): array
{ {
$query = $this->connection->getQueryBuilder() $query = $this->connection->getQueryBuilder()
->select('a.*') ->select('a.*')
->from("{$this->getTable()} a") ->from("{$this->getTable()} a")
->joined($this->statusJoin()) ->joined($this->statusJoin())
->where('a.proyecto_id = :proyecto_id AND bcs.state = :state'); ->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 * @param int $brokerRut
* @return Model\Proyecto\Broker\Contract * @return Model\Proyecto\Broker\Contract
* @throws Common\Implement\Exception\EmptyResult * @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() $query = $this->connection->getQueryBuilder()
->select('a.*') ->select('a.*')
->from("{$this->getTable()} a") ->from("{$this->getTable()} a")
->joined($this->statusJoin()) ->joined($this->statusJoin())
->where('a.proyecto_id = :proyecto_id AND a.broker_rut = :broker_rut AND bcs.state = :state'); ->where('a.project_id = :project_id AND a.broker_rut = :broker_rut AND bcs.type = :state');
return $this->fetchOne($query, ['proyecto_id' => $proyecto_id, 'broker_rut' => $brokerRut, 'state' => Model\Proyecto\Broker\Contract\Type::ACTIVE]); return $this->fetchOne($query, ['project_id' => $projectId, 'broker_rut' => $brokerRut, 'state' => Model\Proyecto\Broker\Contract\State\Type::ACTIVE->value]);
} }
protected function statusJoin(): string 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';
} }
} }

View File

@ -14,23 +14,27 @@ class State extends Common\Ideal\Repository
public function getTable(): string public function getTable(): string
{ {
return 'brokers_contract_states'; return 'broker_contract_states';
} }
public function create(?array $data = null): Model\Proyecto\Broker\Contract\State 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()) ->register('contract_id', (new Common\Implement\Repository\Mapper())
->setProperty('contract') ->setProperty('contract')
->setFunction(function($data) { ->setFunction(function($data) {
return $this->contractRepository->fetchById($data['contract_id']); 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')); ->register('date', new Common\Implement\Repository\Mapper\DateTime('date'));
return $this->parseData(new Model\Proyecto\Broker\Contract\State(), $data, $map); return $this->parseData(new Model\Proyecto\Broker\Contract\State(), $data, $map);
} }
public function save(Common\Define\Model $model): Model\Proyecto\Broker\Contract\State 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; return $model;
} }
public function edit(Common\Define\Model $model, array $new_data): Model\Proyecto\Broker\Contract\State 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); 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 public function fetchByContract(int $contract_id): array
{ {
$query = $this->connection->getQueryBuilder() $query = $this->connection->getQueryBuilder()
@ -46,6 +55,12 @@ class State extends Common\Ideal\Repository
->where('contract_id = :contract_id'); ->where('contract_id = :contract_id');
return $this->fetchMany($query, ['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 public function fetchActiveByContract(int $contract_id): Model\Proyecto\Broker\Contract\State
{ {
$query = $this->connection->getQueryBuilder() $query = $this->connection->getQueryBuilder()

View File

@ -32,7 +32,7 @@ class Contract extends Ideal\Service
public function getByBroker(int $broker_rut): array public function getByBroker(int $broker_rut): array
{ {
try { 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) { } catch (Implement\Exception\EmptyResult $exception) {
throw new ServiceAction\Read(__CLASS__, $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 public function add(array $data): Model\Proyecto\Broker\Contract
{ {
try { 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) {} } catch (Implement\Exception\EmptyResult) {}
try { try {
$filteredData = $this->contractRepository->filterData($data); $filteredData = $this->contractRepository->filterData($data);
$contract = $this->contractRepository->create($filteredData); $contract = $this->contractRepository->create($filteredData);
$contract = $this->contractRepository->save($contract); $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(); $date = new DateTimeImmutable();
if (isset($data['date'])) { if (isset($data['date'])) {
try { try {
@ -125,9 +125,9 @@ class Contract extends Ideal\Service
$contract->addFactory('states', (new Implement\Repository\Factory()) $contract->addFactory('states', (new Implement\Repository\Factory())
->setCallable([$this->stateRepository, 'fetchByContract']) ->setCallable([$this->stateRepository, 'fetchByContract'])
->setArgs(['contract_id' => $contract->id])); ->setArgs(['contract_id' => $contract->id]));
$contract->addFactory('currentState', (new Implement\Repository\Factory()) /*$contract->addFactory('currentState', (new Implement\Repository\Factory())
->setCallable([$this->stateRepository, 'fetchActiveByContract']) ->setCallable([$this->stateRepository, 'fetchActiveByContract'])
->setArgs(['contract_id' => $contract->id])); ->setArgs(['contract_id' => $contract->id]));*/
return $contract; return $contract;
} }
} }