2022-12-20

This commit is contained in:
2022-12-20 14:13:05 -03:00
parent 85fef16b27
commit 0f3febc00d
87 changed files with 2525 additions and 419 deletions

View File

@ -0,0 +1,186 @@
<?php
namespace ProVM\Alias\API;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use PDOException;
use function Safe\{error_log, json_decode};
use ProVM\Alias\Controller\Json;
use ProVM\Concept\API\Controller as ControllerInterface;
use ProVM\Concept\Repository;
abstract class Controller implements ControllerInterface
{
use Json;
public function __construct(ContainerInterface $container)
{
$this->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);
}
}

View File

@ -0,0 +1,107 @@
<?php
namespace ProVM\Alias\API\Route;
use ProVM\Concept\API\Route\Operation as OperationInterface;
use ProVM\Concept\API\Route\Parameter;
use ProVM\Concept\API\Route\Response;
abstract class Operation implements OperationInterface
{
protected array $tags;
public function setTags(array $tags): OperationInterface
{
foreach ($tags as $tag) {
$this->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;
}
}

View File

@ -0,0 +1,74 @@
<?php
namespace ProVM\Alias\API\Route;
use ProVM\Concept\API\Route\Parameter as ParameterInterface;
abstract class Parameter implements ParameterInterface
{
protected string $name;
public function setName(string $name): ParameterInterface
{
$this->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;
}
}

View File

@ -0,0 +1,66 @@
<?php
namespace ProVM\Alias\API\Route;
use ProVM\Concept\API\Route\Response as ResponseInterface;
abstract class Response implements ResponseInterface
{
protected string $description;
public function setDescription(string $description): ResponseInterface
{
$this->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;
}
}

View File

@ -0,0 +1,95 @@
<?php
namespace ProVM\Alias\API\Route;
use ProVM\Concept\API\Route\Route as RouteInterface;
use ProVM\Concept\API\Route\Operation;
use ProVM\Concept\API\Route\Parameter;
abstract class Route implements RouteInterface
{
protected string $ref;
public function setRef(string $ref): RouteInterface
{
$this->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;
}
}

View File

@ -1,10 +1,30 @@
<?php <?php
namespace ProVM\Alias\Database; namespace ProVM\Alias\Database;
use Error;
use function Safe\error_log;
use ProVM\Concept\Database\Query as QueryInterface; use ProVM\Concept\Database\Query as QueryInterface;
abstract class Query implements QueryInterface abstract class Query implements QueryInterface
{ {
protected array $errors;
protected function error(Error $error): Query
{
$this->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 public function __toString(): string
{ {
return $this->build(); return $this->build();

View File

@ -3,7 +3,6 @@ namespace ProVM\Alias\Factory;
use Psr\Container\ContainerInterface; use Psr\Container\ContainerInterface;
use ProVM\Concept\Factory\Model as FactoryInterface; use ProVM\Concept\Factory\Model as FactoryInterface;
use ProVM\Concept\Model as ModelInterface;
use ProVM\Concept\Repository; use ProVM\Concept\Repository;
abstract class Model implements FactoryInterface abstract class Model implements FactoryInterface
@ -18,9 +17,9 @@ abstract class Model implements FactoryInterface
{ {
return $this->container; 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); return $this->getContainer()->get($class);
} }
} }

View File

@ -6,6 +6,17 @@ use ProVM\Concept\Model as ModelInterface;
abstract class Model implements 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; protected bool $new = false;
public function setNew(): ModelInterface public function setNew(): ModelInterface
{ {
@ -60,8 +71,10 @@ abstract class Model implements ModelInterface
public function jsonSerialize(): mixed public function jsonSerialize(): mixed
{ {
$ref = new ReflectionObject($this); $ref = new ReflectionObject($this);
$properties = $ref->getProperties(); $properties = ($ref->getProperties());
$output = []; $output = [
'id' => $this->getId()
];
foreach ($properties as $property) { foreach ($properties as $property) {
if (get_called_class() !== $property->getDeclaringClass()->getName()) { if (get_called_class() !== $property->getDeclaringClass()->getName()) {
continue; continue;

View File

@ -6,16 +6,22 @@ use Error;
use function Safe\error_log; use function Safe\error_log;
use ProVM\Concept\Model; use ProVM\Concept\Model;
use ProVM\Concept\Repository as RepositoryInterface; use ProVM\Concept\Repository as RepositoryInterface;
use ProVM\Concept\Factory\Model as FactoryInterface;
use ProVM\Implement\Database\QueryBuilder; use ProVM\Implement\Database\QueryBuilder;
abstract class Repository implements RepositoryInterface 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->setDatabase($database);
$this->setQueryBuilder($builder); $this->setQueryBuilder($builder);
$this->setFactory($factory);
$this->setProperties(['id']);
$this->setup();
} }
abstract public function setup(): void;
protected QueryBuilder $query; protected QueryBuilder $query;
public function setQueryBuilder(QueryBuilder $builder): RepositoryInterface public function setQueryBuilder(QueryBuilder $builder): RepositoryInterface
{ {
@ -26,6 +32,16 @@ abstract class Repository implements RepositoryInterface
{ {
return $this->query; 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; protected string $table;
public function setTable(string $table): RepositoryInterface public function setTable(string $table): RepositoryInterface
@ -44,6 +60,11 @@ abstract class Repository implements RepositoryInterface
return $this; return $this;
} }
public function setProperties(array $properties): RepositoryInterface public function setProperties(array $properties): RepositoryInterface
{
$this->properties = [];
return $this->addProperties($properties);
}
public function addProperties(array $properties): RepositoryInterface
{ {
foreach ($properties as $property) { foreach ($properties as $property) {
$this->addProperty($property); $this->addProperty($property);
@ -70,11 +91,19 @@ abstract class Repository implements RepositoryInterface
$query = $this->getQueryBuilder()->select()->from($this->getTable())->build(); $query = $this->getQueryBuilder()->select()->from($this->getTable())->build();
return array_map([$this, 'load'], $this->getDatabase()->query($query)); 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 protected function extractProperties(Model $model): array
{ {
$properties = []; $properties = [];
foreach ($this->getProperties() as $p) { foreach ($this->getProperties() as $p) {
if ($model->isNew() and $p === 'id') {
continue;
}
$method = $model::parseGetter($p); $method = $model::parseGetter($p);
if (method_exists($model, $method)) { if (method_exists($model, $method)) {
try { try {
@ -116,4 +145,9 @@ abstract class Repository implements RepositoryInterface
$query = $this->getQueryBuilder()->update()->table($this->getTable())->set($sets)->where('id = ?')->build(); $query = $this->getQueryBuilder()->update()->table($this->getTable())->set($sets)->where('id = ?')->build();
$this->getDatabase()->prepare($query)->update(array_merge($values, [$model->getId()])); $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()]);
}
} }

View File

@ -0,0 +1,23 @@
<?php
namespace ProVM\Concept\API;
use ProVM\Concept\Repository;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
interface Controller
{
public function setSingular(string $singular): Controller;
public function setPlural(string $plural): Controller;
public function getSingular(): string;
public function getPlural(): string;
public function setRepository(Repository $repository): Controller;
public function getRepository(): Repository;
public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface;
public function get(ServerRequestInterface $request, ResponseInterface $response, int $model_id): ResponseInterface;
public function add(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface;
public function edit(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface;
public function editOne(ServerRequestInterface $request, ResponseInterface $response, int $model_id): ResponseInterface;
public function remove(ServerRequestInterface $request, ResponseInterface $response, int $model_id): ResponseInterface;
}

View File

@ -0,0 +1,7 @@
<?php
namespace ProVM\Concept\API;
interface OpenAPI
{
public static function add(array $data);
}

View File

@ -0,0 +1,24 @@
<?php
namespace ProVM\Concept\API\Route;
use JsonSerializable;
use ProVM\Concept\API\OpenAPI;
interface Operation extends JsonSerializable, OpenAPI
{
public function setTags(array $tags): Operation;
public function addTag(string $tag): Operation;
public function getTags(): array;
public function setSummary(string $summary): Operation;
public function getSummary(): string;
public function setDescription(string $description): Operation;
public function getDescription(): string;
public function setParameters(array $parameters): Operation;
public function addParameter(Parameter $parameter): Operation;
public function getParameters(): array;
public function setResponses(array $responses): Operation;
public function addResponse(int $code, Response $response): Operation;
public function getResponses(): array;
public function setDeprecated(): Operation;
public function isDeprecated(): bool;
}

View File

@ -0,0 +1,19 @@
<?php
namespace ProVM\Concept\API\Route;
use JsonSerializable;
use ProVM\Concept\API\OpenAPI;
interface Parameter extends JsonSerializable, OpenAPI
{
public function setName(string $name): Parameter;
public function getName(): string;
public function setIn(string $in): Parameter;
public function getIn(): string;
public function setDescription(string $description): Parameter;
public function getDescription(): string;
public function setRequired(): Parameter;
public function isRequired(): bool;
public function setDeprecated(): Parameter;
public function isDeprecated(): bool;
}

View File

@ -0,0 +1,17 @@
<?php
namespace ProVM\Concept\API\Route;
use JsonSerializable;
use ProVM\Concept\API\OpenAPI;
interface Response extends JsonSerializable, OpenAPI
{
public function setDescription(string $description): Response;
public function getDescription(): string;
public function setHeaders(array $headers): Response;
public function addHeader(string $header): Response;
public function getHeaders(): array;
public function setContent(array $contents): Response;
public function addContent(string $content): Response;
public function getContents(): array;
}

View File

@ -0,0 +1,21 @@
<?php
namespace ProVM\Concept\API\Route;
use JsonSerializable;
use ProVM\Concept\API\OpenAPI;
interface Route extends JsonSerializable, OpenAPI
{
public function setRef(string $ref): Route;
public function getRef(): string;
public function setSummary(string $summary): Route;
public function getSummary(): string;
public function setDescription(string $description): Route;
public function getDescription(): string;
public function setMethods(array $methods): Route;
public function addMethod(string $method, Operation $operation): Route;
public function getMethods(): array;
public function setParameters(array $parameters): Route;
public function addParameter(Parameter $parameter): Route;
public function getParameters(): array;
}

View File

@ -6,5 +6,5 @@ use ProVM\Concept\Repository;
interface Model interface Model
{ {
public function find(ModelInterface $model_name): Repository; public function find(string $model_name): Repository;
} }

View File

@ -0,0 +1,37 @@
<?php
namespace ProVM\Implement\API\Route;
use ProVM\Alias\API\Route\Operation as BaseOperation;
class Operation extends BaseOperation
{
public static function add(array $data): Operation
{
$operation = new Operation();
if (isset($data['tags'])) {
$operation->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;
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace ProVM\Implement\API\Route;
use ProVM\Alias\API\Route\Parameter as BaseParameter;
class Parameter extends BaseParameter
{
public static function add(array $data): Parameter
{
$parameter = new Parameter();
$parameter->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;
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace ProVM\Implement\API\Route;
use ProVM\Alias\API\Route\Response as BaseResponse;
class Response extends BaseResponse
{
public static function add(array $data): Response
{
$response = new Response();
$response->setDescription($data['description']);
if (isset($data['headers'])) {
$response->setHeaders($data['headers']);
}
if (isset($data['content'])) {
$response->setContent($data['content']);
}
return $response;
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace ProVM\Implement\API\Route;
use ProVM\Alias\API\Route\Route as BaseRoute;
class Route extends BaseRoute
{
public static function add(array $data): Route
{
$route = new Route();
if (isset($data['ref'])) {
$route->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;
}
}

View File

@ -1,7 +1,7 @@
<?php <?php
namespace ProVM\Implement\Database; namespace ProVM\Implement\Database;
use Common\Alias\Database; use ProVM\Alias\Database;
class MySQL extends Database class MySQL extends Database
{ {

View File

@ -1,7 +1,7 @@
<?php <?php
namespace ProVM\Implement\Database\Query\MySQL; namespace ProVM\Implement\Database\Query\MySQL;
use Common\Alias\Database\Query; use ProVM\Alias\Database\Query;
class Delete extends Query class Delete extends Query
{ {

View File

@ -1,7 +1,8 @@
<?php <?php
namespace ProVM\Implement\Database\Query\MySQL; namespace ProVM\Implement\Database\Query\MySQL;
use Common\Alias\Database\Query; use Error;
use ProVM\Alias\Database\Query;
class Insert extends Query class Insert extends Query
{ {
@ -85,8 +86,8 @@ class Insert extends Query
$output []= $this->getTable(); $output []= $this->getTable();
try { try {
$output []= "({$this->getColumns()})"; $output []= "({$this->getColumns()})";
} catch (\Error $e) { } catch (Error $e) {
\Safe\error_log($e); $this->error($e);
} }
try { try {
$output []= $this->getSelect(); $output []= $this->getSelect();
@ -95,9 +96,10 @@ class Insert extends Query
} }
try { try {
$output []= "ON DUPLICATE KEY UPDATE {$this->getUpdates()}"; $output []= "ON DUPLICATE KEY UPDATE {$this->getUpdates()}";
} catch (\Error $e) { } catch (Error $e) {
\Safe\error_log($e); $this->error($e);
} }
$this->log();
return implode(' ', $output); return implode(' ', $output);
} }
} }

View File

@ -1,7 +1,9 @@
<?php <?php
namespace ProVM\Implement\Database\Query\MySQL; namespace ProVM\Implement\Database\Query\MySQL;
use Common\Alias\Database\Query; use Error;
use function Safe\error_log;
use ProVM\Alias\Database\Query;
class Select extends Query class Select extends Query
{ {
@ -170,41 +172,42 @@ class Select extends Query
$output = ['SELECT']; $output = ['SELECT'];
try { try {
$output []= $this->getSelect(); $output []= $this->getSelect();
} catch (\Error $e) { } catch (Error $e) {
$output []= '*'; $output []= '*';
} }
$output []= 'FROM'; $output []= 'FROM';
$output []= $this->getFrom(); $output []= $this->getFrom();
try { try {
$output [] = $this->getJoins(); $output [] = $this->getJoins();
} catch (\Error $e) { } catch (Error $e) {
\Safe\error_log($e); $this->error($e);
} }
try { try {
$output []= "WHERE {$this->getWheres()}"; $output []= "WHERE {$this->getWheres()}";
} catch (\Error $e) { } catch (Error $e) {
\Safe\error_log($e); $this->error($e);
} }
try { try {
$output []= "GROUP BY {$this->getGroups()}"; $output []= "GROUP BY {$this->getGroups()}";
} catch (\Error $e) { } catch (Error $e) {
\Safe\error_log($e); $this->error($e);
} }
try { try {
$output []= "HAVING {$this->getHaving()}"; $output []= "HAVING {$this->getHaving()}";
} catch (\Error $e) { } catch (Error $e) {
\Safe\error_log($e); $this->error($e);
} }
try { try {
$output []= "ORDER BY {$this->getOrders()}"; $output []= "ORDER BY {$this->getOrders()}";
} catch (\Error $e) { } catch (Error $e) {
\Safe\error_log($e); $this->error($e);
} }
try { try {
$output []= "LIMIT {$this->getLimit()}"; $output []= "LIMIT {$this->getLimit()}";
} catch (\Error $e) { } catch (Error $e) {
\Safe\error_log($e); $this->error($e);
} }
$this->log();
return implode(' ', $output); return implode(' ', $output);
} }
} }

View File

@ -1,7 +1,7 @@
<?php <?php
namespace ProVM\Implement\Database\Query\MySQL; namespace ProVM\Implement\Database\Query\MySQL;
use Common\Alias\Database\Query; use ProVM\Alias\Database\Query;
class Update extends Query class Update extends Query
{ {

View File

@ -1,12 +1,12 @@
<?php <?php
namespace ProVM\Implement\Database; namespace ProVM\Implement\Database;
use Common\Concept\Database\Query;
use Contabilidad\Implement\Database\Query\MySQL\Delete;
use Contabilidad\Implement\Database\Query\MySQL\Insert;
use Contabilidad\Implement\Database\Query\MySQL\Select;
use Contabilidad\Implement\Database\Query\MySQL\Update;
use Psr\Container\ContainerInterface; use Psr\Container\ContainerInterface;
use ProVM\Concept\Database\Query;
use ProVM\Implement\Database\Query\MySQL\Delete;
use ProVM\Implement\Database\Query\MySQL\Insert;
use ProVM\Implement\Database\Query\MySQL\Select;
use ProVM\Implement\Database\Query\MySQL\Update;
class QueryBuilder class QueryBuilder
{ {
@ -20,7 +20,7 @@ class QueryBuilder
]; ];
foreach ($arr as $b) { foreach ($arr as $b) {
$builder = implode("\\", [ $builder = implode("\\", [
'Contabilidad', 'ProVM',
'Implement', 'Implement',
'Database', 'Database',
'Query', 'Query',

View File

@ -0,0 +1,13 @@
<?php
namespace ProVM\Implement\Factory;
use Psr\Container\ContainerInterface;
use ProVM\Alias\Factory\Model as BaseModel;
class Model extends BaseModel
{
public function __construct(ContainerInterface $container)
{
$this->setContainer($container);
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace ProVM\Implement\Factory;
use Psr\Container\ContainerInterface;
use ProVM\Concept\Repository as RepositoryInterface;
class Repository
{
protected ContainerInterface $container;
public function setContainer(ContainerInterface $container): Repository
{
$this->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);
}
}

View File

@ -6,6 +6,7 @@ use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use function Safe\{json_decode, file_get_contents}; use function Safe\{json_decode, file_get_contents};
use ProVM\Alias\Controller\Json; use ProVM\Alias\Controller\Json;
use ProVM\Implement\Path;
class Base class Base
{ {
@ -13,12 +14,8 @@ class Base
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, ContainerInterface $container): ResponseInterface public function __invoke(ServerRequestInterface $request, ResponseInterface $response, ContainerInterface $container): ResponseInterface
{ {
$folder = $container->get('folders')->documentation; $filename = $container->get('documentation');
$filename = implode(DIRECTORY_SEPARATOR, [ $documentation = json_decode(trim(file_get_contents($filename)));
$folder,
'base.json'
]);
$documentation = json_decode(file_get_contents($filename));
return $this->withJson($response, $documentation); return $this->withJson($response, $documentation);
} }
} }

View File

@ -0,0 +1,16 @@
<?php
namespace Common\Controller;
use Psr\Container\ContainerInterface;
use ProVM\Alias\API\Controller;
use Contabilidad\Repository\Categoria;
class Categorias extends Controller
{
public function setup(ContainerInterface $container): void
{
$this->setSingular('categoria')
->setPlural('categorias')
->setRepository($container->get(Categoria::class));
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace Common\Controller;
use Psr\Container\ContainerInterface;
use ProVM\Alias\API\Controller;
use Contabilidad\Repository\Coneccion;
class Conecciones extends Controller
{
public function setup(ContainerInterface $container): void
{
$this->setSingular('coneccion')
->setPlural('conecciones')
->setRepository($container->get(Coneccion::class));
}
}

View File

@ -1,125 +1,16 @@
<?php <?php
namespace Common\Controller; namespace Common\Controller;
use Psr\Http\Message\ResponseInterface; use Psr\Container\ContainerInterface;
use Psr\Http\Message\ServerRequestInterface; use ProVM\Alias\API\Controller;
use PDOException;
use function Safe\{json_decode,error_log};
use ProVM\Alias\Controller\Json;
use Contabilidad\Repository\Cuenta; use Contabilidad\Repository\Cuenta;
class Cuentas class Cuentas extends Controller
{ {
use Json; public function setup(ContainerInterface $container): void
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, Cuenta $repository): ResponseInterface
{ {
$cuentas = []; $this->setSingular('cuenta')
try { ->setPlural('cuentas')
$cuentas = $repository->fetchAll(); ->setRepository($container->get(Cuenta::class));
} 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);
} }
} }

View File

@ -0,0 +1,17 @@
<?php
namespace Common\Controller\Estado;
use Psr\Container\ContainerInterface;
use ProVM\Alias\API\Controller;
use Contabilidad\Repository\Estado\Coneccion;
class Conecciones extends Controller
{
public function setup(ContainerInterface $container): void
{
$this->setSingular('estado_coneccion')
->setPlural('estados_conecciones')
->setRepository($container->get(Coneccion::class));
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace Common\Controller;
use Psr\Container\ContainerInterface;
use ProVM\Alias\API\Controller;
use Contabilidad\Repository\Moneda;
class Monedas extends Controller
{
public function setup(ContainerInterface $container): void
{
$this->setSingular('moneda');
$this->setPlural('monedas');
$this->setRepository($container->get(Moneda::class));
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace Common\Controller;
use Psr\Container\ContainerInterface;
use ProVM\Alias\API\Controller;
use Contabilidad\Repository\Transaccion;
class Transacciones extends Controller
{
public function setup(ContainerInterface $container): void
{
$this->setSingular('transaccion');
$this->setPlural('transacciones');
$this->setRepository($container->get(Transaccion::class));
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace Common\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Throwable;
use Slim\App;
use Slim\Interfaces\ErrorHandlerInterface;
use function Safe\error_log;
class Error implements ErrorHandlerInterface
{
public function __construct(App $app)
{
$this->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');
}
}

View File

@ -1,36 +1,74 @@
<?php <?php
namespace Common\Service; namespace Common\Service;
use Psr\Container\NotFoundExceptionInterface;
use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ServerRequestInterface as Request;
use DI\NotFoundException;
class Auth { class Auth {
protected string $key; protected string $key;
public function __construct(string $api_key) { public function __construct(string $api_key)
{
$this->key = $api_key; $this->key = $api_key;
} }
public function isValid(Request $request): bool { public function isValid(Request $request): bool
if ($request->hasHeader('Authorization')) { {
$sent_key = $this->getAuthKey($request->getHeader('Authorization')); return $this->key == $this->getKey($request);
return $this->key == $sent_key; }
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'])) { if (isset($request->getParsedBody()['api_key'])) {
$sent_key = $request->getParsedBody()['api_key']; return $request->getParsedBody()['api_key'];
return $this->key == $sent_key;
} }
$post = $request->getParsedBody() ?? json_decode($request->getBody()); $post = $request->getParsedBody() ?? json_decode($request->getBody());
$sent_key = $this->getArrayKey($post); try {
if ($sent_key !== null) { return $this->getArrayKey($post);
return $this->key == $sent_key; } 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)) { if (is_array($auth)) {
$auth = $auth[0]; $auth = $auth[0];
} }
if (str_contains($auth, 'Bearer')) { if (str_contains($auth, 'Bearer')) {
$auth = explode(' ', $auth)[1]; $auth = trim(str_replace('Bearer', '', $auth), ' ,');
} }
return $auth; return $auth;
} }

View File

@ -0,0 +1,60 @@
<?php
namespace Common\Service;
use function Safe\{json_encode, json_decode, file_get_contents, file_put_contents};
use ProVM\Concept\API\Route\Route;
use ProVM\Implement\API\Route\Route as RouteObj;
class Documenter
{
public function __construct(string $filename)
{
$this->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));
}
}

View File

@ -0,0 +1,179 @@
<?php
namespace Common\Service;
use Slim\App;
use ProVM\Concept\API\Controller;
use ProVM\Implement\API\Route\Route;
class Router
{
public function __construct(App &$app, Documenter $documenter)
{
$this->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();
}
}

View File

@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class TipoCategoria extends AbstractMigration
{
public function change(): void
{
$this->table('tipos_categorias')
->addColumn('nombre', 'string')
->create();
}
}

View File

@ -1,26 +0,0 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class TipoCategoria extends AbstractMigration
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* https://book.cakephp.org/phinx/0/en/migrations.html#the-change-method
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change(): void
{
$this->table('tipos_categoria')
->addColumn('descripcion', 'string')
->addColumn('activo', 'boolean')
->create();
}
}

View File

@ -18,7 +18,7 @@ final class TipoEstadoConeccion extends AbstractMigration
*/ */
public function change(): void public function change(): void
{ {
$this->table('tipos_estado_coneccion') $this->table('tipos_estados_conecciones')
->addColumn('descripcion', 'string') ->addColumn('descripcion', 'string')
->create(); ->create();
} }

View File

@ -1,26 +0,0 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class TipoCuenta extends AbstractMigration
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* https://book.cakephp.org/phinx/0/en/migrations.html#the-change-method
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change(): void
{
$this->table('tipos_cuenta')
->addColumn('descripcion', 'string')
->addColumn('color', 'string', ['length' => 6, 'default' => 'ffffff'])
->create();
}
}

View File

@ -21,7 +21,6 @@ final class Categoria extends AbstractMigration
$this->table('categorias') $this->table('categorias')
->addColumn('nombre', 'string') ->addColumn('nombre', 'string')
->addColumn('tipo_id', 'integer') ->addColumn('tipo_id', 'integer')
->addForeignKey('tipo_id', 'tipos_categoria', ['delete' => 'cascade', 'update' => 'cascade'])
->create(); ->create();
} }
} }

View File

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class TipoTransaccion extends AbstractMigration
{
public function change(): void
{
$this->table('tipos_transacciones')
->addColumn('nombre', 'string')
->addColumn('color', 'string')
->create();
}
}

View File

@ -20,10 +20,6 @@ final class Cuenta extends AbstractMigration
{ {
$this->table('cuentas') $this->table('cuentas')
->addColumn('nombre', 'string') ->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(); ->create();
} }
} }

View File

@ -18,12 +18,10 @@ final class EstadoConeccion extends AbstractMigration
*/ */
public function change(): void public function change(): void
{ {
$this->table('estados_coneccion') $this->table('estados_conecciones')
->addColumn('coneccion_id', 'integer') ->addColumn('coneccion_id', 'integer')
->addForeignKey('coneccion_id', 'conecciones', ['delete' => 'cascade', 'update' => 'cascade'])
->addColumn('fecha', 'date') ->addColumn('fecha', 'date')
->addColumn('tipo_id', 'integer') ->addColumn('tipo_id', 'integer')
->addForeignKey('tipo_id', 'tipos_estado_coneccion', ['delete' => 'cascade', 'update' => 'cascade'])
->create(); ->create();
} }
} }

View File

@ -19,14 +19,12 @@ final class Transaccion extends AbstractMigration
public function change(): void public function change(): void
{ {
$this->table('transacciones') $this->table('transacciones')
->addColumn('debito_id', 'integer') ->addColumn('cuenta_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('glosa', 'string') ->addColumn('glosa', 'string')
->addColumn('detalle', 'text') ->addColumn('tipo_id', 'integer')
->addColumn('valor', 'double') ->addColumn('valor', 'double')
->addColumn('categoria_id', 'integer')
->addColumn('fecha', 'datetime')
->create(); ->create();
} }
} }

View File

@ -20,7 +20,6 @@ final class CuentaMoneda extends AbstractMigration
{ {
$this->table('cuentas') $this->table('cuentas')
->addColumn('moneda_id', 'integer') ->addColumn('moneda_id', 'integer')
->addForeignKey('moneda_id', 'monedas', ['delete' => 'cascade', 'update' => 'cascade'])
->update(); ->update();
} }
} }

View File

@ -21,9 +21,9 @@ final class TipoCambio extends AbstractMigration
$this->table('tipos_cambio') $this->table('tipos_cambio')
->addColumn('fecha', 'datetime') ->addColumn('fecha', 'datetime')
->addColumn('desde_id', 'integer') ->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') ->addColumn('hasta_id', 'integer')
->addForeignKey('hasta_id', 'monedas', ['delete' => 'cascade', 'update' => 'cascade']) ->addForeignKey('hasta_id', 'monedas', ['id'], ['delete' => 'cascade', 'update' => 'cascade'])
->addColumn('valor', 'double') ->addColumn('valor', 'double')
->create(); ->create();
} }

View File

@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class CategoriaForeign extends AbstractMigration
{
public function change(): void
{
$this->table('categorias')
->addForeignKey('tipo_id', 'tipos_categorias', ['id'], ['delete' => 'cascade', 'update' => 'cascade'])
->update();
}
}

View File

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class EstadoConeccionForeign extends AbstractMigration
{
public function change(): void
{
$this->table('estados_conecciones')
->addForeignKey('coneccion_id', 'conecciones', ['id'], ['delete' => 'cascade', 'update' => 'cascade'])
->addForeignKey('tipo_id', 'tipos_estados_conecciones', ['id'], ['delete' => 'cascade', 'update' => 'cascade'])
->update();
}
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class TransaccionForeign extends AbstractMigration
{
public function change(): void
{
$this->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();
}
}

View File

@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class CuentaMonedaForeign extends AbstractMigration
{
public function change(): void
{
$this->table('cuentas')
->addForeignKey('moneda_id', 'monedas', ['id'], ['delete' => 'cascade', 'update' => 'cascade'])
->update();
}
}

View File

@ -1,27 +0,0 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class Queue extends AbstractMigration
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* https://book.cakephp.org/phinx/0/en/migrations.html#the-change-method
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change(): void
{
$this->table('queue')
->addColumn('command', 'string')
->addColumn('created', 'datetime')
->addColumn('processed', 'boolean', ['default' => 0])
->create();
}
}

View File

@ -1,28 +0,0 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class QueueArguments extends AbstractMigration
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* https://book.cakephp.org/phinx/0/en/migrations.html#the-change-method
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change(): void
{
$this->table('queue_arguments')
->addColumn('queue_id', 'integer')
->addForeignKey('queue_id', 'queue', ['delete' => 'cascade', 'update' => 'cascade'])
->addColumn('argument', 'string', ['length' => 100])
->addColumn('value', 'string')
->create();
}
}

View File

@ -1,29 +0,0 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class Consolidados extends AbstractMigration
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* https://book.cakephp.org/phinx/0/en/migrations.html#the-change-method
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change(): void
{
$this->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();
}
}

View File

@ -1,36 +0,0 @@
<?php
use Phinx\Seed\AbstractSeed;
class TipoCuenta extends AbstractSeed
{
/**
* Run Method.
*
* Write your database seeder using this method.
*
* More information on writing seeders is available here:
* https://book.cakephp.org/phinx/0/en/seeding.html
*/
public function run()
{
$data = [
[
'descripcion' => 'Ganancia'
],
[
'descripcion' => 'Activo'
],
[
'descripcion' => 'Pasivo'
],
[
'descripcion' => 'Perdida'
]
];
$this->table('tipos_cuenta')
->insert($data)
->saveData();
}
}

View File

@ -1,13 +1,8 @@
<?php <?php
try { ini_set('error_reporting', E_ALL & ~E_NOTICE & ~E_DEPRECATED);
ini_set('error_reporting', E_ALL & ~E_NOTICE & ~E_DEPRECATED); $app = require_once implode(DIRECTORY_SEPARATOR, [
$app = require_once implode(DIRECTORY_SEPARATOR, [ dirname(__DIR__),
dirname(__DIR__), 'setup',
'setup', 'app.php'
'app.php' ]);
]); $app->run();
$app->run();
} catch (Error | Exception $e) {
error_log($e);
throw $e;
}

View File

@ -1,12 +1,433 @@
{ {
"openapi": "3.0.0", "openapi": "3.0.0",
"info": { "info": {
"title": "Contabilidad", "title": "Contabilidad",
"version": "1.0.0" "version": "1.0.0"
}, },
"paths": { "paths": {
"/transactions": { "/coneccion/{model_id}": {
"description": "List transactions" "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"
}
}
}
}
} }
} }
}

View File

@ -0,0 +1,6 @@
<?php
use Common\Controller\Categorias;
$router = $app->getContainer()->get(\Common\Service\Router::class);
$router->setController($app->getContainer()->get(Categorias::class));
$router->build();

View File

@ -0,0 +1,6 @@
<?php
use Common\Controller\Conecciones;
$router = $app->getContainer()->get(\Common\Service\Router::class);
$router->setController($app->getContainer()->get(Conecciones::class));
$router->build();

View File

@ -1,12 +1,6 @@
<?php <?php
use Common\Controller\Cuentas; use Common\Controller\Cuentas;
$app->group('/cuentas', function($app) { $router = $app->getContainer()->get(\Common\Service\Router::class);
$app->post('/add[/]', [Cuentas::class, 'add']); $router->setController($app->getContainer()->get(Cuentas::class));
$app->post('/edit[/]', [Cuentas::class, 'edit']); $router->build();
$app->get('[/]', Cuentas::class);
});
$app->group('/cuenta/{cuenta_id}', function($app) {
$app->post('/edit[/]', [Cuentas::class, 'editOne']);
$app->get('[/]', [Cuentas::class, 'get']);
});

View File

@ -0,0 +1,6 @@
<?php
use Common\Controller\Monedas;
$router = $app->getContainer()->get(\Common\Service\Router::class);
$router->setController($app->getContainer()->get(Monedas::class));
$router->build();

View File

@ -0,0 +1,6 @@
<?php
use Common\Controller\Transacciones;
$router = $app->getContainer()->get(\Common\Service\Router::class);
$router->setController($app->getContainer()->get(Transacciones::class));
$router->build();

View File

@ -1,2 +1,4 @@
<?php <?php
$app->add($app->getContainer()->get(Zeuxisoo\Whoops\Slim\WhoopsMiddleware::class)); $app->add($app->getContainer()->get(Zeuxisoo\Whoops\Slim\WhoopsMiddleware::class));
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
$errorMiddleware->setDefaultErrorHandler($app->getContainer()->get(\Common\Middleware\Error::class));

View File

@ -36,5 +36,11 @@ return [
'python' => 'http://python:5000' 'python' => 'http://python:5000'
]; ];
return (object) $arr; return (object) $arr;
},
'documentation' => function(Container $container) {
return \ProVM\Implement\Path::fromArray([
$container->get('folders')->documentation,
'base.json'
]);
} }
]; ];

View File

@ -10,5 +10,8 @@ return [
$settings->user['password'], $settings->user['password'],
$settings->name $settings->name
); );
},
\ProVM\Concept\Factory\Model::class => function(ContainerInterface $container) {
return new \ProVM\Implement\Factory\Model($container);
} }
]; ];

View File

@ -0,0 +1,8 @@
<?php
use Psr\Container\ContainerInterface;
return [
\Common\Service\Documenter::class => function(ContainerInterface $container) {
return new \Common\Service\Documenter($container->get('documentation'));
}
];

View File

@ -0,0 +1,29 @@
<?php
namespace Contabilidad\Model;
use ProVM\Alias\Model;
use Contabilidad\Model\Tipo\Categoria as TipoCategoria;
class Categoria extends Model
{
protected TipoCategoria $tipo;
public function setTipo(TipoCategoria $tipo): Categoria
{
$this->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;
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace Contabilidad\Model;
use ProVM\Alias\Model;
class Coneccion extends Model
{
protected string $key;
public function setKey(string $key): Coneccion
{
$this->key = $key;
return $this;
}
public function getKey(): string
{
return $this->key;
}
}

View File

@ -5,16 +5,6 @@ use ProVM\Alias\Model;
class Cuenta extends 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; protected string $nombre;
public function setNombre(string $nombre): Cuenta public function setNombre(string $nombre): Cuenta
{ {
@ -25,4 +15,14 @@ class Cuenta extends Model
{ {
return $this->nombre; return $this->nombre;
} }
protected Moneda $moneda;
public function setMoneda(Moneda $moneda): Cuenta
{
$this->moneda = $moneda;
return $this;
}
public function getMoneda(): Moneda
{
return $this->moneda;
}
} }

View File

@ -0,0 +1,41 @@
<?php
namespace Contabilidad\Model\Estado;
use DateTimeInterface;
use ProVM\Alias\Model;
use Contabilidad\Model\Coneccion as Base;
use Contabilidad\Model\Tipo\Estado\Coneccion as Tipo;
class Coneccion extends Model
{
protected Base $coneccion;
public function setConeccion(Base $coneccion): Coneccion
{
$this->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;
}
}

68
api/src/Model/Moneda.php Normal file
View File

@ -0,0 +1,68 @@
<?php
namespace Contabilidad\Model;
use ProVM\Alias\Model;
class Moneda extends Model
{
protected string $denominacion;
public function setDenominacion(string $denominacion): Moneda
{
$this->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);
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace Contabilidad\Model\Tipo;
use ProVM\Alias\Model;
class Categoria extends Model
{
protected string $nombre;
public function setNombre(string $nombre): Categoria
{
$this->nombre = $nombre;
return $this;
}
public function getNombre(): string
{
return $this->nombre;
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace Contabilidad\Model\Tipo\Estado;
use ProVM\Alias\Model;
class Coneccion extends Model
{
protected string $descripcion;
public function setDescripcion(string $descripcion): Coneccion
{
$this->descripcion = $descripcion;
return $this;
}
public function getDescripcion(): string
{
return $this->descripcion;
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace Contabilidad\Model\Tipo;
use ProVM\Alias\Model;
class Transaccion extends Model
{
protected string $nombre;
public function setNombre(string $nombre): Transaccion
{
$this->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;
}
}

View File

@ -0,0 +1,70 @@
<?php
namespace Contabilidad\Model;
use DateTimeInterface;
use ProVM\Alias\Model;
use Contabilidad\Model\Tipo\Transaccion as Tipo;
class Transaccion extends Model
{
protected Cuenta $cuenta;
public function setCuenta(Cuenta $cuenta): Transaccion
{
$this->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;
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace Contabilidad\Repository;
use Psr\Database\DatabaseInterface;
use PDOException;
use ProVM\Alias\Repository;
use ProVM\Concept\Factory\Model as FactoryInterface;
use ProVM\Concept\Model;
use ProVM\Implement\Database\QueryBuilder;
use Contabilidad\Model\Categoria as BaseModel;
use Contabilidad\Model\Tipo\Categoria as Tipo;
class Categoria extends Repository
{
public function setup(): void
{
$this->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]);
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace Contabilidad\Repository;
use PDOException;
use Psr\Database\DatabaseInterface;
use ProVM\Alias\Repository;
use ProVM\Concept\Factory\Model as FactoryInterface;
use ProVM\Concept\Model;
use ProVM\Implement\Database\QueryBuilder;
use Contabilidad\Model\Coneccion as BaseModel;
class Coneccion extends Repository
{
public function setup(): void
{
$this->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]);
}
}

View File

@ -5,23 +5,22 @@ use Psr\Database\DatabaseInterface;
use PDOException; use PDOException;
use ProVM\Alias\Repository; use ProVM\Alias\Repository;
use ProVM\Concept\Model; use ProVM\Concept\Model;
use ProVM\Implement\Database\QueryBuilder;
use Contabilidad\Model\Cuenta as BaseModel; use Contabilidad\Model\Cuenta as BaseModel;
class Cuenta extends Repository class Cuenta extends Repository
{ {
public function __construct(DatabaseInterface $database, QueryBuilder $builder) public function setup(): void
{ {
parent::__construct($database, $builder);
$this->setTable('cuentas'); $this->setTable('cuentas');
$this->setProperties(['id', 'nombre', 'tipo']); $this->addProperties(['nombre']);
} }
public function load(array $data_row): Model public function load(array $data_row): Model
{ {
return (new BaseModel()) return (new BaseModel())
->setId($data_row['id']) ->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 public function create(array $data): Model
{ {
@ -30,23 +29,13 @@ class Cuenta extends Repository
} catch (PDOException $e) { } catch (PDOException $e) {
return (new BaseModel()) return (new BaseModel())
->setNew() ->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 public function fetchByNombre(string $nombre): Model
{ {
$query = $this->getQueryBuilder()->select()->from($this->getTable())->where('nombre = ?')->build(); $query = $this->getQueryBuilder()->select()->from($this->getTable())->where('nombre = ?')->build();
return $this->load($this->getDatabase()->prepare($query)->execute([$nombre])[0]); 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()]);
}
} }

View File

@ -0,0 +1,36 @@
<?php
namespace Contabilidad\Repository\Estado;
use Psr\Database\DatabaseInterface;
use Safe\DateTimeImmutable;
use ProVM\Alias\Repository;
use ProVM\Concept\Factory\Model as FactoryInterface;
use ProVM\Concept\Model;
use ProVM\Implement\Database\QueryBuilder;
use Contabilidad\Model\Estado\Coneccion as BaseModel;
use Contabilidad\Model\Coneccion as Base;
use Contabilidad\Model\Tipo\Estado\Coneccion as Tipo;
class Coneccion extends Repository
{
public function setup(): void
{
$this->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']));
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace Contabilidad\Repository;
use ProVM\Alias\Repository;
use ProVM\Concept\Model;
use Contabilidad\Model\Moneda as BaseModel;
class Moneda extends Repository
{
public function setup(): void
{
$this->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]);
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace Contabilidad\Repository\Tipo;
use Psr\Database\DatabaseInterface;
use PDOException;
use ProVM\Alias\Repository;
use ProVM\Concept\Factory\Model as FactoryInterface;
use ProVM\Concept\Model;
use ProVM\Implement\Database\QueryBuilder;
use Contabilidad\Model\Tipo\Categoria as BaseModel;
class Categoria extends Repository
{
public function setup(): void
{
$this->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]);
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace Contabilidad\Repository\Tipo\Estado;
use Psr\Database\DatabaseInterface;
use PDOException;
use ProVM\Alias\Repository;
use ProVM\Concept\Factory\Model as FactoryInterface;
use ProVM\Concept\Model;
use ProVM\Implement\Database\QueryBuilder;
use Contabilidad\Model\Tipo\Estado\Coneccion as BaseModel;
class Coneccion extends Repository
{
public function setup(): void
{
$this->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]);
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace Contabilidad\Repository;
use ProVM\Alias\Repository;
use ProVM\Concept\Model;
use Contabilidad\Model\Transaccion as BaseModel;
use Safe\DateTimeImmutable;
class Transaccion extends Repository
{
public function setup(): void
{
$this->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']));
}
}

View File

@ -39,6 +39,8 @@ services:
<<: *restart <<: *restart
image: mariadb image: mariadb
env_file: .db.env env_file: .db.env
ports:
- "3309:3306"
volumes: volumes:
- contabilidad_data:/var/lib/mysql - contabilidad_data:/var/lib/mysql
adminer: adminer: