Limpieza de objetos externos
This commit is contained in:
16
api/ProVM/Alias/Controller/Json.php
Normal file
16
api/ProVM/Alias/Controller/Json.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
namespace ProVM\Alias\Controller;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use function Safe\json_encode;
|
||||
|
||||
trait Json
|
||||
{
|
||||
public function withJson(ResponseInterface $response, $json_data, int $status_code = 200): ResponseInterface
|
||||
{
|
||||
$response->getBody()->write(json_encode($json_data));
|
||||
return $response
|
||||
->withStatus($status_code)
|
||||
->withHeader('Content-Type', 'application/json');
|
||||
}
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
<?php
|
||||
namespace Common\Alias;
|
||||
namespace ProVM\Alias;
|
||||
|
||||
use Common\Concept\Database as DatabaseInterface;
|
||||
use Psr\Database\DatabaseInterface;
|
||||
use Exception;
|
||||
use PDO, PDOException, PDOStatement;
|
||||
|
||||
abstract class Database implements DatabaseInterface
|
||||
{
|
||||
@ -24,7 +26,7 @@ abstract class Database implements DatabaseInterface
|
||||
return $this->port;
|
||||
}
|
||||
protected string $name;
|
||||
public function setName(string $database_name): Database
|
||||
public function setName(string $database_name): DatabaseInterface
|
||||
{
|
||||
$this->name = $database_name;
|
||||
return $this;
|
||||
@ -35,7 +37,7 @@ abstract class Database implements DatabaseInterface
|
||||
}
|
||||
protected string $username;
|
||||
protected string $password;
|
||||
public function setUser(string $username, string $password): Database
|
||||
public function setUser(string $username, string $password): DatabaseInterface
|
||||
{
|
||||
$this->username = $username;
|
||||
$this->password = $password;
|
||||
@ -50,17 +52,17 @@ abstract class Database implements DatabaseInterface
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
protected \PDO $connection;
|
||||
public function connect(): Database
|
||||
protected PDO $connection;
|
||||
public function connect(): DatabaseInterface
|
||||
{
|
||||
if ($this->needsUser()) {
|
||||
$this->connection = new \PDO($this->getDsn(), $this->getUser(), $this->getPassword());
|
||||
$this->connection = new PDO($this->getDsn(), $this->getUser(), $this->getPassword());
|
||||
return $this;
|
||||
}
|
||||
$this->connection = new \PDO($this->getDsn());
|
||||
$this->connection = new PDO($this->getDsn());
|
||||
return $this;
|
||||
}
|
||||
public function getConnection(): \PDO
|
||||
public function getConnection(): PDO
|
||||
{
|
||||
if (!isset($this->connection)) {
|
||||
return $this->connect()->connection;
|
||||
@ -71,38 +73,38 @@ abstract class Database implements DatabaseInterface
|
||||
{
|
||||
$st = $this->getConnection()->query($query);
|
||||
if (!$st) {
|
||||
throw new \PDOException("Could not retrieve anything with '{$query}'.");
|
||||
throw new PDOException("Could not retrieve anything with '{$query}'.");
|
||||
}
|
||||
$results = $st->fetchAll(\PDO::FETCH_ASSOC);
|
||||
$results = $st->fetchAll(PDO::FETCH_ASSOC);
|
||||
if (!$results) {
|
||||
throw new \PDOException('Could not retrieve any results.');
|
||||
throw new PDOException('Could not retrieve any results.');
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
public function beginTransaction(): void
|
||||
{
|
||||
if (!$this->getConnection()->beginTransaction()) {
|
||||
throw new \PDOException('Could not begin transaction.');
|
||||
throw new PDOException('Could not begin transaction.');
|
||||
}
|
||||
}
|
||||
public function commit(): void
|
||||
{
|
||||
if (!$this->getConnection()->commit()) {
|
||||
throw new \PDOException('Could not commit');
|
||||
throw new PDOException('Could not commit');
|
||||
}
|
||||
}
|
||||
public function rollBack(): void
|
||||
{
|
||||
if (!$this->getConnection()->rollBack()) {
|
||||
throw new \PDOException('Could not rollback.');
|
||||
throw new PDOException('Could not rollback.');
|
||||
}
|
||||
}
|
||||
protected \PDOStatement $prepared_statement;
|
||||
public function prepare(string $query): Database
|
||||
protected PDOStatement $prepared_statement;
|
||||
public function prepare(string $query): DatabaseInterface
|
||||
{
|
||||
$st = $this->getConnection()->prepare($query);
|
||||
if (!$st) {
|
||||
throw new \PDOException("Could not prepare query '{$query}'.");
|
||||
throw new PDOException("Could not prepare query '{$query}'.");
|
||||
}
|
||||
$this->prepared_statement = $st;
|
||||
return $this;
|
||||
@ -110,42 +112,42 @@ abstract class Database implements DatabaseInterface
|
||||
public function execute(array $data): array
|
||||
{
|
||||
if (!isset($this->prepared_statement)) {
|
||||
throw new \Exception('No prepared statement.');
|
||||
throw new Exception('No prepared statement.');
|
||||
}
|
||||
if (!$this->prepared_statement->execute($data)) {
|
||||
throw new \PDOException('Could not execute prepared statement.');
|
||||
throw new PDOException('Could not execute prepared statement.');
|
||||
}
|
||||
$results = $this->prepared_statement->fetchAll(\PDO::FETCH_ASSOC);
|
||||
$results = $this->prepared_statement->fetchAll(PDO::FETCH_ASSOC);
|
||||
if (!$results) {
|
||||
throw new \PDOException('Could not retrieve any results.');
|
||||
throw new PDOException('Could not retrieve any results.');
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
public function insert(array $values): void
|
||||
{
|
||||
if (!isset($this->prepared_statement)) {
|
||||
throw new \Exception('No prepared statement.');
|
||||
throw new Exception('No prepared statement.');
|
||||
}
|
||||
if (!$this->prepared_statement->execute($values)) {
|
||||
throw new \PDOException('Could not insert.');
|
||||
throw new PDOException('Could not insert.');
|
||||
}
|
||||
}
|
||||
public function update(array $data): void
|
||||
{
|
||||
if (!isset($this->prepared_statement)) {
|
||||
throw new \Exception('No prepared statement.');
|
||||
throw new Exception('No prepared statement.');
|
||||
}
|
||||
if (!$this->prepared_statement->execute($data)) {
|
||||
throw new \PDOException('Could not update.');
|
||||
throw new PDOException('Could not update.');
|
||||
}
|
||||
}
|
||||
public function delete(array $data): void
|
||||
{
|
||||
if (!isset($this->prepared_statement)) {
|
||||
throw new \Exception('No prepared statement.');
|
||||
throw new Exception('No prepared statement.');
|
||||
}
|
||||
if (!$this->prepared_statement->execute($data)) {
|
||||
throw new \PDOException('Could not delete.');
|
||||
throw new PDOException('Could not delete.');
|
||||
}
|
||||
}
|
||||
}
|
12
api/ProVM/Alias/Database/Query.php
Normal file
12
api/ProVM/Alias/Database/Query.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
namespace ProVM\Alias\Database;
|
||||
|
||||
use ProVM\Concept\Database\Query as QueryInterface;
|
||||
|
||||
abstract class Query implements QueryInterface
|
||||
{
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->build();
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
<?php
|
||||
namespace Common\Alias\Factory;
|
||||
namespace ProVM\Alias\Factory;
|
||||
|
||||
use Common\Concept\Factory\Model as FactoryInterface;
|
||||
use Common\Concept\Model as ModelInterface;
|
||||
use Common\Concept\Repository;
|
||||
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
|
||||
{
|
@ -1,8 +1,8 @@
|
||||
<?php
|
||||
namespace Common\Alias;
|
||||
namespace ProVM\Alias;
|
||||
|
||||
use function Safe\{fopen,fclose,fwrite};
|
||||
use Common\Concept\File as FileInterface;
|
||||
use ProVM\Concept\File as FileInterface;
|
||||
|
||||
abstract class File implements FileInterface
|
||||
{
|
@ -1,8 +1,8 @@
|
||||
<?php
|
||||
namespace Common\Alias;
|
||||
namespace ProVM\Alias;
|
||||
|
||||
use function Safe\{touch,mkdir,unlink};
|
||||
use Common\Concept\Filesystem as FilesystemInterface;
|
||||
use ProVM\Concept\Filesystem as FilesystemInterface;
|
||||
|
||||
abstract class Filesystem implements FilesystemInterface
|
||||
{
|
77
api/ProVM/Alias/Model.php
Normal file
77
api/ProVM/Alias/Model.php
Normal file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
namespace ProVM\Alias;
|
||||
|
||||
use ReflectionObject;
|
||||
use ProVM\Concept\Model as ModelInterface;
|
||||
|
||||
abstract class Model implements ModelInterface
|
||||
{
|
||||
protected bool $new = false;
|
||||
public function setNew(): ModelInterface
|
||||
{
|
||||
$this->new = true;
|
||||
return $this;
|
||||
}
|
||||
public function isNew(): bool
|
||||
{
|
||||
return $this->new;
|
||||
}
|
||||
|
||||
protected array $edited;
|
||||
public function setEdited(string $property): ModelInterface
|
||||
{
|
||||
$this->edited []= $property;
|
||||
return $this;
|
||||
}
|
||||
public function getEdited(): array
|
||||
{
|
||||
return $this->edited;
|
||||
}
|
||||
public function isDirty(): bool
|
||||
{
|
||||
return isset($this->edited) and count($this->edited) > 0;
|
||||
}
|
||||
|
||||
public function edit(array $data): void
|
||||
{
|
||||
$this->edited = [];
|
||||
foreach ($data as $key => $val) {
|
||||
if ($key === 'id') {
|
||||
continue;
|
||||
}
|
||||
$getter = Model::parseGetter($key);
|
||||
$setter = Model::parseSetter($key);
|
||||
if (method_exists($this, $getter) and $this->{$getter}() !== $val) {
|
||||
$this->{$setter}($val);
|
||||
$this->setEdited($key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function parseSetter(string $property): string
|
||||
{
|
||||
return 'set' . str_replace(' ', '', ucwords(str_replace('_', ' ', $property)));
|
||||
}
|
||||
public static function parseGetter(string $property): string
|
||||
{
|
||||
return 'get' . str_replace(' ', '', ucwords(str_replace('_', ' ', $property)));
|
||||
}
|
||||
|
||||
public function jsonSerialize(): mixed
|
||||
{
|
||||
$ref = new ReflectionObject($this);
|
||||
$properties = $ref->getProperties();
|
||||
$output = [];
|
||||
foreach ($properties as $property) {
|
||||
if (get_called_class() !== $property->getDeclaringClass()->getName()) {
|
||||
continue;
|
||||
}
|
||||
$key = $property->getName();
|
||||
$method = Model::parseGetter($key);
|
||||
if (method_exists($this, $method)) {
|
||||
$output[$key] = $this->{$method}();
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
}
|
119
api/ProVM/Alias/Repository.php
Normal file
119
api/ProVM/Alias/Repository.php
Normal file
@ -0,0 +1,119 @@
|
||||
<?php
|
||||
namespace ProVM\Alias;
|
||||
|
||||
use Psr\Database\DatabaseInterface;
|
||||
use Error;
|
||||
use function Safe\error_log;
|
||||
use ProVM\Concept\Model;
|
||||
use ProVM\Concept\Repository as RepositoryInterface;
|
||||
use ProVM\Implement\Database\QueryBuilder;
|
||||
|
||||
abstract class Repository implements RepositoryInterface
|
||||
{
|
||||
public function __construct(DatabaseInterface $database, QueryBuilder $builder)
|
||||
{
|
||||
$this->setDatabase($database);
|
||||
$this->setQueryBuilder($builder);
|
||||
}
|
||||
|
||||
protected QueryBuilder $query;
|
||||
public function setQueryBuilder(QueryBuilder $builder): RepositoryInterface
|
||||
{
|
||||
$this->query = $builder;
|
||||
return $this;
|
||||
}
|
||||
public function getQueryBuilder(): QueryBuilder
|
||||
{
|
||||
return $this->query;
|
||||
}
|
||||
|
||||
protected string $table;
|
||||
public function setTable(string $table): RepositoryInterface
|
||||
{
|
||||
$this->table = $table;
|
||||
return $this;
|
||||
}
|
||||
public function getTable(): string
|
||||
{
|
||||
return $this->table;
|
||||
}
|
||||
protected array $properties;
|
||||
public function addProperty(string $name): RepositoryInterface
|
||||
{
|
||||
$this->properties []= $name;
|
||||
return $this;
|
||||
}
|
||||
public function setProperties(array $properties): RepositoryInterface
|
||||
{
|
||||
foreach ($properties as $property) {
|
||||
$this->addProperty($property);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function getProperties(): array
|
||||
{
|
||||
return $this->properties;
|
||||
}
|
||||
protected DatabaseInterface $database;
|
||||
public function setDatabase(DatabaseInterface $database): RepositoryInterface
|
||||
{
|
||||
$this->database = $database;
|
||||
return $this;
|
||||
}
|
||||
public function getDatabase(): DatabaseInterface
|
||||
{
|
||||
return $this->database;
|
||||
}
|
||||
|
||||
public function fetchAll(): array
|
||||
{
|
||||
$query = $this->getQueryBuilder()->select()->from($this->getTable())->build();
|
||||
return array_map([$this, 'load'], $this->getDatabase()->query($query));
|
||||
}
|
||||
|
||||
protected function extractProperties(Model $model): array
|
||||
{
|
||||
$properties = [];
|
||||
foreach ($this->getProperties() as $p) {
|
||||
$method = $model::parseGetter($p);
|
||||
if (method_exists($model, $method)) {
|
||||
try {
|
||||
$properties[$p] = $model->{$method}();
|
||||
} catch (Error $e) {
|
||||
error_log($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $properties;
|
||||
}
|
||||
public function save(Model $model): void
|
||||
{
|
||||
if ($model->isNew()) {
|
||||
$this->saveNew($model);
|
||||
return;
|
||||
}
|
||||
if ($model->isDirty()) {
|
||||
$this->saveUpdate($model);
|
||||
}
|
||||
}
|
||||
protected function saveNew(Model $model): void
|
||||
{
|
||||
$properties = $this->extractProperties($model);
|
||||
$columns = array_keys($properties);
|
||||
$ivalues = array_map(function($item) {return '?';}, array_keys($properties));
|
||||
$values = array_values($properties);
|
||||
$query = $this->getQueryBuilder()->insert()->into($this->getTable())->columns($columns)->values($ivalues)->build();
|
||||
$this->getDatabase()->prepare($query)->insert($values);
|
||||
}
|
||||
protected function saveUpdate(Model $model): void
|
||||
{
|
||||
$edited = $model->getEdited();
|
||||
$properties = array_intersect_key($this->extractProperties($model), array_combine($edited, $edited));
|
||||
$sets = array_map(function($item) {
|
||||
return "{$item} = ?";
|
||||
}, array_keys($properties));
|
||||
$values = array_values($properties);
|
||||
$query = $this->getQueryBuilder()->update()->table($this->getTable())->set($sets)->where('id = ?')->build();
|
||||
$this->getDatabase()->prepare($query)->update(array_merge($values, [$model->getId()]));
|
||||
}
|
||||
}
|
7
api/ProVM/Concept/Database/Query.php
Normal file
7
api/ProVM/Concept/Database/Query.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace ProVM\Concept\Database;
|
||||
|
||||
interface Query
|
||||
{
|
||||
public function build(): string;
|
||||
}
|
10
api/ProVM/Concept/Factory/Model.php
Normal file
10
api/ProVM/Concept/Factory/Model.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
namespace ProVM\Concept\Factory;
|
||||
|
||||
use ProVM\Concept\Model as ModelInterface;
|
||||
use ProVM\Concept\Repository;
|
||||
|
||||
interface Model
|
||||
{
|
||||
public function find(ModelInterface $model_name): Repository;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
namespace Common\Concept;
|
||||
namespace ProVM\Concept;
|
||||
|
||||
interface File
|
||||
{
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
namespace Common\Concept;
|
||||
namespace ProVM\Concept;
|
||||
|
||||
interface Filesystem
|
||||
{
|
16
api/ProVM/Concept/Model.php
Normal file
16
api/ProVM/Concept/Model.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
namespace ProVM\Concept;
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
interface Model extends JsonSerializable
|
||||
{
|
||||
public function setNew(): Model;
|
||||
public function isNew(): bool;
|
||||
public function setEdited(string $property): Model;
|
||||
public function getEdited(): array;
|
||||
public function isDirty(): bool;
|
||||
public function edit(array $data): void;
|
||||
public static function parseSetter(string $property): string;
|
||||
public static function parseGetter(string $property): string;
|
||||
}
|
@ -1,11 +1,12 @@
|
||||
<?php
|
||||
namespace Common\Concept;
|
||||
namespace ProVM\Concept;
|
||||
|
||||
interface Repository
|
||||
{
|
||||
public function fetchAll(): array;
|
||||
public function fetchByKey($key): Model;
|
||||
public function fetchById(int $id): Model;
|
||||
public function load(array $data_row): Model;
|
||||
public function create(array $data): Model;
|
||||
public function save(Model $model): void;
|
||||
public function delete(Model $model): void;
|
||||
}
|
117
api/ProVM/Implement/Collection.php
Normal file
117
api/ProVM/Implement/Collection.php
Normal file
@ -0,0 +1,117 @@
|
||||
<?php
|
||||
namespace ProVM\Implement;
|
||||
|
||||
use Psr\Collection\CollectionInterface;
|
||||
|
||||
class Collection implements CollectionInterface
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->set(CollectionInterface::class, $this);
|
||||
}
|
||||
protected array $data;
|
||||
public function set(mixed $name, $value): CollectionInterface
|
||||
{
|
||||
$this->data[$name] = $value;
|
||||
return $this;
|
||||
}
|
||||
public function has(mixed $name): bool
|
||||
{
|
||||
return isset($this->data[$name]);
|
||||
}
|
||||
public function get(mixed $name)
|
||||
{
|
||||
return $this->process($this->data[$name]) ?? null;
|
||||
}
|
||||
public function remove(mixed $name): CollectionInterface
|
||||
{
|
||||
unset($this->data[$name]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function process($value)
|
||||
{
|
||||
if (is_callable($value)) {
|
||||
return $this->processCallable($value);
|
||||
}
|
||||
if (is_array($value)) {
|
||||
return $this->processArray($value);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
protected function processCallable(Callable $value)
|
||||
{
|
||||
$ref = new \ReflectionFunction($value);
|
||||
$param_array = [];
|
||||
$params = $ref->getParameters();
|
||||
foreach ($params as $p) {
|
||||
$param_array[$p->getName()] = $this->get($p->getType()->getName());
|
||||
}
|
||||
return $ref->invokeArgs($param_array);
|
||||
}
|
||||
protected function processArray(array $value)
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
public static function fromArray(array $source): CollectionInterface
|
||||
{
|
||||
$obj = new Collection();
|
||||
foreach ($source as $key => $value) {
|
||||
$obj->set($key, $value);
|
||||
}
|
||||
return $obj;
|
||||
}
|
||||
public static function fromObject(object $source): CollectionInterface
|
||||
{
|
||||
return Collection::fromArray((array) $source);
|
||||
}
|
||||
|
||||
public function __get(mixed $name): mixed
|
||||
{
|
||||
return $this->get($name);
|
||||
}
|
||||
|
||||
public function current(): mixed
|
||||
{
|
||||
return $this->data[$this->key()];
|
||||
}
|
||||
public function next(): void
|
||||
{
|
||||
next($this->data);
|
||||
}
|
||||
public function key(): mixed
|
||||
{
|
||||
return key($this->data);
|
||||
}
|
||||
public function valid(): bool
|
||||
{
|
||||
return isset($this->data);
|
||||
}
|
||||
public function rewind(): void
|
||||
{
|
||||
reset($this->data);
|
||||
}
|
||||
|
||||
public function offsetExists(mixed $offset): bool
|
||||
{
|
||||
return $this->has($offset);
|
||||
}
|
||||
public function offsetGet(mixed $offset): mixed
|
||||
{
|
||||
return $this->get($offset);
|
||||
}
|
||||
public function offsetSet(mixed $offset, mixed $value): void
|
||||
{
|
||||
$this->set($offset, $value);
|
||||
}
|
||||
public function offsetUnset(mixed $offset): void
|
||||
{
|
||||
$this->remove($offset);
|
||||
}
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
return count($this->data);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
namespace Contabilidad\Implement\Database;
|
||||
namespace ProVM\Implement\Database;
|
||||
|
||||
use Common\Alias\Database;
|
||||
|
47
api/ProVM/Implement/Database/Query/MySQL/Delete.php
Normal file
47
api/ProVM/Implement/Database/Query/MySQL/Delete.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
namespace ProVM\Implement\Database\Query\MySQL;
|
||||
|
||||
use Common\Alias\Database\Query;
|
||||
|
||||
class Delete extends Query
|
||||
{
|
||||
protected string $table;
|
||||
public function from($table): Delete
|
||||
{
|
||||
$this->table = $table;
|
||||
return $this;
|
||||
}
|
||||
public function getFrom(): string
|
||||
{
|
||||
return $this->table;
|
||||
}
|
||||
protected array $conditions;
|
||||
public function where(array|string $conditions): Delete
|
||||
{
|
||||
if (is_string($conditions)) {
|
||||
return $this->addCondition($conditions);
|
||||
}
|
||||
foreach ($conditions as $condition) {
|
||||
$this->addCondition($condition);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function addCondition(string $condition): Delete
|
||||
{
|
||||
$this->conditions []= $condition;
|
||||
return $this;
|
||||
}
|
||||
public function getWhere(): string
|
||||
{
|
||||
return implode(' AND ', $this->conditions);
|
||||
}
|
||||
|
||||
public function build(): string
|
||||
{
|
||||
$output = ['DELETE FROM'];
|
||||
$output []= $this->getFrom();
|
||||
$output []= "WHERE {$this->getWhere()}";
|
||||
|
||||
return implode(' ', $output);
|
||||
}
|
||||
}
|
103
api/ProVM/Implement/Database/Query/MySQL/Insert.php
Normal file
103
api/ProVM/Implement/Database/Query/MySQL/Insert.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
namespace ProVM\Implement\Database\Query\MySQL;
|
||||
|
||||
use Common\Alias\Database\Query;
|
||||
|
||||
class Insert extends Query
|
||||
{
|
||||
protected string $table;
|
||||
public function into(string $table): Insert
|
||||
{
|
||||
$this->table = $table;
|
||||
return $this;
|
||||
}
|
||||
public function getTable(): string
|
||||
{
|
||||
return $this->table;
|
||||
}
|
||||
protected Select $select;
|
||||
public function select(Select $select): Insert
|
||||
{
|
||||
$this->select = $select;
|
||||
return $this;
|
||||
}
|
||||
public function getSelect(): string
|
||||
{
|
||||
return $this->select->build();
|
||||
}
|
||||
protected array $columns;
|
||||
public function columns(array $columns): Insert
|
||||
{
|
||||
foreach ($columns as $column) {
|
||||
$this->addColumn($column);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function addColumn(string $column): Insert
|
||||
{
|
||||
$this->columns []= $column;
|
||||
return $this;
|
||||
}
|
||||
public function getColumns(): string
|
||||
{
|
||||
return implode(', ', array_map(function($item) {return "`{$item}`";}, $this->columns));
|
||||
}
|
||||
protected array $values;
|
||||
public function values(array $values): Insert
|
||||
{
|
||||
foreach ($values as $value) {
|
||||
$this->addValue($value);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function addValue(string $value): Insert
|
||||
{
|
||||
$this->values []= $value;
|
||||
return $this;
|
||||
}
|
||||
public function getValues(): string
|
||||
{
|
||||
return implode(', ', array_map(function($item) {
|
||||
return $item;
|
||||
}, $this->values));
|
||||
}
|
||||
protected array $updates;
|
||||
public function update(array $updates): Insert
|
||||
{
|
||||
foreach ($updates as $update) {
|
||||
$this->addUpdate($update);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function addUpdate(string $update_string): Insert
|
||||
{
|
||||
$this->updates []= $update_string;
|
||||
return $this;
|
||||
}
|
||||
public function getUpdates(): string
|
||||
{
|
||||
return implode(', ', $this->updates);
|
||||
}
|
||||
|
||||
public function build(): string
|
||||
{
|
||||
$output = ['INSERT INTO'];
|
||||
$output []= $this->getTable();
|
||||
try {
|
||||
$output []= "({$this->getColumns()})";
|
||||
} catch (\Error $e) {
|
||||
\Safe\error_log($e);
|
||||
}
|
||||
try {
|
||||
$output []= $this->getSelect();
|
||||
} catch (\Error $e) {
|
||||
$output []= "VALUES ({$this->getValues()})";
|
||||
}
|
||||
try {
|
||||
$output []= "ON DUPLICATE KEY UPDATE {$this->getUpdates()}";
|
||||
} catch (\Error $e) {
|
||||
\Safe\error_log($e);
|
||||
}
|
||||
return implode(' ', $output);
|
||||
}
|
||||
}
|
210
api/ProVM/Implement/Database/Query/MySQL/Select.php
Normal file
210
api/ProVM/Implement/Database/Query/MySQL/Select.php
Normal file
@ -0,0 +1,210 @@
|
||||
<?php
|
||||
namespace ProVM\Implement\Database\Query\MySQL;
|
||||
|
||||
use Common\Alias\Database\Query;
|
||||
|
||||
class Select extends Query
|
||||
{
|
||||
protected array $columns;
|
||||
public function select(array|string $columns): Select
|
||||
{
|
||||
if (is_string($columns)) {
|
||||
return $this->addColumn($columns);
|
||||
}
|
||||
foreach ($columns as $column) {
|
||||
$this->addColumn($column);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function addColumn(string $column): Select
|
||||
{
|
||||
$this->columns []= $column;
|
||||
return $this;
|
||||
}
|
||||
public function getSelect(): string
|
||||
{
|
||||
return implode(', ', array_map(function($item) {
|
||||
return "`{$item}`";
|
||||
}, $this->columns));
|
||||
}
|
||||
protected string $from;
|
||||
public function from(string $table): Select
|
||||
{
|
||||
$this->from = $table;
|
||||
return $this;
|
||||
}
|
||||
public function getFrom(): string
|
||||
{
|
||||
return $this->from;
|
||||
}
|
||||
protected array $joins;
|
||||
public function join(array $joins): Select
|
||||
{
|
||||
if (is_string($joins[0])) {
|
||||
return $this->addJoin($joins[0], $joins[1], $joins[2]);
|
||||
}
|
||||
foreach ($joins as $join) {
|
||||
$this->addJoin($join[0], $join[1], $join[2]);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function addJoin(string $join_type, string $join_table, string $conditions): Select
|
||||
{
|
||||
$join_type = strtoupper($join_type);
|
||||
$this->joins []= "{$join_type} {$join_table} {$conditions}";
|
||||
return $this;
|
||||
}
|
||||
public function getJoins(): string
|
||||
{
|
||||
return implode('', $this->joins);
|
||||
}
|
||||
protected array $conditions;
|
||||
public function where(array|string $conditions): Select
|
||||
{
|
||||
if (is_string($conditions)) {
|
||||
return $this->addWhere($conditions);
|
||||
}
|
||||
foreach ($conditions as $condition) {
|
||||
$this->addWhere($condition);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function addWhere($condition): Select
|
||||
{
|
||||
$this->conditions []= $condition;
|
||||
return $this;
|
||||
}
|
||||
public function getWheres(): string
|
||||
{
|
||||
return implode(' AND ', $this->conditions);
|
||||
}
|
||||
protected array $orders;
|
||||
public function order(array|string $orders): Select
|
||||
{
|
||||
if (is_string($orders)) {
|
||||
return $this->addOrder($orders);
|
||||
}
|
||||
foreach ($orders as $order) {
|
||||
if (is_array($order)) {
|
||||
$this->addOrder($order[0], $order[1]);
|
||||
continue;
|
||||
}
|
||||
$this->addOrder($order);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function addOrder(string $order, string $dir = 'desc'): Select
|
||||
{
|
||||
$dir = strtoupper($dir);
|
||||
$this->orders []= "{$order} {$dir}";
|
||||
return $this;
|
||||
}
|
||||
public function getOrders(): string
|
||||
{
|
||||
return implode(', ', $this->orders);
|
||||
}
|
||||
protected array $groups;
|
||||
public function group(array|string $groups): Select
|
||||
{
|
||||
if (is_string($groups)) {
|
||||
return $this->addGroup($groups);
|
||||
}
|
||||
foreach ($groups as $group) {
|
||||
$this->addGroup($group);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function addGroup(string $group): Select
|
||||
{
|
||||
$this->groups []= $group;
|
||||
return $this;
|
||||
}
|
||||
public function getGroups(): string
|
||||
{
|
||||
return implode(', ', $this->groups);
|
||||
}
|
||||
protected array $having;
|
||||
public function having(array|string $havings): Select
|
||||
{
|
||||
if (is_string($havings)) {
|
||||
return $this->addHaving($havings);
|
||||
}
|
||||
foreach ($havings as $having) {
|
||||
$this->addHaving($having);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function addHaving(string $having): Select
|
||||
{
|
||||
$this->having []= $having;
|
||||
return $this;
|
||||
}
|
||||
public function getHaving(): string
|
||||
{
|
||||
return implode(' AND ', $this->having);
|
||||
}
|
||||
protected int $limit;
|
||||
public function limit(int $limit): Select
|
||||
{
|
||||
$this->limit = $limit;
|
||||
return $this;
|
||||
}
|
||||
protected int $offset;
|
||||
public function offset(int $offset): Select
|
||||
{
|
||||
$this->offset = $offset;
|
||||
return $this;
|
||||
}
|
||||
public function getLimit(): string
|
||||
{
|
||||
$output = [$this->limit];
|
||||
if (isset($this->offset)) {
|
||||
$output []= 'OFFSET';
|
||||
$output []= $this->offset;
|
||||
}
|
||||
return implode(' ', $output);
|
||||
}
|
||||
|
||||
public function build(): string
|
||||
{
|
||||
$output = ['SELECT'];
|
||||
try {
|
||||
$output []= $this->getSelect();
|
||||
} catch (\Error $e) {
|
||||
$output []= '*';
|
||||
}
|
||||
$output []= 'FROM';
|
||||
$output []= $this->getFrom();
|
||||
try {
|
||||
$output [] = $this->getJoins();
|
||||
} catch (\Error $e) {
|
||||
\Safe\error_log($e);
|
||||
}
|
||||
try {
|
||||
$output []= "WHERE {$this->getWheres()}";
|
||||
} catch (\Error $e) {
|
||||
\Safe\error_log($e);
|
||||
}
|
||||
try {
|
||||
$output []= "GROUP BY {$this->getGroups()}";
|
||||
} catch (\Error $e) {
|
||||
\Safe\error_log($e);
|
||||
}
|
||||
try {
|
||||
$output []= "HAVING {$this->getHaving()}";
|
||||
} catch (\Error $e) {
|
||||
\Safe\error_log($e);
|
||||
}
|
||||
try {
|
||||
$output []= "ORDER BY {$this->getOrders()}";
|
||||
} catch (\Error $e) {
|
||||
\Safe\error_log($e);
|
||||
}
|
||||
try {
|
||||
$output []= "LIMIT {$this->getLimit()}";
|
||||
} catch (\Error $e) {
|
||||
\Safe\error_log($e);
|
||||
}
|
||||
return implode(' ', $output);
|
||||
}
|
||||
}
|
67
api/ProVM/Implement/Database/Query/MySQL/Update.php
Normal file
67
api/ProVM/Implement/Database/Query/MySQL/Update.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
namespace ProVM\Implement\Database\Query\MySQL;
|
||||
|
||||
use Common\Alias\Database\Query;
|
||||
|
||||
class Update extends Query
|
||||
{
|
||||
protected string $table;
|
||||
public function table(string $table): Update
|
||||
{
|
||||
$this->table = $table;
|
||||
return $this;
|
||||
}
|
||||
public function getTable(): string
|
||||
{
|
||||
return $this->table;
|
||||
}
|
||||
protected array $sets;
|
||||
public function set(array|string $set_strings): Update
|
||||
{
|
||||
if (is_string($set_strings)) {
|
||||
return $this->addSet($set_strings);
|
||||
}
|
||||
foreach ($set_strings as $set_string) {
|
||||
$this->addSet($set_string);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function addSet(string $set_string): Update
|
||||
{
|
||||
$this->sets []= $set_string;
|
||||
return $this;
|
||||
}
|
||||
public function getSets(): string
|
||||
{
|
||||
return implode(', ', $this->sets);
|
||||
}
|
||||
protected array $conditions;
|
||||
public function where(array|string $conditions): Update
|
||||
{
|
||||
if (is_string($conditions)) {
|
||||
return $this->addCondition($conditions);
|
||||
}
|
||||
foreach ($conditions as $condition) {
|
||||
$this->addCondition($condition);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function addCondition(string $condition): Update
|
||||
{
|
||||
$this->conditions []= $condition;
|
||||
return $this;
|
||||
}
|
||||
public function getWhere(): string
|
||||
{
|
||||
return implode(' AND ', $this->conditions);
|
||||
}
|
||||
|
||||
public function build(): string
|
||||
{
|
||||
$output = ['UPDATE'];
|
||||
$output []= $this->getTable();
|
||||
$output []= "SET {$this->getSets()}";
|
||||
$output []= "WHERE {$this->getWhere()}";
|
||||
return implode(' ', $output);
|
||||
}
|
||||
}
|
61
api/ProVM/Implement/Database/QueryBuilder.php
Normal file
61
api/ProVM/Implement/Database/QueryBuilder.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
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;
|
||||
|
||||
class QueryBuilder
|
||||
{
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$arr = [
|
||||
'select',
|
||||
'insert',
|
||||
'update',
|
||||
'delete'
|
||||
];
|
||||
foreach ($arr as $b) {
|
||||
$builder = implode("\\", [
|
||||
'Contabilidad',
|
||||
'Implement',
|
||||
'Database',
|
||||
'Query',
|
||||
'MySQL',
|
||||
ucwords($b)
|
||||
]);
|
||||
$this->addBuilder($container->get($builder));
|
||||
}
|
||||
}
|
||||
protected array $builders;
|
||||
public function addBuilder(Query $builder): QueryBuilder
|
||||
{
|
||||
$name = explode("\\", get_class($builder));
|
||||
$name = array_pop($name);
|
||||
$this->builders[strtolower($name)] = $builder;
|
||||
return $this;
|
||||
}
|
||||
public function start(string $name): Query
|
||||
{
|
||||
return $this->builders[strtolower($name)];
|
||||
}
|
||||
public function select(): Select
|
||||
{
|
||||
return $this->start('select');
|
||||
}
|
||||
public function insert(): Insert
|
||||
{
|
||||
return $this->start('insert');
|
||||
}
|
||||
public function update(): Update
|
||||
{
|
||||
return $this->start('update');
|
||||
}
|
||||
public function delete(): Delete
|
||||
{
|
||||
return $this->start('delete');
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
namespace Contabilidad\Implement;
|
||||
namespace ProVM\Implement;
|
||||
|
||||
use Common\Alias\File as BaseFile;
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
namespace Contabilidad\Implement;
|
||||
namespace ProVM\Implement;
|
||||
|
||||
use Common\Concept\File as FileInterface;
|
||||
use Common\Alias\Filesystem as BaseFilesystem;
|
14
api/Psr/Collection/CollectionInterface.php
Normal file
14
api/Psr/Collection/CollectionInterface.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
namespace Psr\Collection;
|
||||
|
||||
use Iterator, ArrayAccess, Countable;
|
||||
|
||||
interface CollectionInterface extends Iterator, ArrayAccess, Countable
|
||||
{
|
||||
public function set(mixed $name, $value): CollectionInterface;
|
||||
public function has(mixed $name): bool;
|
||||
public function get(mixed $name);
|
||||
public function remove(mixed $name): CollectionInterface;
|
||||
public static function fromArray(array $source): CollectionInterface;
|
||||
public static function fromObject(object $source): CollectionInterface;
|
||||
}
|
@ -1,25 +1,27 @@
|
||||
<?php
|
||||
namespace Common\Concept;
|
||||
namespace Psr\Database;
|
||||
|
||||
interface Database
|
||||
use PDO;
|
||||
|
||||
interface DatabaseInterface
|
||||
{
|
||||
public function setHost(string $host, ?int $port = null): Database;
|
||||
public function setHost(string $host, ?int $port = null): DatabaseInterface;
|
||||
public function getHost(): string;
|
||||
public function getPort(): int;
|
||||
public function setName(string $database_name): Database;
|
||||
public function setName(string $database_name): DatabaseInterface;
|
||||
public function getName(): string;
|
||||
public function setUser(string $username, string $password): Database;
|
||||
public function setUser(string $username, string $password): DatabaseInterface;
|
||||
public function getUser(): string;
|
||||
public function getPassword(): string;
|
||||
public function getDsn(): string;
|
||||
public function needsUser(): bool;
|
||||
public function connect(): Database;
|
||||
public function getConnection(): \PDO;
|
||||
public function connect(): DatabaseInterface;
|
||||
public function getConnection(): PDO;
|
||||
public function beginTransaction(): void;
|
||||
public function commit(): void;
|
||||
public function rollBack(): void;
|
||||
public function query(string $query): array;
|
||||
public function prepare(string $query): Database;
|
||||
public function prepare(string $query): DatabaseInterface;
|
||||
public function execute(array $data): array;
|
||||
public function insert(array $values): void;
|
||||
public function update(array $data): void;
|
@ -1,8 +0,0 @@
|
||||
<?php
|
||||
namespace Common\Alias;
|
||||
|
||||
use Common\Concept\Model as ModelInterface;
|
||||
|
||||
abstract class Model implements ModelInterface
|
||||
{
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
<?php
|
||||
namespace Common\Alias;
|
||||
|
||||
use Common\Concept\Database;
|
||||
use Common\Concept\Model;
|
||||
use Common\Concept\Repository as RepositoryInterface;
|
||||
|
||||
abstract class Repository implements RepositoryInterface
|
||||
{
|
||||
protected string $table;
|
||||
public function setTable(string $table): RepositoryInterface
|
||||
{
|
||||
$this->table = $table;
|
||||
return $this;
|
||||
}
|
||||
public function getTable(): string
|
||||
{
|
||||
return $this->table;
|
||||
}
|
||||
protected array $properties;
|
||||
public function addProperty(string $name): RepositoryInterface
|
||||
{
|
||||
$this->properties []= $name;
|
||||
return $this;
|
||||
}
|
||||
public function setProperties(array $properties): RepositoryInterface
|
||||
{
|
||||
foreach ($properties as $property) {
|
||||
$this->addProperty($property);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function getProperties(): array
|
||||
{
|
||||
return $this->properties;
|
||||
}
|
||||
protected Database $database;
|
||||
public function setDatabase(Database $database): RepositoryInterface
|
||||
{
|
||||
$this->database = $database;
|
||||
return $this;
|
||||
}
|
||||
public function getDatabase(): Database
|
||||
{
|
||||
return $this->database;
|
||||
}
|
||||
|
||||
public function fetchAll(): array
|
||||
{
|
||||
$query = "SELECT * FROM {$this->getTable()}";
|
||||
return array_map([$this, 'load'], $this->getDatabase()->query($query));
|
||||
}
|
||||
|
||||
public function save(Model $model): void
|
||||
{
|
||||
$columns = implode(', ', array_map(function($item) {return "'{$item}'";}, $this->getProperties()));
|
||||
$values = implode(', ', array_map(function($item) {return '?';}, $this->getProperties()));
|
||||
$query = "INSERT INTO {$this->getTable()} ({$columns}) VALUES ({$values})";
|
||||
$values = array_map(function($item) use ($model) {$method = str_replace(' ', '', ucwords(str_replace('_', '', $item)));return $model->{"get{$method}"}();}, $this->getProperties());
|
||||
$this->getDatabase()->prepare($query)->insert($values);
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
<?php
|
||||
namespace Common\Concept\Factory;
|
||||
|
||||
use Common\Concept\Model as ModelInterface;
|
||||
use Common\Concept\Repository;
|
||||
|
||||
interface Model
|
||||
{
|
||||
public function find(ModelInterface $model_name): Repository;
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
<?php
|
||||
namespace Common\Concept;
|
||||
|
||||
interface Model
|
||||
{
|
||||
}
|
24
api/common/Controller/Base.php
Normal file
24
api/common/Controller/Base.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
namespace Common\Controller;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use function Safe\{json_decode, file_get_contents};
|
||||
use ProVM\Alias\Controller\Json;
|
||||
|
||||
class Base
|
||||
{
|
||||
use Json;
|
||||
|
||||
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));
|
||||
return $this->withJson($response, $documentation);
|
||||
}
|
||||
}
|
125
api/common/Controller/Cuentas.php
Normal file
125
api/common/Controller/Cuentas.php
Normal file
@ -0,0 +1,125 @@
|
||||
<?php
|
||||
namespace Common\Controller;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use PDOException;
|
||||
use function Safe\{json_decode,error_log};
|
||||
use ProVM\Alias\Controller\Json;
|
||||
use Contabilidad\Repository\Cuenta;
|
||||
|
||||
class Cuentas
|
||||
{
|
||||
use Json;
|
||||
|
||||
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, Cuenta $repository): ResponseInterface
|
||||
{
|
||||
$cuentas = [];
|
||||
try {
|
||||
$cuentas = $repository->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);
|
||||
}
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Middleware;
|
||||
namespace Common\Middleware;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\RequestHandlerInterface as Handler;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ResponseFactoryInterface as Factory;
|
||||
use Contabilidad\Common\Service\Auth as Service;
|
||||
use Common\Service\Auth as Service;
|
||||
|
||||
class Auth {
|
||||
protected Factory $factory;
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Service;
|
||||
namespace Common\Service;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
"psr-4": {
|
||||
"Common\\": "common/",
|
||||
"Contabilidad\\": "src/",
|
||||
"ProVM\\": "ProVM/",
|
||||
"Psr\\": "Psr/"
|
||||
}
|
||||
},
|
||||
|
12
api/resources/documentation/base.json
Normal file
12
api/resources/documentation/base.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"title": "Contabilidad",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"paths": {
|
||||
"/transactions": {
|
||||
"description": "List transactions"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,4 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\Base;
|
||||
use Common\Controller\Base;
|
||||
|
||||
$app->get('/key/generate[/]', [Base::class, 'generate_key']);
|
||||
$app->get('/balance[/]', [Contabilidad\Common\Controller\TiposCategorias::class, 'balance']);
|
||||
$app->get('/info', [Base::class, 'info']);
|
||||
$app->get('/', Base::class);
|
||||
|
@ -1,13 +0,0 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\Categorias;
|
||||
|
||||
$app->group('/categorias', function($app) {
|
||||
$app->post('/add[/]', [Categorias::class, 'add']);
|
||||
$app->get('[/]', Categorias::class);
|
||||
});
|
||||
$app->group('/categoria/{categoria_id}', function($app) {
|
||||
$app->get('/cuentas', [Categorias::class, 'cuentas']);
|
||||
$app->put('/edit', [Categorias::class, 'edit']);
|
||||
$app->delete('/delete', [Categorias::class, 'delete']);
|
||||
$app->get('[/]', [Categorias::class, 'show']);
|
||||
});
|
@ -1,7 +0,0 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\Consolidados;
|
||||
|
||||
$app->group('/consolidar', function($app) {
|
||||
$app->get('/update/{mes}/{cuenta_id}', [Consolidados::class, 'update']);
|
||||
$app->get('[/]', [Consolidados::class, 'cli']);
|
||||
});
|
@ -1,20 +1,12 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\Cuentas;
|
||||
use Common\Controller\Cuentas;
|
||||
|
||||
$app->group('/cuentas', function($app) {
|
||||
$app->post('/add[/]', [Cuentas::class, 'add']);
|
||||
$app->get('[/]', Cuentas::class);
|
||||
$app->post('/add[/]', [Cuentas::class, 'add']);
|
||||
$app->post('/edit[/]', [Cuentas::class, 'edit']);
|
||||
$app->get('[/]', Cuentas::class);
|
||||
});
|
||||
$app->group('/cuenta/{cuenta_id}', function($app) {
|
||||
$app->get('/entradas', [Cuentas::class, 'entradas']);
|
||||
$app->group('/transacciones', function($app) {
|
||||
$app->get('/amount', [Cuentas::class, 'transaccionesAmount']);
|
||||
$app->get('/month/{month}', [Cuentas::class, 'transaccionesMonth']);
|
||||
$app->get('/acum/{date}', [Cuentas::class, 'transaccionesAcumulation']);
|
||||
$app->get('[/{limit:[0-9]+}[/{start:[0-9]+}]]', [Cuentas::class, 'transacciones']);
|
||||
});
|
||||
$app->get('/categoria', [Cuentas::class, 'categoria']);
|
||||
$app->put('/edit', [Cuentas::class, 'edit']);
|
||||
$app->delete('/delete', [Cuentas::class, 'delete']);
|
||||
$app->get('[/]', [Cuentas::class, 'show']);
|
||||
$app->post('/edit[/]', [Cuentas::class, 'editOne']);
|
||||
$app->get('[/]', [Cuentas::class, 'get']);
|
||||
});
|
||||
|
@ -1,5 +0,0 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\Import;
|
||||
|
||||
$app->post('/import', Import::class);
|
||||
$app->get('/import/uploads', [Import::class, 'uploads']);
|
@ -1,12 +0,0 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\Monedas;
|
||||
|
||||
$app->group('/monedas', function($app) {
|
||||
$app->post('/add[/]', [Monedas::class, 'add']);
|
||||
$app->get('[/]', Monedas::class);
|
||||
});
|
||||
$app->group('/moneda/{moneda_id}', function($app) {
|
||||
$app->put('/edit', [Monedas::class, 'edit']);
|
||||
$app->delete('/delete', [Monedas::class, 'delete']);
|
||||
$app->get('[/]', [Monedas::class, 'show']);
|
||||
});
|
@ -1,8 +0,0 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\Queues;
|
||||
|
||||
$app->group('/queues', function($app) {
|
||||
$app->get('/pending', [Queues::class, 'pending']);
|
||||
$app->post('/processed', [Queues::class, 'processed']);
|
||||
$app->get('[/]', Queues::class);
|
||||
});
|
@ -1,16 +0,0 @@
|
||||
<?php
|
||||
$folder = implode(DIRECTORY_SEPARATOR, [
|
||||
__DIR__,
|
||||
'tipos'
|
||||
]);
|
||||
if (file_exists($folder)) {
|
||||
$app->group('/tipos', function($app) use ($folder) {
|
||||
$files = new DirectoryIterator($folder);
|
||||
foreach ($files as $file) {
|
||||
if ($file->isDir() or $file->getExtension() != 'php') {
|
||||
continue;
|
||||
}
|
||||
include_once $file->getRealPath();
|
||||
}
|
||||
});
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\TiposCambios;
|
||||
|
||||
$app->group('/cambios', function($app) {
|
||||
$app->post('/obtener[/]', [TiposCambios::class, 'obtain']);
|
||||
$app->post('/add[/]', [TiposCambios::class, 'add']);
|
||||
$app->get('[/]', TiposCambios::class);
|
||||
});
|
||||
$app->group('/cambio/{tipo_id}', function($app) {
|
||||
$app->put('/edit[/]', [TiposCambios::class, 'edit']);
|
||||
$app->delete('/delete[/]', [TiposCambios::class, 'delete']);
|
||||
$app->get('[/]', [TiposCambios::class, 'show']);
|
||||
});
|
@ -1,13 +0,0 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\TiposCategorias;
|
||||
|
||||
$app->group('/categorias', function($app) {
|
||||
$app->post('/add[/]', [TiposCategorias::class, 'add']);
|
||||
$app->get('[/]', TiposCategorias::class);
|
||||
});
|
||||
$app->group('/categoria/{tipo_id}', function($app) {
|
||||
$app->get('/categorias', [TiposCategorias::class, 'categorias']);
|
||||
$app->put('/edit', [TiposCategorias::class, 'edit']);
|
||||
$app->delete('/delete', [TiposCategorias::class, 'delete']);
|
||||
$app->get('[/]', [TiposCategorias::class, 'show']);
|
||||
});
|
@ -1,12 +0,0 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\TiposCuentas;
|
||||
|
||||
$app->group('/cuentas', function($app) {
|
||||
$app->post('/add[/]', [TiposCuentas::class, 'add']);
|
||||
$app->get('[/]', TiposCuentas::class);
|
||||
});
|
||||
$app->group('/cuenta/{tipo_id}', function($app) {
|
||||
$app->put('/edit', [TiposCuentas::class, 'edit']);
|
||||
$app->delete('/delete', [TiposCuentas::class, 'delete']);
|
||||
$app->get('[/]', [TiposCuentas::class, 'show']);
|
||||
});
|
@ -1,12 +0,0 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\Transacciones;
|
||||
|
||||
$app->group('/transacciones', function($app) {
|
||||
$app->post('/add[/]', [Transacciones::class, 'add']);
|
||||
$app->get('[/]', Transacciones::class);
|
||||
});
|
||||
$app->group('/transaccion/{transaccion_id}', function($app) {
|
||||
$app->put('/edit', [Transacciones::class, 'edit']);
|
||||
$app->delete('/delete', [Transacciones::class, 'delete']);
|
||||
$app->get('[/]', [Transacciones::class, 'show']);
|
||||
});
|
@ -1,12 +0,0 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\Files;
|
||||
|
||||
$app->group('/uploads', function($app) {
|
||||
$app->post('/add[/]', [Files::class, 'upload']);
|
||||
$app->get('[/]', Files::class);
|
||||
});
|
||||
$app->group('/upload/{folder}/{filename}', function($app) {
|
||||
$app->put('[/]', [Files::class, 'edit']);
|
||||
$app->delete('[/]', [Files::class, 'delete']);
|
||||
$app->get('[/]', [Files::class, 'get']);
|
||||
});
|
@ -1,6 +0,0 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\Workers;
|
||||
|
||||
$app->group('/workers', function($app) {
|
||||
$app->post('/register', [Workers::class, 'register']);
|
||||
});
|
@ -1,2 +1,2 @@
|
||||
<?php
|
||||
$app->add($app->getContainer()->get(Contabilidad\Common\Middleware\Auth::class));
|
||||
$app->add($app->getContainer()->get(Common\Middleware\Auth::class));
|
||||
|
@ -2,28 +2,39 @@
|
||||
use Psr\Container\ContainerInterface as Container;
|
||||
|
||||
return [
|
||||
'folders' => function(Container $c) {
|
||||
$arr = [
|
||||
'base' => dirname(__DIR__, 2)
|
||||
];
|
||||
$arr['resources'] = implode(DIRECTORY_SEPARATOR, [
|
||||
$arr['base'],
|
||||
'resources'
|
||||
]);
|
||||
$arr['routes'] = implode(DIRECTORY_SEPARATOR, [
|
||||
$arr['resources'],
|
||||
'routes'
|
||||
]);
|
||||
$arr['public'] = implode(DIRECTORY_SEPARATOR, [
|
||||
$arr['base'],
|
||||
'public'
|
||||
]);
|
||||
return (object) $arr;
|
||||
},
|
||||
'urls' => function(Container $c) {
|
||||
$arr = [
|
||||
'python' => 'http://python:5000'
|
||||
];
|
||||
return (object) $arr;
|
||||
}
|
||||
'folders' => function(Container $c) {
|
||||
return \ProVM\Implement\Collection::fromArray([
|
||||
'base' => dirname(__DIR__, 2),
|
||||
'resources' => function(\Psr\Collection\CollectionInterface $collection) {
|
||||
return implode(DIRECTORY_SEPARATOR, [
|
||||
$collection['base'],
|
||||
'resources'
|
||||
]);
|
||||
},
|
||||
'documentation' => function(\Psr\Collection\CollectionInterface $collection) {
|
||||
return implode(DIRECTORY_SEPARATOR, [
|
||||
$collection['resources'],
|
||||
'documentation'
|
||||
]);
|
||||
},
|
||||
'routes' => function(\Psr\Collection\CollectionInterface $collection) {
|
||||
return implode(DIRECTORY_SEPARATOR, [
|
||||
$collection['resources'],
|
||||
'routes'
|
||||
]);
|
||||
},
|
||||
'public' => function(\Psr\Collection\CollectionInterface $collection) {
|
||||
return implode(DIRECTORY_SEPARATOR, [
|
||||
$collection['base'],
|
||||
'public'
|
||||
]);
|
||||
}
|
||||
]);
|
||||
},
|
||||
'urls' => function(Container $c) {
|
||||
$arr = [
|
||||
'python' => 'http://python:5000'
|
||||
];
|
||||
return (object) $arr;
|
||||
}
|
||||
];
|
||||
|
@ -14,15 +14,6 @@ return [
|
||||
'name' => $_ENV['MYSQL_DATABASE']
|
||||
]
|
||||
];
|
||||
function toObj($arr) {
|
||||
$obj = (object) $arr;
|
||||
foreach ($arr as $k => $v) {
|
||||
if (is_array($v)) {
|
||||
$obj->{$k} = toObj($v);
|
||||
}
|
||||
}
|
||||
return $obj;
|
||||
}
|
||||
return (object) ['databases' => toObj($arr), 'short_names' => true];
|
||||
return (object) ['databases' => \ProVM\Implement\Collection::fromArray($arr), 'short_names' => true];
|
||||
}
|
||||
];
|
||||
|
14
api/setup/setups/01_auth.php
Normal file
14
api/setup/setups/01_auth.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
return [
|
||||
\Common\Service\Auth::class => function(ContainerInterface $container) {
|
||||
return new \Common\Service\Auth($container->get('api_key'));
|
||||
},
|
||||
\Common\Middleware\Auth::class => function(ContainerInterface $container) {
|
||||
return new \Common\Middleware\Auth(
|
||||
$container->get(\Nyholm\Psr7\Factory\Psr17Factory::class),
|
||||
$container->get(\Common\Service\Auth::class)
|
||||
);
|
||||
}
|
||||
];
|
@ -2,12 +2,12 @@
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
return [
|
||||
\Common\Concept\Database::class => function(ContainerInterface $container) {
|
||||
$settings = $container->get('databases')->default;
|
||||
return new \Contabilidad\Implement\Database\MySQL(
|
||||
$settings->host->name,
|
||||
$settings->user->name,
|
||||
$settings->user->password,
|
||||
\Psr\Database\DatabaseInterface::class => function(ContainerInterface $container) {
|
||||
$settings = (object) $container->get('databases')->databases->default;
|
||||
return new \ProVM\Implement\Database\MySQL(
|
||||
$settings->host['name'],
|
||||
$settings->user['name'],
|
||||
$settings->user['password'],
|
||||
$settings->name
|
||||
);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
namespace Contabilidad\Model;
|
||||
|
||||
use Common\Alias\Model;
|
||||
use ProVM\Alias\Model;
|
||||
|
||||
class Cuenta extends Model
|
||||
{
|
||||
@ -15,4 +15,14 @@ class Cuenta extends Model
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
protected string $nombre;
|
||||
public function setNombre(string $nombre): Cuenta
|
||||
{
|
||||
$this->nombre = $nombre;
|
||||
return $this;
|
||||
}
|
||||
public function getNombre(): string
|
||||
{
|
||||
return $this->nombre;
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,18 @@
|
||||
<?php
|
||||
namespace Contabilidad\Repository;
|
||||
|
||||
use Common\Alias\Repository;
|
||||
use Common\Concept\Model;
|
||||
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()
|
||||
public function __construct(DatabaseInterface $database, QueryBuilder $builder)
|
||||
{
|
||||
parent::__construct($database, $builder);
|
||||
$this->setTable('cuentas');
|
||||
$this->setProperties(['id', 'nombre', 'tipo']);
|
||||
}
|
||||
@ -16,17 +20,33 @@ class Cuenta extends Repository
|
||||
public function load(array $data_row): Model
|
||||
{
|
||||
return (new BaseModel())
|
||||
->setId($data_row['id']);
|
||||
->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 fetchByKey($key): Model
|
||||
public function fetchById(int $id): Model
|
||||
{
|
||||
$query = "SELECT * FROM {$this->getTable()} WHERE `id` = ?";
|
||||
return $this->load($this->getDatabase()->prepare($query)->execute($key)[0]);
|
||||
$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 = "DELETE FROM {$this->getTable()} WHERE `id` = ?";
|
||||
$query = $this->getQueryBuilder()->delete()->from($this->getTable())->where('id = ?')->build();
|
||||
$this->getDatabase()->prepare($query)->delete([$model->getId()]);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ services:
|
||||
api:
|
||||
profiles:
|
||||
- api
|
||||
container_name: api
|
||||
<<: *restart
|
||||
image: php
|
||||
build:
|
||||
@ -19,9 +20,10 @@ services:
|
||||
- ./api/:/app/
|
||||
- ./api/php.ini:/usr/local/etc/php/conf.d/php.ini
|
||||
- ./logs/api/php/:/var/log/php/
|
||||
api-proxy:
|
||||
api_proxy:
|
||||
profiles:
|
||||
- api
|
||||
container_name: api_proxy
|
||||
<<: *restart
|
||||
image: nginx
|
||||
ports:
|
||||
@ -33,6 +35,7 @@ services:
|
||||
db:
|
||||
profiles:
|
||||
- api
|
||||
container_name: db
|
||||
<<: *restart
|
||||
image: mariadb
|
||||
env_file: .db.env
|
||||
@ -41,6 +44,7 @@ services:
|
||||
adminer:
|
||||
profiles:
|
||||
- api
|
||||
container_name: adminer
|
||||
<<: *restart
|
||||
image: adminer
|
||||
ports:
|
||||
@ -49,6 +53,7 @@ services:
|
||||
ui:
|
||||
profiles:
|
||||
- ui
|
||||
container_name: ui
|
||||
<<: *restart
|
||||
image: php-ui
|
||||
env_file:
|
||||
@ -60,9 +65,10 @@ services:
|
||||
- ./ui/:/app/
|
||||
- ./ui/php.ini:/usr/local/etc/php/conf.d/php.ini
|
||||
- ./logs/ui/php/:/var/log/php/
|
||||
ui-proxy:
|
||||
ui_proxy:
|
||||
profiles:
|
||||
- ui
|
||||
container_name: ui_proxy
|
||||
<<: *restart
|
||||
image: nginx
|
||||
ports:
|
||||
@ -75,6 +81,7 @@ services:
|
||||
python:
|
||||
profiles:
|
||||
- python
|
||||
container_name: python
|
||||
<<: *restart
|
||||
build:
|
||||
context: ./python
|
||||
@ -91,6 +98,7 @@ services:
|
||||
console:
|
||||
profiles:
|
||||
- console
|
||||
container_name: console
|
||||
<<: *restart
|
||||
build:
|
||||
context: ./console
|
||||
|
Reference in New Issue
Block a user