diff --git a/api/ProVM/Alias/API/Controller.php b/api/ProVM/Alias/API/Controller.php new file mode 100644 index 0000000..71def3f --- /dev/null +++ b/api/ProVM/Alias/API/Controller.php @@ -0,0 +1,186 @@ +setup($container); + } + + abstract public function setup(ContainerInterface $container): void; + + protected array $names; + public function setSingular(string $singular): ControllerInterface + { + $this->names['singular'] = $singular; + return $this; + } + public function setPlural(string $plural): ControllerInterface + { + $this->names['plural'] = $plural; + return $this; + } + public function getSingular(): string + { + return $this->names['singular']; + } + public function getPlural(): string + { + return $this->names['plural']; + } + protected Repository $repository; + public function setRepository(Repository $repository): ControllerInterface + { + $this->repository = $repository; + return $this; + } + public function getRepository(): Repository + { + return $this->repository; + } + + public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface + { + $objs = []; + try { + $objs = $this->getRepository()->fetchAll(); + } catch (PDOException $e) { + error_log($e); + } + return $this->withJson($response, [$this->getPlural() => $objs]); + } + public function get(ServerRequestInterface $request, ResponseInterface $response, int $model_id): ResponseInterface + { + $obj = null; + try { + $obj = $this->getRepository()->fetchById($model_id); + } catch (PDOException $e) { + error_log($e); + } + return $this->withJson($response, [$this->getSingular() => $obj]); + } + public function add(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface + { + $body = $request->getBody(); + $contents = $body->getContents(); + $json = json_decode($contents)->{$this->getPlural()}; + if (!is_array($json)) { + $json = [$json]; + } + $output = [ + 'input' => $json, + $this->getPlural() => [] + ]; + foreach ($json as $data) { + $obj = $this->getRepository()->create((array) $data); + $status = true; + $exists = true; + if ($obj->isNew()) { + $exists = false; + try { + $this->getRepository()->save($obj); + } catch (PDOException $e) { + error_log($e); + $status = false; + } + $output[$this->getPlural()] []= [ + $this->getSingular() => $obj, + 'exists' => $exists, + 'added' => $status + ]; + } + } + return $this->withJson($response, $output); + } + public function edit(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface + { + $body = $request->getBody(); + $contents = $body->getContents(); + $json = json_decode($contents)->{$this->getPlural()}; + if (!is_array($json)) { + $json = [$json]; + } + $output = [ + 'input' => $json, + $this->getPlural() => [] + ]; + foreach ($json as $data) { + $obj = $this->getRepository()->fetchById($data->id); + $old = clone $obj; + try { + $obj->edit((array) $data); + $status = $obj->isDirty(); + if ($status) { + $this->getRepository()->save($obj); + } + } catch (PDOException $e) { + error_log($e); + $status = false; + } + $output[$this->getPlural()] []= [ + 'antes' => $old, + $this->getSingular() => $obj, + 'edited' => $status + ]; + } + return $this->withJson($response, $output); + } + public function editOne(ServerRequestInterface $request, ResponseInterface $response, int $model_id): ResponseInterface + { + $obj = $this->getRepository()->fetchById($model_id); + $body = $request->getBody(); + $contents = $body->getContents(); + $json = json_decode($contents, JSON_OBJECT_AS_ARRAY)[$this->getSingular()]; + $output = [ + 'input' => $json, + 'old' => clone $obj + ]; + try { + $obj->edit((array) $json); + $status = $obj->isDirty(); + if ($status) { + $this->getRepository()->save($obj); + } + } catch (PDOException $e) { + error_log($e); + $status = false; + } + $output[$this->getSingular()] = $obj; + $output['edited'] = $status; + return $this->withJson($response, $output); + } + public function remove(ServerRequestInterface $request, ResponseInterface $response, int $model_id): ResponseInterface + { + $output = [ + $this->getSingular() => null, + 'exists' => true, + 'deleted' => false + ]; + try { + $obj = $this->getRepository()->fetchById($model_id); + $output[$this->getSingular()] = clone $obj; + try { + $this->repository->delete($obj); + } catch (PDOException $e) { + error_log($e); + $output['deleted'] = false; + } + } catch (PDOException $e) { + error_log($e); + $output['exists'] = false; + } + return $this->withJson($response, $output); + } +} diff --git a/api/ProVM/Alias/API/Route/Operation.php b/api/ProVM/Alias/API/Route/Operation.php new file mode 100644 index 0000000..dcd461f --- /dev/null +++ b/api/ProVM/Alias/API/Route/Operation.php @@ -0,0 +1,107 @@ +addTag($tag); + } + return $this; + } + public function addTag(string $tag): OperationInterface + { + $this->tags []= $tag; + return $this; + } + public function getTags(): array + { + return $this->tags; + } + protected string $summary; + public function setSummary(string $summary): OperationInterface + { + $this->summary = $summary; + return $this; + } + public function getSummary(): string + { + return $this->summary; + } + protected string $description; + public function setDescription(string $description): OperationInterface + { + $this->description = $description; + return $this; + } + public function getDescription(): string + { + return $this->description; + } + protected array $parameters; + public function setParameters(array $parameters): OperationInterface + { + foreach ($parameters as $parameter) { + $this->addParameter($parameter); + } + return $this; + } + public function addParameter(Parameter $parameter): OperationInterface + { + $this->parameters []= $parameter; + return $this; + } + public function getParameters(): array + { + return $this->parameters; + } + protected array $responses; + public function setResponses(array $responses): OperationInterface + { + foreach ($responses as $code => $response) { + $this->addResponse($code, $response); + } + return $this; + } + public function addResponse(int $code, Response $response): OperationInterface + { + $this->responses[$code] = $response; + return $this; + } + public function getResponses(): array + { + return $this->responses; + } + protected bool $deprecated; + public function setDeprecated(): OperationInterface + { + $this->deprecated = true; + return $this; + } + public function isDeprecated(): bool + { + return $this->deprecated ?? false; + } + + public function jsonSerialize(): mixed + { + $arr = []; + $fields = ['tags', 'summary', 'description', 'parameters', 'responses']; + foreach ($fields as $field) { + if (isset($this->{$field})) { + $method = 'get' . ucwords($field); + $arr[$field] = $this->{$method}(); + } + } + if ($this->isDeprecated()) { + $arr['deprecated'] = true; + } + return $arr; + } +} diff --git a/api/ProVM/Alias/API/Route/Parameter.php b/api/ProVM/Alias/API/Route/Parameter.php new file mode 100644 index 0000000..0e48732 --- /dev/null +++ b/api/ProVM/Alias/API/Route/Parameter.php @@ -0,0 +1,74 @@ +name = $name; + return $this; + } + public function getName(): string + { + return $this->name; + } + protected string $description; + public function setDescription(string $description): ParameterInterface + { + $this->description = $description; + return $this; + } + public function getDescription(): string + { + return $this->description; + } + protected string $in; + public function setIn(string $in): ParameterInterface + { + $this->in = $in; + return $this; + } + public function getIn(): string + { + return $this->in; + } + protected bool $required; + public function setRequired(): ParameterInterface + { + $this->required = true; + return $this; + } + public function isRequired(): bool + { + return $this->required ?? false; + } + protected bool $deprecated; + public function setDeprecated(): ParameterInterface + { + $this->deprecated = true; + return $this; + } + public function isDeprecated(): bool + { + return $this->deprecated ?? false; + } + + public function jsonSerialize(): mixed + { + $arr = [ + 'name' => $this->getName(), + 'in' => $this->getIn(), + 'description' => $this->getDescription() + ]; + if ($this->isRequired()) { + $arr['required'] = true; + } + if ($this->isDeprecated()) { + $arr['deprecated'] = true; + } + return $arr; + } +} diff --git a/api/ProVM/Alias/API/Route/Response.php b/api/ProVM/Alias/API/Route/Response.php new file mode 100644 index 0000000..613979c --- /dev/null +++ b/api/ProVM/Alias/API/Route/Response.php @@ -0,0 +1,66 @@ +description = $description; + return $this; + } + public function getDescription(): string + { + return $this->description; + } + protected array $headers; + public function setHeaders(array $headers): ResponseInterface + { + foreach ($headers as $header) { + $this->addHeader($header); + } + return $this; + } + public function addHeader(string $header): ResponseInterface + { + $this->headers []= $header; + return $this; + } + public function getHeaders(): array + { + return $this->headers; + } + protected array $contents; + public function setContent(array $contents): ResponseInterface + { + foreach ($contents as $content) { + $this->addContent($content); + } + return $this; + } + public function addContent(string $content): ResponseInterface + { + $this->contents []= $content; + return $this; + } + public function getContents(): array + { + return $this->contents; + } + + public function jsonSerialize(): mixed + { + $arr = [ + 'description' => $this->getDescription() + ]; + if (isset($this->headers) and count($this->headers) > 0) { + $arr['headers'] = $this->getHeaders(); + } + if (isset($this->contents) and count($this->contents) > 0) { + $arr['content'] = $this->getContents(); + } + return $arr; + } +} diff --git a/api/ProVM/Alias/API/Route/Route.php b/api/ProVM/Alias/API/Route/Route.php new file mode 100644 index 0000000..969e632 --- /dev/null +++ b/api/ProVM/Alias/API/Route/Route.php @@ -0,0 +1,95 @@ +ref = $ref; + return $this; + } + public function getRef(): string + { + return $this->ref; + } + protected string $summary; + public function setSummary(string $summary): RouteInterface + { + $this->summary = $summary; + return $this; + } + public function getSummary(): string + { + return $this->summary; + } + protected string $description; + public function setDescription(string $description): RouteInterface + { + $this->description = $description; + return $this; + } + public function getDescription(): string + { + return $this->description; + } + protected array $methods; + public function setMethods(array $methods): RouteInterface + { + foreach ($methods as $method => $operation) { + $this->addMethod($method, $operation); + } + return $this; + } + public function addMethod(string $method, Operation $operation): RouteInterface + { + $this->methods[$method] = $operation; + return $this; + } + public function getMethods(): array + { + return $this->methods; + } + protected array $parameters; + public function setParameters(array $parameters): RouteInterface + { + foreach ($parameters as $parameter) { + $this->addParameter($parameter); + } + return $this; + } + public function addParameter(Parameter $parameter): RouteInterface + { + $this->parameters []= $parameter; + return $this; + } + public function getParameters(): array + { + return $this->parameters; + } + + public function jsonSerialize(): mixed + { + $arr = []; + if (isset($this->ref)) { + $arr['ref'] = $this->getRef(); + } + if (isset($this->summary)) { + $arr['summary'] = $this->getSummary(); + } + if (isset($this->description)) { + $arr['description'] = $this->getDescription(); + } + foreach ($this->methods as $method => $operation) { + $arr[$method] = $operation; + } + if (isset($this->parameters)) { + $arr['parameters'] = $this->getParameters(); + } + return $arr; + } +} diff --git a/api/ProVM/Alias/Database/Query.php b/api/ProVM/Alias/Database/Query.php index 0bda90d..3b73e97 100644 --- a/api/ProVM/Alias/Database/Query.php +++ b/api/ProVM/Alias/Database/Query.php @@ -1,10 +1,30 @@ errors []= $error; + return $this; + } + protected function log(): void + { + if (!isset($this->errors) or count($this->errors) === 0) { + return; + } + $message = ['Query Error']; + foreach ($this->errors as $error) { + $message []= $error->getMessage(); + } + error_log(implode(PHP_EOL, $message)); + } + public function __toString(): string { return $this->build(); diff --git a/api/ProVM/Alias/Factory/Model.php b/api/ProVM/Alias/Factory/Model.php index 32aed52..11439a5 100644 --- a/api/ProVM/Alias/Factory/Model.php +++ b/api/ProVM/Alias/Factory/Model.php @@ -3,7 +3,6 @@ namespace ProVM\Alias\Factory; use Psr\Container\ContainerInterface; use ProVM\Concept\Factory\Model as FactoryInterface; -use ProVM\Concept\Model as ModelInterface; use ProVM\Concept\Repository; abstract class Model implements FactoryInterface @@ -18,9 +17,9 @@ abstract class Model implements FactoryInterface { return $this->container; } - public function find(ModelInterface $model_name): Repository + public function find(string $model_name): Repository { - $class = str_replace('Model', 'Repository', get_class($model_name)); + $class = str_replace('Model', 'Repository', $model_name); return $this->getContainer()->get($class); } } diff --git a/api/ProVM/Alias/Model.php b/api/ProVM/Alias/Model.php index caa3b65..6268d70 100644 --- a/api/ProVM/Alias/Model.php +++ b/api/ProVM/Alias/Model.php @@ -6,6 +6,17 @@ use ProVM\Concept\Model as ModelInterface; abstract class Model implements ModelInterface { + protected int $id; + public function setId(int $id): ModelInterface + { + $this->id = $id; + return $this; + } + public function getId(): int + { + return $this->id; + } + protected bool $new = false; public function setNew(): ModelInterface { @@ -60,8 +71,10 @@ abstract class Model implements ModelInterface public function jsonSerialize(): mixed { $ref = new ReflectionObject($this); - $properties = $ref->getProperties(); - $output = []; + $properties = ($ref->getProperties()); + $output = [ + 'id' => $this->getId() + ]; foreach ($properties as $property) { if (get_called_class() !== $property->getDeclaringClass()->getName()) { continue; diff --git a/api/ProVM/Alias/Repository.php b/api/ProVM/Alias/Repository.php index 8a9fdfe..061ad2e 100644 --- a/api/ProVM/Alias/Repository.php +++ b/api/ProVM/Alias/Repository.php @@ -6,16 +6,22 @@ use Error; use function Safe\error_log; use ProVM\Concept\Model; use ProVM\Concept\Repository as RepositoryInterface; +use ProVM\Concept\Factory\Model as FactoryInterface; use ProVM\Implement\Database\QueryBuilder; abstract class Repository implements RepositoryInterface { - public function __construct(DatabaseInterface $database, QueryBuilder $builder) + public function __construct(DatabaseInterface $database, QueryBuilder $builder, FactoryInterface $factory) { $this->setDatabase($database); $this->setQueryBuilder($builder); + $this->setFactory($factory); + $this->setProperties(['id']); + $this->setup(); } + abstract public function setup(): void; + protected QueryBuilder $query; public function setQueryBuilder(QueryBuilder $builder): RepositoryInterface { @@ -26,6 +32,16 @@ abstract class Repository implements RepositoryInterface { return $this->query; } + protected FactoryInterface $factory; + public function setFactory(FactoryInterface $factory): RepositoryInterface + { + $this->factory = $factory; + return $this; + } + public function getFactory(): FactoryInterface + { + return $this->factory; + } protected string $table; public function setTable(string $table): RepositoryInterface @@ -44,6 +60,11 @@ abstract class Repository implements RepositoryInterface return $this; } public function setProperties(array $properties): RepositoryInterface + { + $this->properties = []; + return $this->addProperties($properties); + } + public function addProperties(array $properties): RepositoryInterface { foreach ($properties as $property) { $this->addProperty($property); @@ -70,11 +91,19 @@ abstract class Repository implements RepositoryInterface $query = $this->getQueryBuilder()->select()->from($this->getTable())->build(); return array_map([$this, 'load'], $this->getDatabase()->query($query)); } + public function fetchById(int $id): Model + { + $query = $this->getQueryBuilder()->select()->from($this->getTable())->where('id = ?'); + return $this->load($this->getDatabase()->prepare($query)->execute([$id])[0]); + } protected function extractProperties(Model $model): array { $properties = []; foreach ($this->getProperties() as $p) { + if ($model->isNew() and $p === 'id') { + continue; + } $method = $model::parseGetter($p); if (method_exists($model, $method)) { try { @@ -116,4 +145,9 @@ abstract class Repository implements RepositoryInterface $query = $this->getQueryBuilder()->update()->table($this->getTable())->set($sets)->where('id = ?')->build(); $this->getDatabase()->prepare($query)->update(array_merge($values, [$model->getId()])); } + public function delete(Model $model): void + { + $query = $this->getQueryBuilder()->delete()->from($this->getTable())->where('id = ?')->build(); + $this->getDatabase()->prepare($query)->delete([$model->getId()]); + } } diff --git a/api/ProVM/Concept/API/Controller.php b/api/ProVM/Concept/API/Controller.php new file mode 100644 index 0000000..7ebce50 --- /dev/null +++ b/api/ProVM/Concept/API/Controller.php @@ -0,0 +1,23 @@ +setTags($data['tags']); + } + if (isset($data['summary'])) { + $operation->setSummary($data['summary']); + } + if (isset($data['description'])) { + $operation->setDescription($data['description']); + } + if (isset($data['parameters'])) { + foreach ($data['parameters'] as $p) { + $parameter = Parameter::add($p); + $operation->addParameter($parameter); + } + } + if (isset($data['responses'])) { + foreach ($data['responses'] as $code => $r) { + $response = Response::add($r); + $operation->addResponse($code, $response); + } + } + if (isset($data['deprecated'])) { + $operation->setDeprecated(); + } + return $operation; + } +} diff --git a/api/ProVM/Implement/API/Route/Parameter.php b/api/ProVM/Implement/API/Route/Parameter.php new file mode 100644 index 0000000..2e0d245 --- /dev/null +++ b/api/ProVM/Implement/API/Route/Parameter.php @@ -0,0 +1,24 @@ +setName($data['name']); + $parameter->setIn($data['in']); + if (isset($data['description'])) { + $parameter->setDescription($data['description']); + } + if (isset($data['required'])) { + $parameter->setRequired(); + } + if (isset($data['deprecated'])) { + $parameter->setDeprecated(); + } + return $parameter; + } +} diff --git a/api/ProVM/Implement/API/Route/Response.php b/api/ProVM/Implement/API/Route/Response.php new file mode 100644 index 0000000..d44848c --- /dev/null +++ b/api/ProVM/Implement/API/Route/Response.php @@ -0,0 +1,20 @@ +setDescription($data['description']); + if (isset($data['headers'])) { + $response->setHeaders($data['headers']); + } + if (isset($data['content'])) { + $response->setContent($data['content']); + } + return $response; + } +} diff --git a/api/ProVM/Implement/API/Route/Route.php b/api/ProVM/Implement/API/Route/Route.php new file mode 100644 index 0000000..ee37618 --- /dev/null +++ b/api/ProVM/Implement/API/Route/Route.php @@ -0,0 +1,35 @@ +setRef($data['ref']); + } + if (isset($data['summary'])) { + $route->setSummary($data['summary']); + } + if (isset($data['description'])) { + $route->setDescription($data['description']); + } + $methods = ['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace']; + foreach ($methods as $method) { + if (isset($data[$method])) { + $operation = Operation::add($data[$method]); + $route->addMethod($method, $operation); + } + } + if (isset($data['parameters'])) { + foreach ($data['parameters'] as $p) { + $parameter = Parameter::add($p); + $operation->addParameter($parameter); + } + } + return $route; + } +} diff --git a/api/ProVM/Implement/Database/MySQL.php b/api/ProVM/Implement/Database/MySQL.php index 325554d..9e0a7fe 100644 --- a/api/ProVM/Implement/Database/MySQL.php +++ b/api/ProVM/Implement/Database/MySQL.php @@ -1,7 +1,7 @@ getTable(); try { $output []= "({$this->getColumns()})"; - } catch (\Error $e) { - \Safe\error_log($e); + } catch (Error $e) { + $this->error($e); } try { $output []= $this->getSelect(); @@ -95,9 +96,10 @@ class Insert extends Query } try { $output []= "ON DUPLICATE KEY UPDATE {$this->getUpdates()}"; - } catch (\Error $e) { - \Safe\error_log($e); + } catch (Error $e) { + $this->error($e); } + $this->log(); return implode(' ', $output); } } diff --git a/api/ProVM/Implement/Database/Query/MySQL/Select.php b/api/ProVM/Implement/Database/Query/MySQL/Select.php index 49d25b1..0535f81 100644 --- a/api/ProVM/Implement/Database/Query/MySQL/Select.php +++ b/api/ProVM/Implement/Database/Query/MySQL/Select.php @@ -1,7 +1,9 @@ getSelect(); - } catch (\Error $e) { + } catch (Error $e) { $output []= '*'; } $output []= 'FROM'; $output []= $this->getFrom(); try { $output [] = $this->getJoins(); - } catch (\Error $e) { - \Safe\error_log($e); + } catch (Error $e) { + $this->error($e); } try { $output []= "WHERE {$this->getWheres()}"; - } catch (\Error $e) { - \Safe\error_log($e); + } catch (Error $e) { + $this->error($e); } try { $output []= "GROUP BY {$this->getGroups()}"; - } catch (\Error $e) { - \Safe\error_log($e); + } catch (Error $e) { + $this->error($e); } try { $output []= "HAVING {$this->getHaving()}"; - } catch (\Error $e) { - \Safe\error_log($e); + } catch (Error $e) { + $this->error($e); } try { $output []= "ORDER BY {$this->getOrders()}"; - } catch (\Error $e) { - \Safe\error_log($e); + } catch (Error $e) { + $this->error($e); } try { $output []= "LIMIT {$this->getLimit()}"; - } catch (\Error $e) { - \Safe\error_log($e); + } catch (Error $e) { + $this->error($e); } + $this->log(); return implode(' ', $output); } } diff --git a/api/ProVM/Implement/Database/Query/MySQL/Update.php b/api/ProVM/Implement/Database/Query/MySQL/Update.php index 608dd0f..ba5b01a 100644 --- a/api/ProVM/Implement/Database/Query/MySQL/Update.php +++ b/api/ProVM/Implement/Database/Query/MySQL/Update.php @@ -1,7 +1,7 @@ setContainer($container); + } +} diff --git a/api/ProVM/Implement/Factory/Repository.php b/api/ProVM/Implement/Factory/Repository.php new file mode 100644 index 0000000..d264203 --- /dev/null +++ b/api/ProVM/Implement/Factory/Repository.php @@ -0,0 +1,38 @@ +container = $container; + return $this; + } + public function getContainer(): ContainerInterface + { + return $this->container; + } + protected string $namespace; + public function setNamespace(string $namespace): Repository + { + $this->namespace = $namespace; + return $this; + } + public function getNamespace(): string + { + return $this->namespace; + } + + public function find(string $repository_class): RepositoryInterface + { + $class = implode("\\", [ + $this->getNamespace(), + $repository_class + ]); + return $this->getContainer()->get($class); + } +} diff --git a/api/common/Controller/Base.php b/api/common/Controller/Base.php index 0fd357d..b0db61c 100644 --- a/api/common/Controller/Base.php +++ b/api/common/Controller/Base.php @@ -6,6 +6,7 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use function Safe\{json_decode, file_get_contents}; use ProVM\Alias\Controller\Json; +use ProVM\Implement\Path; class Base { @@ -13,12 +14,8 @@ class Base public function __invoke(ServerRequestInterface $request, ResponseInterface $response, ContainerInterface $container): ResponseInterface { - $folder = $container->get('folders')->documentation; - $filename = implode(DIRECTORY_SEPARATOR, [ - $folder, - 'base.json' - ]); - $documentation = json_decode(file_get_contents($filename)); + $filename = $container->get('documentation'); + $documentation = json_decode(trim(file_get_contents($filename))); return $this->withJson($response, $documentation); } } diff --git a/api/common/Controller/Categorias.php b/api/common/Controller/Categorias.php new file mode 100644 index 0000000..8de5eba --- /dev/null +++ b/api/common/Controller/Categorias.php @@ -0,0 +1,16 @@ +setSingular('categoria') + ->setPlural('categorias') + ->setRepository($container->get(Categoria::class)); + } +} diff --git a/api/common/Controller/Conecciones.php b/api/common/Controller/Conecciones.php new file mode 100644 index 0000000..7e1bc1c --- /dev/null +++ b/api/common/Controller/Conecciones.php @@ -0,0 +1,16 @@ +setSingular('coneccion') + ->setPlural('conecciones') + ->setRepository($container->get(Coneccion::class)); + } +} diff --git a/api/common/Controller/Cuentas.php b/api/common/Controller/Cuentas.php index f8c8487..d3a47c1 100644 --- a/api/common/Controller/Cuentas.php +++ b/api/common/Controller/Cuentas.php @@ -1,125 +1,16 @@ fetchAll(); - } catch (PDOException $e) { - error_log($e); - } - return $this->withJson($response, compact('cuentas')); - } - public function get(ServerRequestInterface $request, ResponseInterface $response, Cuenta $repository, $cuenta_id): ResponseInterface - { - $cuenta = null; - try { - $cuenta = $repository->fetchById($cuenta_id); - } catch (PDOException $e) { - error_log($e); - } - return $this->withJson($response, compact('cuenta')); - } - public function add(ServerRequestInterface $request, ResponseInterface $response, Cuenta $repository): ResponseInterface - { - $body = $request->getBody(); - $contents = $body->getContents(); - $json = json_decode($contents); - if (!is_array($json)) { - $json = [$json]; - } - $output = [ - 'input' => $json, - 'cuentas' => [] - ]; - foreach ($json as $data) { - $cuenta = $repository->create((array) $data); - $status = true; - $exists = true; - if ($cuenta->isNew()) { - $exists = false; - try { - $repository->save($cuenta); - } catch (PDOException $e) { - error_log($e); - $status = false; - } - } - $output['cuentas'] []= [ - 'cuenta' => $cuenta, - 'exists' => $exists, - 'added' => $status - ]; - } - return $this->withJson($response, $output); - } - public function edit(ServerRequestInterface $request, ResponseInterface $response, Cuenta $repository): ResponseInterface - { - $body = $request->getBody(); - $contents = $body->getContents(); - $json = json_decode($contents); - if (!is_array($json)) { - $json = [$json]; - } - $output = [ - 'input' => $json, - 'cuentas' => [] - ]; - foreach ($json as $data) { - $cuenta = $repository->fetchById($data->id); - $old = clone $cuenta; - try { - $cuenta->edit((array) $data); - $status = $cuenta->isDirty(); - if ($status) { - $repository->save($cuenta); - } - } catch (PDOException $e) { - error_log($e); - $status = false; - } - $output['cuentas'] []= [ - 'antes' => $old, - 'cuenta' => $cuenta, - 'edited' => $status - ]; - } - return $this->withJson($response, $output); - } - public function editOne(ServerRequestInterface $request, ResponseInterface $response, Cuenta $repository, $cuenta_id): ResponseInterface - { - $cuenta = $repository->fetchById($cuenta_id); - $body = $request->getBody(); - $contents = $body->getContents(); - $json = json_decode($contents, JSON_OBJECT_AS_ARRAY); - $output = [ - 'input' => $json, - 'old' => clone $cuenta - ]; - try { - $cuenta->edit((array) $json); - $status = $cuenta->isDirty(); - if ($status) { - $repository->save($cuenta); - } - } catch (PDOException $e) { - error_log($e); - $status = false; - } - $output['cuenta'] = $cuenta; - $output['edited'] = $status; - return $this->withJson($response, $output); + $this->setSingular('cuenta') + ->setPlural('cuentas') + ->setRepository($container->get(Cuenta::class)); } } diff --git a/api/common/Controller/Estado/Conecciones.php b/api/common/Controller/Estado/Conecciones.php new file mode 100644 index 0000000..094fab6 --- /dev/null +++ b/api/common/Controller/Estado/Conecciones.php @@ -0,0 +1,17 @@ +setSingular('estado_coneccion') + ->setPlural('estados_conecciones') + ->setRepository($container->get(Coneccion::class)); + } +} diff --git a/api/common/Controller/Monedas.php b/api/common/Controller/Monedas.php new file mode 100644 index 0000000..99fc0c1 --- /dev/null +++ b/api/common/Controller/Monedas.php @@ -0,0 +1,16 @@ +setSingular('moneda'); + $this->setPlural('monedas'); + $this->setRepository($container->get(Moneda::class)); + } +} diff --git a/api/common/Controller/Transacciones.php b/api/common/Controller/Transacciones.php new file mode 100644 index 0000000..9a457f0 --- /dev/null +++ b/api/common/Controller/Transacciones.php @@ -0,0 +1,16 @@ +setSingular('transaccion'); + $this->setPlural('transacciones'); + $this->setRepository($container->get(Transaccion::class)); + } +} diff --git a/api/common/Middleware/Error.php b/api/common/Middleware/Error.php new file mode 100644 index 0000000..3165165 --- /dev/null +++ b/api/common/Middleware/Error.php @@ -0,0 +1,44 @@ +setApp($app); + } + + protected App $app; + public function setApp(App $app): Error + { + $this->app = $app; + return $this; + } + public function getApp(): App + { + return $this->app; + } + + public function __invoke(ServerRequestInterface $request, Throwable $exception, bool $displayErrorDetails, bool $logErrors, bool $logErrorDetails): ResponseInterface + { + error_log($exception); + $response = $this->getApp()->getResponseFactory()->createResponse($exception->getCode()); + $output = json_encode([ + 'uri' => $request->getUri()->getPath(), + 'code' => $exception->getCode(), + 'message' => $exception->getMessage(), + 'file' => $exception->getFile(), + 'line' => $exception->getLine(), + 'trace' => $exception->getTrace() + ], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + $response->getBody()->write($output); + return $response->withHeader('Content-Type', 'application/json'); + } +} diff --git a/api/common/Service/Auth.php b/api/common/Service/Auth.php index 702b38f..b31878f 100644 --- a/api/common/Service/Auth.php +++ b/api/common/Service/Auth.php @@ -1,36 +1,74 @@ key = $api_key; } - public function isValid(Request $request): bool { - if ($request->hasHeader('Authorization')) { - $sent_key = $this->getAuthKey($request->getHeader('Authorization')); - return $this->key == $sent_key; + public function isValid(Request $request): bool + { + return $this->key == $this->getKey($request); + } + public function getKey(Request $request): string + { + $errors = []; + try { + return $this->getHeaderKey($request); + } catch (NotFoundExceptionInterface $e) { + $errors []= $e; } + try { + return $this->getBodyKey($request); + } catch (NotFoundExceptionInterface $e) { + $errors []= $e; + } + try { + return $this->getQueryKey($request); + } catch (NotFoundExceptionInterface $e) { + $errors []= $e; + } + throw new NotFoundException('API Key not found.'); + } + protected function getHeaderKey(Request $request): string + { + if ($request->hasHeader('Authorization')) { + return $this->getAuthKey($request->getHeader('Authorization')); + } + throw new NotFoundException('API Key not found on header'); + } + protected function getBodyKey(Request $request): string + { if (isset($request->getParsedBody()['api_key'])) { - $sent_key = $request->getParsedBody()['api_key']; - return $this->key == $sent_key; + return $request->getParsedBody()['api_key']; } $post = $request->getParsedBody() ?? json_decode($request->getBody()); - $sent_key = $this->getArrayKey($post); - if ($sent_key !== null) { - return $this->key == $sent_key; + try { + return $this->getArrayKey($post); + } catch (\Exception $e) { + throw new NotFoundException('API Key not found in body.'); } - $sent_key = $this->getArrayKey($request->getQueryParams()); - return $this->key == $sent_key; } - protected function getAuthKey($auth) { + protected function getQueryKey(Request $request): string + { + try { + return $this->getArrayKey($request->getQueryParams()); + } catch (\Exception $e) { + throw new NotFoundException('API Key not found in query.'); + } + } + protected function getAuthKey($auth) + { if (is_array($auth)) { $auth = $auth[0]; } if (str_contains($auth, 'Bearer')) { - $auth = explode(' ', $auth)[1]; + $auth = trim(str_replace('Bearer', '', $auth), ' ,'); } return $auth; } diff --git a/api/common/Service/Documenter.php b/api/common/Service/Documenter.php new file mode 100644 index 0000000..5cdf40b --- /dev/null +++ b/api/common/Service/Documenter.php @@ -0,0 +1,60 @@ +setFilename($filename); + } + + protected string $filename; + public function setFilename(string $filename): Documenter + { + $this->filename = $filename; + return $this; + } + public function getFilename(): string + { + return $this->filename; + } + + protected array $routes; + public function setRoutes(array $routes): Documenter + { + foreach ($routes as $path => $route) { + $this->addRoute($path, $route); + } + return $this; + } + public function addRoute(string $path, Route $route): Documenter + { + $this->routes[$path] = $route; + return $this; + } + public function getRoutes(): array + { + return $this->routes; + } + + protected function load(): mixed + { + $json = json_decode(trim(file_get_contents($this->getFilename())), JSON_OBJECT_AS_ARRAY); + foreach ($json['paths'] as $path => $data) { + $route = RouteObj::add($data); + $this->addRoute($path, $route); + } + return $json; + } + public function save(): void + { + $json = $this->load(); + $json['paths'] = $this->getRoutes(); + ksort($json['paths']); + file_put_contents($this->getFilename(), json_encode($json, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); + } +} diff --git a/api/common/Service/Router.php b/api/common/Service/Router.php new file mode 100644 index 0000000..587b097 --- /dev/null +++ b/api/common/Service/Router.php @@ -0,0 +1,179 @@ +setApp($app); + $this->setDocumenter($documenter); + } + + protected App $app; + public function setApp(App &$app): Router + { + $this->app = $app; + return $this; + } + public function getApp(): App + { + return $this->app; + } + protected Documenter $documenter; + public function setDocumenter(Documenter $documenter): Router + { + $this->documenter = $documenter; + return $this; + } + public function getDocumenter(): Documenter + { + return $this->documenter; + } + protected Controller $controller; + public function setController(Controller $controller): Router + { + $this->controller = $controller; + return $this; + } + public function getController(): Controller + { + return $this->controller; + } + + protected function document(): void + { + $docs = [ + "/{$this->getController()->getPlural()}" => [ + 'get' => [ + 'description' => "Entrega una lista de {$this->getController()->getPlural()}", + 'responses' => [ + '200' => [ + 'description' => "Lista de {$this->getController()->getPlural()}" + ] + ] + ] + ], + "/{$this->getController()->getPlural()}/add" => [ + 'post' => [ + 'description' => "Agregar {$this->getController()->getPlural()} con una lista", + 'parameters' => [ + [ + 'name' => $this->getController()->getPlural(), + 'in' => 'query', + 'description' => 'Lista de datos para agregar', + 'required' => true + ] + ], + 'responses' => [ + '200' => [ + 'description' => "Entrega un listado de {$this->getController()->getPlural()} y si fueron agregadas" + ] + ] + ] + ], + "/{$this->getController()->getPlural()}/edit" => [ + 'put' => [ + 'description' => "Editar multiples {$this->getController()->getPlural()} con una lista", + 'parameters' => [ + [ + 'name' => $this->getController()->getPlural(), + 'in' => 'query', + 'description' => 'Lista de datos para editar', + 'required' => true + ] + ], + 'responses' => [ + '200' => [ + 'description' => "Entrega un listado de {$this->getController()->getPlural()} identificando si fueron editados" + ] + ] + ] + ], + "/{$this->getController()->getSingular()}/{model_id}" => [ + 'get' => [ + 'description' => "Entrega {$this->getController()->getSingular()}", + 'parameters' => [ + [ + 'name' => 'id', + 'in' => 'path', + 'description' => "{$this->getController()->getSingular()} id", + 'required' => true + ] + ], + 'responses' => [ + '200' => [ + 'description' => "{$this->getController()->getSingular()} found or null" + ] + ] + ] + ], + "/{$this->getController()->getSingular()}/{model_id}/edit" => [ + 'put' => [ + 'description' => '', + 'parameters' => [ + [ + 'name' => 'model_id', + 'in' => 'path', + 'description' => "{$this->getController()->getSingular()} id", + 'required' => true + ], + [ + 'name' => "{$this->getController()->getSingular()}", + 'in' => 'query', + 'description' => '', + 'required' => true + ] + ], + 'responses' => [ + '200' => [ + 'description' => '' + ] + ] + ] + ], + "/{$this->getController()->getSingular()}/{model_id}/remove" => [ + 'delete' => [ + 'description' => '', + 'parameters' => [ + [ + 'name' => 'model_id', + 'in' => 'path', + 'description' => "{$this->getController()->getSingular()} id", + 'required' => true + ] + ], + 'responses' => [ + '200' => [ + 'description' => '' + ] + ] + ] + ] + ]; + + foreach ($docs as $path => $r) { + $route = Route::add($r); + $this->getDocumenter()->addRoute($path, $route); + } + $this->getDocumenter()->save(); + } + public function build(): void + { + $this->getApp()->group('/' . $this->getController()->getPlural(), function($app) { + $app->post('/add[/]', [get_class($this->getController()), 'add']); + $app->put('/edit[/]', [get_class($this->getController()), 'edit']); + $app->get('[/]', get_class($this->getController())); + }); + $this->getApp()->group('/' . $this->getController()->getSingular() . '/{model_id}', function($app) { + $app->put('/edit[/]', [get_class($this->getController()), 'editOne']); + $app->delete('/remove[/]', [get_class($this->getController()), 'remove']); + $app->get('[/]', [get_class($this->getController()), 'get']); + }); + + $this->document(); + } +} diff --git a/api/db/migrations/20211029150354_tipo_categoria.php b/api/db/migrations/20211029150354_tipo_categoria.php new file mode 100644 index 0000000..4ee43de --- /dev/null +++ b/api/db/migrations/20211029150354_tipo_categoria.php @@ -0,0 +1,14 @@ +table('tipos_categorias') + ->addColumn('nombre', 'string') + ->create(); + } +} diff --git a/api/db/migrations/20211029150551_tipo_categoria.php b/api/db/migrations/20211029150551_tipo_categoria.php deleted file mode 100644 index 7ca9068..0000000 --- a/api/db/migrations/20211029150551_tipo_categoria.php +++ /dev/null @@ -1,26 +0,0 @@ -table('tipos_categoria') - ->addColumn('descripcion', 'string') - ->addColumn('activo', 'boolean') - ->create(); - } -} diff --git a/api/db/migrations/20211029150601_tipo_estado_coneccion.php b/api/db/migrations/20211029150601_tipo_estado_coneccion.php index c99e71f..b1897f5 100644 --- a/api/db/migrations/20211029150601_tipo_estado_coneccion.php +++ b/api/db/migrations/20211029150601_tipo_estado_coneccion.php @@ -18,7 +18,7 @@ final class TipoEstadoConeccion extends AbstractMigration */ public function change(): void { - $this->table('tipos_estado_coneccion') + $this->table('tipos_estados_conecciones') ->addColumn('descripcion', 'string') ->create(); } diff --git a/api/db/migrations/20211029150754_tipo_cuenta.php b/api/db/migrations/20211029150754_tipo_cuenta.php deleted file mode 100644 index 98b7ba1..0000000 --- a/api/db/migrations/20211029150754_tipo_cuenta.php +++ /dev/null @@ -1,26 +0,0 @@ -table('tipos_cuenta') - ->addColumn('descripcion', 'string') - ->addColumn('color', 'string', ['length' => 6, 'default' => 'ffffff']) - ->create(); - } -} diff --git a/api/db/migrations/20211029152716_categoria.php b/api/db/migrations/20211029152716_categoria.php index f20ecef..0b86def 100644 --- a/api/db/migrations/20211029152716_categoria.php +++ b/api/db/migrations/20211029152716_categoria.php @@ -21,7 +21,6 @@ final class Categoria extends AbstractMigration $this->table('categorias') ->addColumn('nombre', 'string') ->addColumn('tipo_id', 'integer') - ->addForeignKey('tipo_id', 'tipos_categoria', ['delete' => 'cascade', 'update' => 'cascade']) ->create(); } } diff --git a/api/db/migrations/20211029152730_tipo_transaccion.php b/api/db/migrations/20211029152730_tipo_transaccion.php new file mode 100644 index 0000000..78d3e00 --- /dev/null +++ b/api/db/migrations/20211029152730_tipo_transaccion.php @@ -0,0 +1,15 @@ +table('tipos_transacciones') + ->addColumn('nombre', 'string') + ->addColumn('color', 'string') + ->create(); + } +} diff --git a/api/db/migrations/20211029152732_cuenta.php b/api/db/migrations/20211029152732_cuenta.php index ec94236..faef895 100644 --- a/api/db/migrations/20211029152732_cuenta.php +++ b/api/db/migrations/20211029152732_cuenta.php @@ -20,10 +20,6 @@ final class Cuenta extends AbstractMigration { $this->table('cuentas') ->addColumn('nombre', 'string') - ->addColumn('categoria_id', 'integer') - ->addForeignKey('categoria_id', 'categorias', ['delete' => 'cascade', 'update' => 'cascade']) - ->addColumn('tipo_id', 'integer') - ->addForeignKey('tipo_id', 'tipos_cuenta', ['delete' => 'cascade', 'update' => 'cascade']) ->create(); } } diff --git a/api/db/migrations/20211029152738_estado_coneccion.php b/api/db/migrations/20211029152738_estado_coneccion.php index c39b435..9c0033d 100644 --- a/api/db/migrations/20211029152738_estado_coneccion.php +++ b/api/db/migrations/20211029152738_estado_coneccion.php @@ -18,12 +18,10 @@ final class EstadoConeccion extends AbstractMigration */ public function change(): void { - $this->table('estados_coneccion') + $this->table('estados_conecciones') ->addColumn('coneccion_id', 'integer') - ->addForeignKey('coneccion_id', 'conecciones', ['delete' => 'cascade', 'update' => 'cascade']) ->addColumn('fecha', 'date') ->addColumn('tipo_id', 'integer') - ->addForeignKey('tipo_id', 'tipos_estado_coneccion', ['delete' => 'cascade', 'update' => 'cascade']) ->create(); } } diff --git a/api/db/migrations/20211029152752_transaccion.php b/api/db/migrations/20211029152752_transaccion.php index fae3397..1c58270 100644 --- a/api/db/migrations/20211029152752_transaccion.php +++ b/api/db/migrations/20211029152752_transaccion.php @@ -19,14 +19,12 @@ final class Transaccion extends AbstractMigration public function change(): void { $this->table('transacciones') - ->addColumn('debito_id', 'integer') - ->addForeignKey('debito_id', 'cuentas', ['delete' => 'cascade', 'update' => 'cascade']) - ->addColumn('credito_id', 'integer') - ->addForeignKey('credito_id', 'cuentas', ['delete' => 'cascade', 'update' => 'cascade']) - ->addColumn('fecha', 'datetime') + ->addColumn('cuenta_id', 'integer') ->addColumn('glosa', 'string') - ->addColumn('detalle', 'text') + ->addColumn('tipo_id', 'integer') ->addColumn('valor', 'double') + ->addColumn('categoria_id', 'integer') + ->addColumn('fecha', 'datetime') ->create(); } } diff --git a/api/db/migrations/20211204210207_cuenta_moneda.php b/api/db/migrations/20211204210207_cuenta_moneda.php index 012c942..1e77051 100644 --- a/api/db/migrations/20211204210207_cuenta_moneda.php +++ b/api/db/migrations/20211204210207_cuenta_moneda.php @@ -20,7 +20,6 @@ final class CuentaMoneda extends AbstractMigration { $this->table('cuentas') ->addColumn('moneda_id', 'integer') - ->addForeignKey('moneda_id', 'monedas', ['delete' => 'cascade', 'update' => 'cascade']) ->update(); } } diff --git a/api/db/migrations/20211205002439_tipo_cambio.php b/api/db/migrations/20211205002439_tipo_cambio.php index 2e89488..bd6687d 100644 --- a/api/db/migrations/20211205002439_tipo_cambio.php +++ b/api/db/migrations/20211205002439_tipo_cambio.php @@ -21,9 +21,9 @@ final class TipoCambio extends AbstractMigration $this->table('tipos_cambio') ->addColumn('fecha', 'datetime') ->addColumn('desde_id', 'integer') - ->addForeignKey('desde_id', 'monedas', ['delete' => 'cascade', 'update' => 'cascade']) + ->addForeignKey('desde_id', 'monedas', ['id'], ['delete' => 'cascade', 'update' => 'cascade']) ->addColumn('hasta_id', 'integer') - ->addForeignKey('hasta_id', 'monedas', ['delete' => 'cascade', 'update' => 'cascade']) + ->addForeignKey('hasta_id', 'monedas', ['id'], ['delete' => 'cascade', 'update' => 'cascade']) ->addColumn('valor', 'double') ->create(); } diff --git a/api/db/migrations/20211329160000_categoria_foreign.php b/api/db/migrations/20211329160000_categoria_foreign.php new file mode 100644 index 0000000..a803a59 --- /dev/null +++ b/api/db/migrations/20211329160000_categoria_foreign.php @@ -0,0 +1,14 @@ +table('categorias') + ->addForeignKey('tipo_id', 'tipos_categorias', ['id'], ['delete' => 'cascade', 'update' => 'cascade']) + ->update(); + } +} diff --git a/api/db/migrations/20211329161000_estado_coneccion_foreign.php b/api/db/migrations/20211329161000_estado_coneccion_foreign.php new file mode 100644 index 0000000..62ea529 --- /dev/null +++ b/api/db/migrations/20211329161000_estado_coneccion_foreign.php @@ -0,0 +1,15 @@ +table('estados_conecciones') + ->addForeignKey('coneccion_id', 'conecciones', ['id'], ['delete' => 'cascade', 'update' => 'cascade']) + ->addForeignKey('tipo_id', 'tipos_estados_conecciones', ['id'], ['delete' => 'cascade', 'update' => 'cascade']) + ->update(); + } +} diff --git a/api/db/migrations/20211329162000_transaccion_foreign.php b/api/db/migrations/20211329162000_transaccion_foreign.php new file mode 100644 index 0000000..5f6b9ea --- /dev/null +++ b/api/db/migrations/20211329162000_transaccion_foreign.php @@ -0,0 +1,16 @@ +table('transacciones') + ->addForeignKey('cuenta_id', 'cuentas', ['id'], ['delete' => 'cascade', 'update' => 'cascade']) + ->addForeignKey('tipo_id', 'tipos_transacciones', ['id'], ['delete' => 'cascade', 'update' => 'cascade']) + ->addForeignKey('categoria_id', 'categorias', ['id'], ['delete' => 'cascade', 'update' => 'cascade']) + ->update(); + } +} diff --git a/api/db/migrations/20211329163000_cuenta_moneda_foreign.php b/api/db/migrations/20211329163000_cuenta_moneda_foreign.php new file mode 100644 index 0000000..a137461 --- /dev/null +++ b/api/db/migrations/20211329163000_cuenta_moneda_foreign.php @@ -0,0 +1,14 @@ +table('cuentas') + ->addForeignKey('moneda_id', 'monedas', ['id'], ['delete' => 'cascade', 'update' => 'cascade']) + ->update(); + } +} diff --git a/api/db/migrations/20220325185534_queue.php b/api/db/migrations/20220325185534_queue.php deleted file mode 100644 index dda0f8f..0000000 --- a/api/db/migrations/20220325185534_queue.php +++ /dev/null @@ -1,27 +0,0 @@ -table('queue') - ->addColumn('command', 'string') - ->addColumn('created', 'datetime') - ->addColumn('processed', 'boolean', ['default' => 0]) - ->create(); - } -} diff --git a/api/db/migrations/20220325185539_queue_arguments.php b/api/db/migrations/20220325185539_queue_arguments.php deleted file mode 100644 index 08496c0..0000000 --- a/api/db/migrations/20220325185539_queue_arguments.php +++ /dev/null @@ -1,28 +0,0 @@ -table('queue_arguments') - ->addColumn('queue_id', 'integer') - ->addForeignKey('queue_id', 'queue', ['delete' => 'cascade', 'update' => 'cascade']) - ->addColumn('argument', 'string', ['length' => 100]) - ->addColumn('value', 'string') - ->create(); - } -} diff --git a/api/db/migrations/20220325191129_consolidados.php b/api/db/migrations/20220325191129_consolidados.php deleted file mode 100644 index 4ea1d5c..0000000 --- a/api/db/migrations/20220325191129_consolidados.php +++ /dev/null @@ -1,29 +0,0 @@ -table('consolidados') - ->addColumn('cuenta_id', 'integer') - ->addForeignKey('cuenta_id', 'cuentas', ['delete' => 'cascade', 'update' => 'cascade']) - ->addColumn('fecha', 'date') - ->addColumn('periodo', 'string', ['length' => 50]) - ->addColumn('saldo', 'double') - ->create(); - } -} diff --git a/api/db/seeds/TipoCuenta.php b/api/db/seeds/TipoCuenta.php deleted file mode 100644 index 5356de6..0000000 --- a/api/db/seeds/TipoCuenta.php +++ /dev/null @@ -1,36 +0,0 @@ - 'Ganancia' - ], - [ - 'descripcion' => 'Activo' - ], - [ - 'descripcion' => 'Pasivo' - ], - [ - 'descripcion' => 'Perdida' - ] - ]; - $this->table('tipos_cuenta') - ->insert($data) - ->saveData(); - } -} diff --git a/api/public/index.php b/api/public/index.php index 925826b..e460051 100644 --- a/api/public/index.php +++ b/api/public/index.php @@ -1,13 +1,8 @@ run(); -} catch (Error | Exception $e) { - error_log($e); - throw $e; -} +ini_set('error_reporting', E_ALL & ~E_NOTICE & ~E_DEPRECATED); +$app = require_once implode(DIRECTORY_SEPARATOR, [ + dirname(__DIR__), + 'setup', + 'app.php' +]); +$app->run(); diff --git a/api/resources/documentation/base.json b/api/resources/documentation/base.json index 8470615..d4f3167 100644 --- a/api/resources/documentation/base.json +++ b/api/resources/documentation/base.json @@ -1,12 +1,433 @@ { - "openapi": "3.0.0", - "info": { - "title": "Contabilidad", - "version": "1.0.0" - }, - "paths": { - "/transactions": { - "description": "List transactions" + "openapi": "3.0.0", + "info": { + "title": "Contabilidad", + "version": "1.0.0" + }, + "paths": { + "/coneccion/{model_id}": { + "get": { + "description": "Entrega coneccion", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "coneccion id", + "required": true + } + ], + "responses": { + "200": { + "description": "coneccion found or null" + } + } + } + }, + "/coneccion/{model_id}/edit": { + "put": { + "description": "", + "parameters": [ + { + "name": "model_id", + "in": "path", + "description": "coneccion id", + "required": true + }, + { + "name": "coneccion", + "in": "query", + "description": "", + "required": true + } + ], + "responses": { + "200": { + "description": "" + } + } + } + }, + "/coneccion/{model_id}/remove": { + "delete": { + "description": "", + "parameters": [ + { + "name": "model_id", + "in": "path", + "description": "coneccion id", + "required": true + } + ], + "responses": { + "200": { + "description": "" + } + } + } + }, + "/conecciones": { + "get": { + "description": "Entrega una lista de conecciones", + "responses": { + "200": { + "description": "Lista de conecciones" + } + } + } + }, + "/conecciones/add": { + "post": { + "description": "Agregar conecciones con una lista", + "parameters": [ + { + "name": "conecciones", + "in": "query", + "description": "Lista de datos para agregar", + "required": true + } + ], + "responses": { + "200": { + "description": "Entrega un listado de conecciones y si fueron agregadas" + } + } + } + }, + "/conecciones/edit": { + "put": { + "description": "Editar multiples conecciones con una lista", + "parameters": [ + { + "name": "conecciones", + "in": "query", + "description": "Lista de datos para editar", + "required": true + } + ], + "responses": { + "200": { + "description": "Entrega un listado de conecciones identificando si fueron editados" + } + } + } + }, + "/cuenta/{model_id}": { + "get": { + "description": "Entrega cuenta", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "cuenta id", + "required": true + } + ], + "responses": { + "200": { + "description": "cuenta found or null" + } + } + } + }, + "/cuenta/{model_id}/edit": { + "put": { + "description": "", + "parameters": [ + { + "name": "model_id", + "in": "path", + "description": "cuenta id", + "required": true + }, + { + "name": "cuenta", + "in": "query", + "description": "", + "required": true + } + ], + "responses": { + "200": { + "description": "" + } + } + } + }, + "/cuenta/{model_id}/remove": { + "delete": { + "description": "", + "parameters": [ + { + "name": "model_id", + "in": "path", + "description": "cuenta id", + "required": true + } + ], + "responses": { + "200": { + "description": "" + } + } + } + }, + "/cuentas": { + "get": { + "description": "Entrega una lista de cuentas", + "responses": { + "200": { + "description": "Lista de cuentas" + } + } + } + }, + "/cuentas/add": { + "post": { + "description": "Agregar cuentas con una lista", + "parameters": [ + { + "name": "cuentas", + "in": "query", + "description": "Lista de datos para agregar", + "required": true + } + ], + "responses": { + "200": { + "description": "Entrega un listado de cuentas y si fueron agregadas" + } + } + } + }, + "/cuentas/edit": { + "put": { + "description": "Editar multiples cuentas con una lista", + "parameters": [ + { + "name": "cuentas", + "in": "query", + "description": "Lista de datos para editar", + "required": true + } + ], + "responses": { + "200": { + "description": "Entrega un listado de cuentas identificando si fueron editados" + } + } + } + }, + "/moneda/{model_id}": { + "get": { + "description": "Entrega moneda", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "moneda id", + "required": true + } + ], + "responses": { + "200": { + "description": "moneda found or null" + } + } + } + }, + "/moneda/{model_id}/edit": { + "put": { + "description": "", + "parameters": [ + { + "name": "model_id", + "in": "path", + "description": "moneda id", + "required": true + }, + { + "name": "moneda", + "in": "query", + "description": "", + "required": true + } + ], + "responses": { + "200": { + "description": "" + } + } + } + }, + "/moneda/{model_id}/remove": { + "delete": { + "description": "", + "parameters": [ + { + "name": "model_id", + "in": "path", + "description": "moneda id", + "required": true + } + ], + "responses": { + "200": { + "description": "" + } + } + } + }, + "/monedas": { + "get": { + "description": "Entrega una lista de monedas", + "responses": { + "200": { + "description": "Lista de monedas" + } + } + } + }, + "/monedas/add": { + "post": { + "description": "Agregar monedas con una lista", + "parameters": [ + { + "name": "monedas", + "in": "query", + "description": "Lista de datos para agregar", + "required": true + } + ], + "responses": { + "200": { + "description": "Entrega un listado de monedas y si fueron agregadas" + } + } + } + }, + "/monedas/edit": { + "put": { + "description": "Editar multiples monedas con una lista", + "parameters": [ + { + "name": "monedas", + "in": "query", + "description": "Lista de datos para editar", + "required": true + } + ], + "responses": { + "200": { + "description": "Entrega un listado de monedas identificando si fueron editados" + } + } + } + }, + "/transaccion/{model_id}": { + "get": { + "description": "Entrega transaccion", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "transaccion id", + "required": true + } + ], + "responses": { + "200": { + "description": "transaccion found or null" + } + } + } + }, + "/transaccion/{model_id}/edit": { + "put": { + "description": "", + "parameters": [ + { + "name": "model_id", + "in": "path", + "description": "transaccion id", + "required": true + }, + { + "name": "transaccion", + "in": "query", + "description": "", + "required": true + } + ], + "responses": { + "200": { + "description": "" + } + } + } + }, + "/transaccion/{model_id}/remove": { + "delete": { + "description": "", + "parameters": [ + { + "name": "model_id", + "in": "path", + "description": "transaccion id", + "required": true + } + ], + "responses": { + "200": { + "description": "" + } + } + } + }, + "/transacciones": { + "get": { + "description": "Entrega una lista de transacciones", + "responses": { + "200": { + "description": "Lista de transacciones" + } + } + } + }, + "/transacciones/add": { + "post": { + "description": "Agregar transacciones con una lista", + "parameters": [ + { + "name": "transacciones", + "in": "query", + "description": "Lista de datos para agregar", + "required": true + } + ], + "responses": { + "200": { + "description": "Entrega un listado de transacciones y si fueron agregadas" + } + } + } + }, + "/transacciones/edit": { + "put": { + "description": "Editar multiples transacciones con una lista", + "parameters": [ + { + "name": "transacciones", + "in": "query", + "description": "Lista de datos para editar", + "required": true + } + ], + "responses": { + "200": { + "description": "Entrega un listado de transacciones identificando si fueron editados" + } + } + } + } } - } -} +} \ No newline at end of file diff --git a/api/resources/routes/categorias.php b/api/resources/routes/categorias.php new file mode 100644 index 0000000..efdac64 --- /dev/null +++ b/api/resources/routes/categorias.php @@ -0,0 +1,6 @@ +getContainer()->get(\Common\Service\Router::class); +$router->setController($app->getContainer()->get(Categorias::class)); +$router->build(); diff --git a/api/resources/routes/conecciones.php b/api/resources/routes/conecciones.php new file mode 100644 index 0000000..11c48ed --- /dev/null +++ b/api/resources/routes/conecciones.php @@ -0,0 +1,6 @@ +getContainer()->get(\Common\Service\Router::class); +$router->setController($app->getContainer()->get(Conecciones::class)); +$router->build(); diff --git a/api/resources/routes/cuentas.php b/api/resources/routes/cuentas.php index 3fd3ea6..f1b57ea 100644 --- a/api/resources/routes/cuentas.php +++ b/api/resources/routes/cuentas.php @@ -1,12 +1,6 @@ group('/cuentas', function($app) { - $app->post('/add[/]', [Cuentas::class, 'add']); - $app->post('/edit[/]', [Cuentas::class, 'edit']); - $app->get('[/]', Cuentas::class); -}); -$app->group('/cuenta/{cuenta_id}', function($app) { - $app->post('/edit[/]', [Cuentas::class, 'editOne']); - $app->get('[/]', [Cuentas::class, 'get']); -}); +$router = $app->getContainer()->get(\Common\Service\Router::class); +$router->setController($app->getContainer()->get(Cuentas::class)); +$router->build(); diff --git a/api/resources/routes/monedas.php b/api/resources/routes/monedas.php new file mode 100644 index 0000000..017d377 --- /dev/null +++ b/api/resources/routes/monedas.php @@ -0,0 +1,6 @@ +getContainer()->get(\Common\Service\Router::class); +$router->setController($app->getContainer()->get(Monedas::class)); +$router->build(); diff --git a/api/resources/routes/transacciones.php b/api/resources/routes/transacciones.php new file mode 100644 index 0000000..88497b7 --- /dev/null +++ b/api/resources/routes/transacciones.php @@ -0,0 +1,6 @@ +getContainer()->get(\Common\Service\Router::class); +$router->setController($app->getContainer()->get(Transacciones::class)); +$router->build(); diff --git a/api/setup/middlewares/99_error_handler.php b/api/setup/middlewares/99_error_handler.php index 29c59fa..d6926de 100644 --- a/api/setup/middlewares/99_error_handler.php +++ b/api/setup/middlewares/99_error_handler.php @@ -1,2 +1,4 @@ add($app->getContainer()->get(Zeuxisoo\Whoops\Slim\WhoopsMiddleware::class)); +$errorMiddleware = $app->addErrorMiddleware(true, true, true); +$errorMiddleware->setDefaultErrorHandler($app->getContainer()->get(\Common\Middleware\Error::class)); diff --git a/api/setup/settings/02_common.php b/api/setup/settings/02_common.php index 38c7030..14867d8 100644 --- a/api/setup/settings/02_common.php +++ b/api/setup/settings/02_common.php @@ -36,5 +36,11 @@ return [ 'python' => 'http://python:5000' ]; return (object) $arr; + }, + 'documentation' => function(Container $container) { + return \ProVM\Implement\Path::fromArray([ + $container->get('folders')->documentation, + 'base.json' + ]); } ]; diff --git a/api/setup/setups/02_database.php b/api/setup/setups/02_database.php index f602bc4..2d265ea 100644 --- a/api/setup/setups/02_database.php +++ b/api/setup/setups/02_database.php @@ -10,5 +10,8 @@ return [ $settings->user['password'], $settings->name ); + }, + \ProVM\Concept\Factory\Model::class => function(ContainerInterface $container) { + return new \ProVM\Implement\Factory\Model($container); } ]; diff --git a/api/setup/setups/03_documenter.php b/api/setup/setups/03_documenter.php new file mode 100644 index 0000000..38dd2d1 --- /dev/null +++ b/api/setup/setups/03_documenter.php @@ -0,0 +1,8 @@ + function(ContainerInterface $container) { + return new \Common\Service\Documenter($container->get('documentation')); + } +]; diff --git a/api/src/Model/Categoria.php b/api/src/Model/Categoria.php new file mode 100644 index 0000000..4a8c23c --- /dev/null +++ b/api/src/Model/Categoria.php @@ -0,0 +1,29 @@ +tipo = $tipo; + return $this; + } + public function getTipo(): TipoCategoria + { + return $this->tipo; + } + protected string $nombre; + public function setNombre(string $nombre): Categoria + { + $this->nombre = $nombre; + return $this; + } + public function getNombre(): string + { + return $this->nombre; + } +} diff --git a/api/src/Model/Coneccion.php b/api/src/Model/Coneccion.php new file mode 100644 index 0000000..969563b --- /dev/null +++ b/api/src/Model/Coneccion.php @@ -0,0 +1,18 @@ +key = $key; + return $this; + } + public function getKey(): string + { + return $this->key; + } +} diff --git a/api/src/Model/Cuenta.php b/api/src/Model/Cuenta.php index 34d2da2..5e62a98 100644 --- a/api/src/Model/Cuenta.php +++ b/api/src/Model/Cuenta.php @@ -5,16 +5,6 @@ use ProVM\Alias\Model; class Cuenta extends Model { - protected int $id; - public function setId(int $id): Cuenta - { - $this->id = $id; - return $this; - } - public function getId(): int - { - return $this->id; - } protected string $nombre; public function setNombre(string $nombre): Cuenta { @@ -25,4 +15,14 @@ class Cuenta extends Model { return $this->nombre; } + protected Moneda $moneda; + public function setMoneda(Moneda $moneda): Cuenta + { + $this->moneda = $moneda; + return $this; + } + public function getMoneda(): Moneda + { + return $this->moneda; + } } diff --git a/api/src/Model/Estado/Coneccion.php b/api/src/Model/Estado/Coneccion.php new file mode 100644 index 0000000..86b7ffb --- /dev/null +++ b/api/src/Model/Estado/Coneccion.php @@ -0,0 +1,41 @@ +coneccion = $coneccion; + return $this; + } + public function getConeccion(): Base + { + return $this->coneccion; + } + protected DateTimeInterface $fecha; + public function setFecha(DateTimeInterface $fecha): Coneccion + { + $this->fecha = $fecha; + return $this; + } + public function getFecha(): DateTimeInterface + { + return $this->fecha; + } + protected Tipo $tipo; + public function setTipo(Tipo $tipo): Coneccion + { + $this->tipo = $tipo; + return $this; + } + public function getTipo(): Tipo + { + return $this->tipo; + } +} diff --git a/api/src/Model/Moneda.php b/api/src/Model/Moneda.php new file mode 100644 index 0000000..d1c047a --- /dev/null +++ b/api/src/Model/Moneda.php @@ -0,0 +1,68 @@ +denominacion = $denominacion; + return $this; + } + public function getDenominacion(): string + { + return $this->denominacion; + } + protected string $codigo; + public function setCodigo(string $codigo): Moneda + { + $this->codigo = $codigo; + return $this; + } + public function getCodigo(): string + { + return $this->codigo; + } + protected string $prefijo; + public function setPrefijo(string $prefijo): Moneda + { + $this->prefijo = $prefijo; + return $this; + } + public function getPrefijo(): string + { + return $this->prefijo ?? ''; + } + protected string $sufijo; + public function setSufijo(string $sufijo): Moneda + { + $this->sufijo = $sufijo; + return $this; + } + public function getSufijo(): string + { + return $this->sufijo ?? ''; + } + protected int $decimales; + public function setDecimales(int $decimales): Moneda + { + $this->decimales = $decimales; + return $this; + } + public function getDecimales(): int + { + return $this->decimales ?? 0; + } + + public function format(float $value): string + { + $output = [ + $this->getPrefijo(), + number_format($value, $this->getDecimales()), + $this->getSufijo() + ]; + return implode(' ', $output); + } +} diff --git a/api/src/Model/Tipo/Categoria.php b/api/src/Model/Tipo/Categoria.php new file mode 100644 index 0000000..e1c5229 --- /dev/null +++ b/api/src/Model/Tipo/Categoria.php @@ -0,0 +1,18 @@ +nombre = $nombre; + return $this; + } + public function getNombre(): string + { + return $this->nombre; + } +} diff --git a/api/src/Model/Tipo/Estado/Coneccion.php b/api/src/Model/Tipo/Estado/Coneccion.php new file mode 100644 index 0000000..663b470 --- /dev/null +++ b/api/src/Model/Tipo/Estado/Coneccion.php @@ -0,0 +1,18 @@ +descripcion = $descripcion; + return $this; + } + public function getDescripcion(): string + { + return $this->descripcion; + } +} diff --git a/api/src/Model/Tipo/Transaccion.php b/api/src/Model/Tipo/Transaccion.php new file mode 100644 index 0000000..cdbb649 --- /dev/null +++ b/api/src/Model/Tipo/Transaccion.php @@ -0,0 +1,28 @@ +nombre = $nombre; + return $this; + } + public function getNombre(): string + { + return $this->nombre; + } + protected string $color; + public function setColor(string $color): Transaccion + { + $this->color = $color; + return $this; + } + public function getColor(): string + { + return $this->color; + } +} diff --git a/api/src/Model/Transaccion.php b/api/src/Model/Transaccion.php new file mode 100644 index 0000000..2d23242 --- /dev/null +++ b/api/src/Model/Transaccion.php @@ -0,0 +1,70 @@ +cuenta = $cuenta; + return $this; + } + public function getCuenta(): Cuenta + { + return $this->cuenta; + } + protected string $glosa; + public function setGlosa(string $glosa): Transaccion + { + $this->glosa = $glosa; + return $this; + } + public function getGlosa(): string + { + return $this->glosa; + } + protected Tipo $tipo; + public function setTipo(Tipo $tipo): Transaccion + { + $this->tipo = $tipo; + return $this; + } + public function getTipo(): Tipo + { + return $this->tipo; + } + protected float $valor; + public function setValor(float $valor): Transaccion + { + $this->valor = $valor; + return $this; + } + public function getValor(): float + { + return $this->valor; + } + protected Categoria $categoria; + public function setCategoria(Categoria $categoria): Transaccion + { + $this->categoria = $categoria; + return $this; + } + public function getCategoria(): Categoria + { + return $this->categoria; + } + protected DateTimeInterface $fecha; + public function setFecha(DateTimeInterface $fecha): Transaccion + { + $this->fecha = $fecha; + return $this; + } + public function getFecha(): DateTimeInterface + { + return $this->fecha; + } +} diff --git a/api/src/Repository/Categoria.php b/api/src/Repository/Categoria.php new file mode 100644 index 0000000..3629c25 --- /dev/null +++ b/api/src/Repository/Categoria.php @@ -0,0 +1,43 @@ +setTable('categorias'); + $this->addProperties(['tipo_id', 'nombre']); + } + + public function load(array $data_row): Model + { + return (new BaseModel()) + ->setId($data_row['id']) + ->setTipo($this->getFactory()->find(Tipo::class)->fetchById($data_row['tipo_id'])) + ->setNombre($data_row['nombre']); + } + public function create(array $data): Model + { + try { + return $this->fetchByNombre($data['nombre']); + } catch (PDOException $e) { + return (new BaseModel()) + ->setNew() + ->setNombre($data['nombre']); + } + } + public function fetchByNombre(string $nombre): Model + { + $query = $this->getQueryBuilder()->select()->from($this->getTable())->where('nombre = ?'); + return $this->load($this->getDatabase()->prepare($query)->execute([$nombre])[0]); + } +} diff --git a/api/src/Repository/Coneccion.php b/api/src/Repository/Coneccion.php new file mode 100644 index 0000000..9fbce14 --- /dev/null +++ b/api/src/Repository/Coneccion.php @@ -0,0 +1,41 @@ +setTable('conecciones'); + $this->addProperties(['key']); + } + + public function load(array $data_row): Model + { + return (new BaseModel()) + ->setId($data_row['id']) + ->setKey($data_row['key']); + } + public function create(array $data): Model + { + try { + return $this->fetchByKey($data['key']); + } catch (PDOException $e) { + return (new BaseModel()) + ->setNew() + ->setKey($data['key']); + } + } + public function fetchByKey(string $key): Model + { + $query = $this->getQueryBuilder()->select()->from($this->getTable())->where('key = ?'); + return $this->load($this->getDatabase()->prepare($query)->execute([$key])[0]); + } +} diff --git a/api/src/Repository/Cuenta.php b/api/src/Repository/Cuenta.php index 4b1cc85..79fe961 100644 --- a/api/src/Repository/Cuenta.php +++ b/api/src/Repository/Cuenta.php @@ -5,23 +5,22 @@ use Psr\Database\DatabaseInterface; use PDOException; use ProVM\Alias\Repository; use ProVM\Concept\Model; -use ProVM\Implement\Database\QueryBuilder; use Contabilidad\Model\Cuenta as BaseModel; class Cuenta extends Repository { - public function __construct(DatabaseInterface $database, QueryBuilder $builder) + public function setup(): void { - parent::__construct($database, $builder); $this->setTable('cuentas'); - $this->setProperties(['id', 'nombre', 'tipo']); + $this->addProperties(['nombre']); } public function load(array $data_row): Model { return (new BaseModel()) ->setId($data_row['id']) - ->setNombre($data_row['nombre']); + ->setNombre($data_row['nombre']) + ->setMoneda($this->getFactory()->find(Moneda::class)->fetchById($data_row['moneda_id'])); } public function create(array $data): Model { @@ -30,23 +29,13 @@ class Cuenta extends Repository } catch (PDOException $e) { return (new BaseModel()) ->setNew() - ->setNombre($data['nombre']); + ->setNombre($data['nombre']) + ->setMoneda($this->getFactory()->find(Moneda::class)->fetchById($data['moneda_id'])); } } - - public function fetchById(int $id): Model - { - $query = $this->getQueryBuilder()->select()->from($this->getTable())->where('id = ?')->build(); - return $this->load($this->getDatabase()->prepare($query)->execute([$id])[0]); - } public function fetchByNombre(string $nombre): Model { $query = $this->getQueryBuilder()->select()->from($this->getTable())->where('nombre = ?')->build(); return $this->load($this->getDatabase()->prepare($query)->execute([$nombre])[0]); } - public function delete(Model $model): void - { - $query = $this->getQueryBuilder()->delete()->from($this->getTable())->where('id = ?')->build(); - $this->getDatabase()->prepare($query)->delete([$model->getId()]); - } } diff --git a/api/src/Repository/Estado/Coneccion.php b/api/src/Repository/Estado/Coneccion.php new file mode 100644 index 0000000..aed491d --- /dev/null +++ b/api/src/Repository/Estado/Coneccion.php @@ -0,0 +1,36 @@ +setTable('estados_conecciones'); + $this->addProperties(['coneccion_id', 'fecha', 'tipo_id']); + } + + public function load(array $data_row): Model + { + return (new BaseModel()) + ->setId($data_row['id']) + ->setConeccion($this->getFactory()->find(Base::class)->fetchById($data_row['coneccion_id'])) + ->setFecha(new DateTimeImmutable($data_row['fecha'])) + ->setTipo($this->getFactory()->find(Tipo::class)->fetchById($data_row['tipo_id'])); + } + public function create(array $data): Model + { + return (new BaseModel()) + ->setNew() + ->setFecha(new DateTimeImmutable($data['fecha'])); + } +} diff --git a/api/src/Repository/Moneda.php b/api/src/Repository/Moneda.php new file mode 100644 index 0000000..ab25024 --- /dev/null +++ b/api/src/Repository/Moneda.php @@ -0,0 +1,56 @@ +setTable('monedas'); + $this->setProperties(['denominacion', 'codigo', 'prefijo', 'sufijo', 'decimales']); + } + + public function load(array $data_row): Model + { + return (new BaseModel()) + ->setId($data_row['id']) + ->setDenominacion($data_row['denominacion']) + ->setCodigo($data_row['codigo']) + ->setPrefijo($data_row['prefijo']) + ->setSufijo($data_row['sufijo']) + ->setDecimales($data_row['decimales']); + } + + public function create(array $data): Model + { + try { + return $this->fetchByCodigo($data['codigo']); + } catch (\PDOException $e) { + try { + return $this->fetchByDenominacion($data['denominacion']); + } catch (\PDOException $e) { + return (new BaseModel()) + ->setNew() + ->setDenominacion($data['denominacion']) + ->setCodigo($data['codigo']) + ->setPrefijo($data['prefijo']) + ->setSufijo($data['sufijo']) + ->setDecimales($data['decimales']); + } + } + } + + public function fetchByCodigo(string $codigo): Moneda + { + $query = $this->getQueryBuilder()->select()->where('codigo = ?'); + return $this->load($this->getDatabase()->prepare($query)->execute([$codigo])[0]); + } + public function fetchByDenominacion(string $denominacion): Moneda + { + $query = $this->getQueryBuilder()->select()->where('denominacion = ?'); + return $this->load($this->getDatabase()->prepare($query)->execute([$denominacion])[0]); + } +} diff --git a/api/src/Repository/Tipo/Categoria.php b/api/src/Repository/Tipo/Categoria.php new file mode 100644 index 0000000..d3d1dfe --- /dev/null +++ b/api/src/Repository/Tipo/Categoria.php @@ -0,0 +1,41 @@ +setTable('tipos_categorias'); + $this->addProperties(['nombre']); + } + + public function load(array $data_row): Model + { + return (new BaseModel()) + ->setId($data_row['id']) + ->setNombre($data_row['nombre']); + } + public function create(array $data): Model + { + try { + return $this->fetchByNombre($data['nombre']); + } catch (PDOException $e) { + return (new BaseModel()) + ->setNew() + ->setNombre($data['nombre']); + } + } + public function fetchByNombre(string $nombre): Model + { + $query = $this->getQueryBuilder()->select()->from($this->getTable())->where('nombre = ?'); + return $this->load($this->getDatabase()->prepare($query)->execute([$nombre])[0]); + } +} diff --git a/api/src/Repository/Tipo/Estado/Coneccion.php b/api/src/Repository/Tipo/Estado/Coneccion.php new file mode 100644 index 0000000..2b6c481 --- /dev/null +++ b/api/src/Repository/Tipo/Estado/Coneccion.php @@ -0,0 +1,41 @@ +setTable('tipos_estados_conecciones'); + $this->addProperties(['descripcion']); + } + + public function load(array $data_row): Model + { + return (new BaseModel()) + ->setId($data_row['id']) + ->setDescripcion($data_row['descripcion']); + } + public function create(array $data): Model + { + try { + return $this->fetchByDescripcion($data['descripcion']); + } catch (PDOException $e) { + return (new BaseModel()) + ->setNew() + ->setDescripcion($data['descripcion']); + } + } + public function fetchByDescripcion(string $descripcion): Model + { + $query = $this->getQueryBuilder()->select()->from($this->getTable())->where('descripcion = ?'); + return $this->load($this->getDatabase()->prepare($query)->execute([$descripcion])[0]); + } +} diff --git a/api/src/Repository/Transaccion.php b/api/src/Repository/Transaccion.php new file mode 100644 index 0000000..88359bd --- /dev/null +++ b/api/src/Repository/Transaccion.php @@ -0,0 +1,41 @@ +setTable('cuentas'); + $this->addProperties(['nombre']); + } + + public function load(array $data_row): Model + { + return (new BaseModel()) + ->setId($data_row['id']) + ->setCuenta($this->getFactory()->find(Cuenta::class)->fetchById($data_row['cuenta_id'])) + ->setGlosa($data_row['glosa']) + ->setTipo($this->getFactory()->find(Tipo::class)->fetchById($data_row['tipo_id'])) + ->setValor($data_row['valor']) + ->setCategoria($this->getFactory()->find(Categoria::class)->fetchById($data_row['categoria_id'])) + ->setFecha(new DateTimeImmutable($data_row['fecha'])); + } + + public function create(array $data): Model + { + return (new BaseModel()) + ->setNew() + ->setCuenta($this->getFactory()->find(Cuenta::class)->fetchById($data['cuenta_id'])) + ->setGlosa($data['glosa']) + ->setTipo($this->getFactory()->find(Tipo::class)->fetchById($data['tipo_id'])) + ->setValor($data['valor']) + ->setCategoria($this->getFactory()->find(Categoria::class)->fetchById($data['categoria_id'])) + ->setFecha(new DateTimeImmutable($data['fecha'])); + } +} diff --git a/docker-compose.yml b/docker-compose.yml index 762a041..619cc94 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -39,6 +39,8 @@ services: <<: *restart image: mariadb env_file: .db.env + ports: + - "3309:3306" volumes: - contabilidad_data:/var/lib/mysql adminer: