3. Capa de infraestructura
3.1. Comunicación con sistemas legacy (Quartup)
La API está diseñada para interactuar con sistemas legacy de Quartup a través de una capa de abstracción que permite el acceso a datos y funcionalidades existentes.
3.1.1. CoreQuartup
El componente central de esta integración es la clase CoreQuartup, un singleton que actúa como punto de entrada al sistema legacy:
namespace App\Core;
class CoreQuartup
{
private static $instancia = null;
private static $qu_basic_Instancia = null;
// Obtiene la instancia única de CoreQuartup
public static function obtenerInstancia() {
if (self::$instancia === null) {
self::$instancia = new self();
}
return self::$instancia;
}
// Obtiene la instancia de QU_Basic, componente fundamental de Quartup
public static function getQuBasic($sessionId = null) {
if (self::$qu_basic_Instancia === null) {
self::$qu_basic_Instancia = new Basic(false, false);
}
return self::$qu_basic_Instancia;
}
// Métodos para operaciones CRUD y transacciones
// ...
}
Este componente implementa funciones fundamentales:
- Manejo de sesiones de usuario
- Operaciones CRUD básicas con tablas de Quartup
- Gestión de transacciones
- Conversión de codificación entre UTF-8 y Latin1
3.1.2. Adaptadores para tablas legacy
La infraestructura incluye adaptadores específicos para cada tabla legacy, organizados en carpetas por módulos del sistema (PPos, PMaes, etc.). Estos adaptadores se implementan siguiendo una estructura consistente que facilita su integración con el resto del sistema.
3.2. Modelos de acceso a datos
3.2.1. BaseModel y sus implementaciones
El sistema implementa una jerarquía de modelos para abstraer el acceso a datos:
namespace App\Base\DB;
class BaseModel implements ModelInterface
{
protected $qu_table; // instancia de la QU_TablePoll
public $table = '';
// Implementación de métodos CRUD
public function selectById($id) { /* ... */ }
public function selectOne(array $init) { /* ... */ }
public function store(array $item) { /* ... */ }
public function update($id, array $data) { /* ... */ }
public function delete($id) { /* ... */ }
// Métodos para transacciones
public function startTransaction() { /* ... */ }
public function commitTransaction() { /* ... */ }
public function rollbackTransaction($err) { /* ... */ }
}
Las principales implementaciones de BaseModel son:
BaseModelPool
Utilizado para tablas simples:
class BaseModelPool extends BaseModel
{
public function __construct()
{
$this->qu_table = CoreQuartup::getInstancieOb($this->table);
parent::__construct();
}
}
BaseModelTree
Especializado para estructuras más complejas:
class BaseModelTree extends BaseModel
{
public function __construct()
{
$this->qu_table = CoreQuartup::getInstancieObTree($this->table, []);
parent::__construct();
}
}
Tienes razón, en el punto 3.2.2 mencioné que el trait CollectionTrait proporciona ciertas funcionalidades pero no especifiqué cuáles son. Voy a corregirlo:
3.2.2. Trait CollectionTrait
Para la gestión de colecciones de datos, el sistema utiliza el trait CollectionTrait que proporciona funcionalidad para:
- Paginación de resultados: Divide los conjuntos de datos en páginas para mejorar el rendimiento y la experiencia de usuario.
- Filtrado dinámico: Permite aplicar criterios de filtrado complejos mediante estructuras JSON.
- Ordenamiento personalizable: Soporta ordenamiento por múltiples campos y direcciones.
- Búsqueda simple: Implementa búsquedas en múltiples campos mediante el parámetro
simpleSearch. - Cálculo automático de metadatos: Genera información como total de registros, páginas y contadores filtrados.
namespace App\Base\DB;
trait CollectionTrait
{
public function collection($request)
{
// Obtener parámetros de paginación
$page = $request["page"] ?? 1;
$itemsPerPage = $request["itemsPerPage"] ?? 30;
$filters = $request["filters"] ?? null;
$permanentFilters = $request["permanentFilters"] ?? null;
// Procesar búsqueda simple si existe
if (isset($request["simpleSearch"])) {
$filters = $this->mergeSimpleSearchInFilters($filters, $request["simpleSearch"]);
}
// Calcular totales y aplicar filtros
$totalRecords = $permanentFilters
? (int) $this->getTotalFilteredRecords($permanentFilters)
: (int) $this->getTotalRecords();
// Combinar filtros permanentes y temporales
$combinedFilters = $this->combineFilters($permanentFilters, $filters);
$totalFilteredRecords = $filters
? (int) $this->getTotalFilteredRecords($combinedFilters)
: $totalRecords;
// Calcular paginación
$totalPages = (int) ceil($totalFilteredRecords / $itemsPerPage);
$page = max(min($page, $totalPages), 1);
$offset = ($page - 1) * $itemsPerPage;
// Procesar ordenamiento
$order = null;
if (isset($request["sortDesc"]) && isset($request["sortBy"])) {
$order = [
"by" => json_decode($request["sortBy"]),
"desc" => json_decode($request["sortDesc"]),
];
}
// Obtener registros paginados
$recordsForCurrentPage = $this->getRecordsPerPage($offset, $itemsPerPage, $combinedFilters, $order);
// Devolver resultado estructurado
return [
'collection' => $recordsForCurrentPage,
'totalRows' => (int) $totalRecords,
'totalFilteredRows' => (int) $totalFilteredRecords,
'pages' => (int) $totalPages,
'page' => (int) $page,
'itemsPerPage' => (int) $itemsPerPage,
];
}
}
El trait también incluye métodos auxiliares para:
- Combinar filtros permanentes y temporales
- Resolver cadenas de filtros JSON en condiciones SQL
- Aplicar búsquedas en múltiples campos
- Extraer y formatear condiciones de ordenamiento
Esta implementación de colecciones permite a los controladores y servicios trabajar con conjuntos de datos de manera consistente, independientemente del modelo subyacente, facilitando la creación de endpoints RESTful con capacidades avanzadas de filtrado y paginación.
3.3. Repositorios
La implementación del patrón Repositorio proporciona una abstracción adicional sobre los modelos:
namespace App\Base;
class Repository implements RepositoryInterface
{
protected $model;
public function __construct(ModelInterface $model)
{
$this->model = $model;
}
public function selectable($map) {
$mapa = array_combine($map, $map);
$mapa['PK'] = 'id';
$this->model->setMap($mapa);
}
// Métodos CRUD
public function collection($request) { /* ... */ }
public function selectById($id) { /* ... */ }
public function selectOne(array $init) { /* ... */ }
public function store(array $request) { /* ... */ }
public function update($id, array $request) { /* ... */ }
public function delete($id) { /* ... */ }
// Gestión de transacciones
public function transaction($callable) { /* ... */ }
}
3.3.1. Repositorios específicos
Para cada dominio, existen repositorios especializados que extienden la clase base. Estos repositorios pueden implementar métodos adicionales específicos del dominio:
namespace Infrastructures\Legacy\PPos\PosartticVArticulo;
class PosartticVArticuloRepository extends Repository
{
public function __construct(PosartticVArticuloModel $model)
{
parent::__construct($model);
}
public function getByCodOrAcceso($codOrAcceso)
{
$articulo = $this->selectOne(['cod_articulo' => $codOrAcceso]);
if ($articulo) {
return $articulo;
}
return $this->selectOne(['acceso' => $codOrAcceso]);
}
}
3.4. Implementación de QueryBuilder
El sistema incluye un QueryBuilder personalizado para construir consultas SQL de manera flexible:
namespace App\Base\QueryBuilder;
class QueryBuilder
{
protected $selectStatement = "*";
protected $tableName = "";
protected $joins = [];
public $where = "";
protected $limit = null;
protected $offset = null;
protected $orderByClause = "";
protected $groupBy = [];
// Métodos fluidos para construir consultas
public function select(string $select) { /* ... */ return $this; }
public function from(string $tableName) { /* ... */ return $this; }
public function where($field /* params */) { /* ... */ return $this; }
public function orWhere($field /* params */) { /* ... */ return $this; }
public function join($table /* params */) { /* ... */ return $this; }
public function take($limit) { /* ... */ return $this; }
public function skip($offset) { /* ... */ return $this; }
// Generar consulta SQL final
public function build() { /* ... */ }
}
3.4.1. Filtrado avanzado
El componente QueryBuilderFilters permite construir condiciones WHERE complejas a partir de estructuras JSON:
namespace App\Base\QueryBuilder;
class QueryBuilderFilters
{
protected $str = "";
protected $arr = [];
public function __construct($array, $map)
{
// Inicializar y procesar filtros
$this->arr = $array;
$this->run();
}
// Métodos para parsear condiciones
protected function parseCondition($array) { /* ... */ }
protected function isValidOperator($operator) { /* ... */ }
protected function convertArrayInToString($array) { /* ... */ }
// Obtener condición WHERE
public function getStr() {
return $this->str;
}
}
Este componente soporta operaciones avanzadas como:
- Operadores lógicos ($and, $or, $not)
- Comparaciones (=, !=, >, <, >=, <=)
- Búsqueda por patrones (like, not like)
- Listas (in, not in)
- Rangos (between)
- Valores nulos (is null, is not null)
La capa de infraestructura proporciona una abstracción robusta sobre el sistema legacy Quartup, exponiendo una interfaz moderna y orientada a objetos que facilita la construcción de la API. Esta arquitectura permite aislar los detalles de implementación del sistema legacy mientras proporciona un acceso consistente a los datos para las capas superiores de la aplicación.