Appearance
Patron Cross-Schema Queryable
Tipo: Patron Tecnico de Backend Alcance: Todos los servicios con operaciones multi-schema Estado: Implementado Fecha: 2027-01-27 Version: 1.0
Conceptual Foundation: Para entender los CONCEPTOS arquitectónicos de multi-schema querying, consulte Database Architecture: Multi-Schema. Este documento describe la implementación técnica del patrón.
Documento de Requisitos de Negocio: Sistema de Busqueda Multi-Schema para Operaciones Transaccionales
Este documento describe la implementacion tecnica del patron Cross-Schema Queryable, que estandariza las operaciones de consulta a traves de multiples schemas PostgreSQL. Para el contexto de negocio, escenarios problemáticos y reglas arquitecturales, consulte el documento general.
Indice
- Problema Tecnico
- Descripcion del Patron
- Componentes
- Estrategias de Consulta
- Metodos Helper
- Uso en Servicios
- Dependencias
- Testing
- Rendimiento
- Extension a Nuevos Modulos
- Referencia de API
Problema Tecnico
Boilerplate Repetitivo en Servicios
Antes de este patron, cada servicio que necesitaba consultar datos en multiples schemas PostgreSQL debia implementar manualmente toda la logica de:
- Determinar el schema actual del usuario desde el JWT
- Consultar la configuracion de niveles de la tabla
- Resolver los schemas objetivo segun la configuracion
- Iterar por cada schema cambiando el
search_path - Ejecutar la consulta en cada schema
- Acumular o retornar resultados
- Adjuntar metadata de schema a cada resultado
Esto representaba entre 15 y 20 lineas de codigo boilerplate por cada metodo de servicio que necesitaba buscar en multiples schemas. Con multiples metodos por servicio y multiples servicios por modulo, la duplicacion era significativa.
Problemas Derivados
- Duplicacion masiva: Cada servicio reimplementaba la misma logica con variaciones minimas
- Inconsistencia: Diferentes implementaciones tenian sutiles diferencias de comportamiento
- Dificultad de mantenimiento: Un cambio en la logica cross-schema requeria modificar todos los servicios
- Testing complejo: Cada servicio necesitaba tests individuales para la logica cross-schema
- Falta de optimizacion: No todos los servicios priorizaban el schema actual para rendimiento
Descripcion del Patron
Solucion: Interface + Trait
El patron Cross-Schema Queryable encapsula toda la logica de consulta multi-schema en dos componentes reutilizables:
- CrossSchemaQueryableInterface: Define el contrato que deben cumplir los servicios
- CrossSchemaQueryable (Trait): Provee la implementacion default
Los servicios implementan la interface y usan el trait, reduciendo el boilerplate de 15-20 lineas a 5-10 lineas por metodo (reduccion del 60-70%).
Principios de Diseno
- Single Source of Truth: Toda la logica cross-schema vive en un unico lugar
- Open/Closed: Los servicios extienden el comportamiento sin modificar el trait
- Interface Segregation: La interface define exactamente dos metodos publicos
- Composition over Inheritance: Se usa trait (composicion) en lugar de herencia de clases
- Strategy Pattern: Los dos metodos representan dos estrategias de busqueda
Componentes
1. CrossSchemaQueryableInterface
Ubicacion: Interface/MultiSchema/CrossSchemaQueryableInterface.php
Namespace: App\Interface\MultiSchema
Define el contrato con dos metodos publicos:
php
interface CrossSchemaQueryableInterface
{
public function queryAcrossSchemas(
callable $queryCallback,
string $tableName,
array $defaultLevels,
bool $multiSchema = true
): array;
public function findFirstAcrossSchemas(
callable $queryCallback,
string $tableName,
array $defaultLevels,
bool $multiSchema = true
);
}Parametros comunes:
| Parametro | Tipo | Descripcion |
|---|---|---|
$queryCallback | callable | Funcion que ejecuta la consulta especifica. Recibe string $schema como argumento. |
$tableName | string | Nombre de la tabla para determinar configuracion de niveles. |
$defaultLevels | array | Niveles de schema por defecto para esta tabla (ej: [2, 3]). |
$multiSchema | bool | Habilita/deshabilita la busqueda multi-schema. Default: true. |
2. CrossSchemaQueryable (Trait)
Ubicacion: Traits/CrossSchemaQueryable.php
Namespace: App\Traits
Provee la implementacion default de ambos metodos de la interface, mas tres metodos helper protegidos.
Dependencias del trait:
- Usa el trait
ConnectionUtils(parasetSchemaContext()) - Requiere propiedad
$this->connections(via traitConectable) con acceso aConnectionManager - Requiere propiedad
$this->multiSchemaServicede tipoMultiSchemaService
3. MultiSchemaService
Ubicacion: service/Config/MultiSchemaService.php
Namespace: App\service\Config
Servicio de soporte que resuelve la configuracion de schemas. Provee:
getCurrentSchema(): Obtiene el schema actual del JWT payloadisMultiSchemaActive($tableName, $defaultLevels): Determina si multi-schema esta activo para una tablagetTargetSchemas($tableName, $defaultLevels, $currentSchema): Resuelve la lista de schemas objetivo
Reglas de activacion (RA-001):
- Si la tabla tiene un solo nivel Y no es
LEVEL_CAJA→ multi-schema inactivo - Si la tabla tiene multiples niveles → multi-schema activo
- Si la tabla tiene un solo nivel
LEVEL_CAJA→ multi-schema activo (busca en todas las cajas)
Niveles soportados:
| Constante | Valor | Schema |
|---|---|---|
LEVEL_EMPRESA | 1 | public |
LEVEL_SUCURSAL | 2 | sucXXXX |
LEVEL_CAJA | 3 | sucXXXXcajaXXXX |
4. SchemaService
Ubicacion: service/Config/SchemaService.php
Namespace: App\service\Config
Servicio de bajo nivel que consulta information_schema de PostgreSQL:
getSchemasWithTable($table): Devuelve todos los schemas que contienen una tablagetSucursales(): Devuelve todos los schemas de tipo sucursal (suc\d{4})getCajas($sucursal): Devuelve todos los schemas de caja para una sucursal
5. ConnectionUtils (Trait)
Ubicacion: connection/ConnectionUtils.php
Namespace: App\connection
Utilidades estaticas para manipulacion de schemas PostgreSQL:
extractSucursalSchema($schema): Extrae la porcion de sucursal de un schema de cajabuildSearchPath($schema): Construye el search_path jerarquicosetSchemaContext($conn, $schema): EjecutaSET search_pathen una conexion PDOformatSchemaName($schema): Convierte nombre tecnico a formato legible
Estrategias de Consulta
Estrategia 1: Batch/Accumulate (queryAcrossSchemas)
Proposito: Acumular resultados de todos los schemas en un unico array.
Caso de uso tipico: Metodos getAll(), listados, reportes consolidados.
Flujo de ejecucion:
1. Obtener schema actual del JWT
2. Resolver schemas objetivo (resolveTargetSchemas)
3. Priorizar schema actual (prioritizeCurrentSchema)
4. Para cada schema:
a. Cambiar search_path al schema
b. Ejecutar callback
c. Adjuntar _schema a cada resultado
d. Agregar resultados al array acumulado
5. Retornar array con todos los resultadosImplementacion:
php
public function queryAcrossSchemas(
callable $queryCallback,
string $tableName,
array $defaultLevels,
bool $multiSchema = true
): array {
$currentSchema = $this->multiSchemaService->getCurrentSchema();
$schemas = $this->resolveTargetSchemas($tableName, $defaultLevels, $currentSchema, $multiSchema);
$schemas = $this->prioritizeCurrentSchema($schemas, $currentSchema);
$allResults = [];
foreach ($schemas as $schema) {
self::setSchemaContext($this->connections->get('principal'), $schema);
$results = $queryCallback($schema);
if (is_array($results)) {
foreach ($results as $result) {
$this->attachSchemaMetadata($result, $schema);
$allResults[] = $result;
}
}
}
return $allResults;
}Retorno: array - Array de objetos/DTOs con propiedad _schema adjuntada.
Estrategia 2: Early Exit (findFirstAcrossSchemas)
Proposito: Retornar el primer resultado no nulo encontrado, deteniendo la iteracion.
Caso de uso tipico: Metodos getById(), findByNumero(), busquedas de registro unico.
Flujo de ejecucion:
1. Obtener schema actual del JWT
2. Resolver schemas objetivo (resolveTargetSchemas)
3. Priorizar schema actual (prioritizeCurrentSchema)
4. Para cada schema:
a. Cambiar search_path al schema
b. Ejecutar callback
c. Si resultado != null:
- Adjuntar _schema al resultado
- RETORNAR resultado (early exit)
5. Si ninguno encontro resultado → retornar nullImplementacion:
php
public function findFirstAcrossSchemas(
callable $queryCallback,
string $tableName,
array $defaultLevels,
bool $multiSchema = true
) {
$currentSchema = $this->multiSchemaService->getCurrentSchema();
$schemas = $this->resolveTargetSchemas($tableName, $defaultLevels, $currentSchema, $multiSchema);
$schemas = $this->prioritizeCurrentSchema($schemas, $currentSchema);
foreach ($schemas as $schema) {
self::setSchemaContext($this->connections->get('principal'), $schema);
$result = $queryCallback($schema);
if ($result !== null) {
$this->attachSchemaMetadata($result, $schema);
return $result;
}
}
return null;
}Retorno: mixed|null - Primer objeto/DTO encontrado con _schema, o null.
Optimizacion de rendimiento: Al priorizar el schema actual y usar early exit, en el caso mas comun (registro en schema actual) solo se ejecuta una sola consulta.
Metodos Helper
resolveTargetSchemas()
Visibilidad: protected
Proposito: Determinar la lista de schemas donde se debe buscar.
Logica:
Si multiSchema=true Y isMultiSchemaActive=true:
→ Retornar schemas de MultiSchemaService::getTargetSchemas()
Si no:
→ Retornar [$currentSchema] (solo schema actual)Parametros:
| Parametro | Tipo | Descripcion |
|---|---|---|
$tableName | string | Tabla para consultar configuracion |
$defaultLevels | array | Niveles por defecto |
$currentSchema | string | Schema actual del usuario |
$multiSchema | bool | Flag habilitacion |
Retorno: array de nombres de schemas.
prioritizeCurrentSchema()
Visibilidad: protected
Proposito: Mover el schema actual al inicio del array para optimizar rendimiento.
Logica: Si $currentSchema esta en el array, se mueve al indice 0.
Justificacion: En la mayoria de los casos, el registro buscado esta en el schema actual del usuario. Priorizar este schema reduce la cantidad de consultas necesarias, especialmente con la estrategia early-exit.
Ejemplo:
Input: ['suc0001caja001', 'suc0001', 'suc0001caja002']
Current: 'suc0001'
Output: ['suc0001', 'suc0001caja001', 'suc0001caja002']attachSchemaMetadata()
Visibilidad: protected
Proposito: Adjuntar el nombre del schema de origen a cada resultado.
Logica: Si el objeto resultado tiene una propiedad _schema, se asigna el nombre del schema. Si no tiene la propiedad, no hace nada (safe operation).
Requisito para DTOs: Los DTOs que seran usados con este patron deben declarar:
php
public ?string $_schema = null;Uso en Servicios
Patron de Implementacion Completo
Para que un servicio use el patron Cross-Schema Queryable, debe:
- Implementar
CrossSchemaQueryableInterface - Usar los traits
Conectable,CrossSchemaQueryable - Inyectar
ConnectionManageren el constructor - Inicializar
$this->multiSchemaServiceen el constructor
php
<?php
namespace App\service\Tesoreria;
use App\Interface\MultiSchema\CrossSchemaQueryableInterface;
use App\Traits\Conectable;
use App\Traits\CrossSchemaQueryable;
use App\connection\ConnectionManager;
use App\service\Config\MultiSchemaService;
class MovimientoCajaService implements CrossSchemaQueryableInterface
{
use Conectable;
use CrossSchemaQueryable;
private MovimientoCaja $model;
private const LEVEL_SUCURSAL = 2;
private const LEVEL_CAJA = 3;
public function __construct(ConnectionManager $manager)
{
$this->setConnectionManager($manager);
$this->multiSchemaService = new MultiSchemaService($manager->get('principal'));
$this->model = new MovimientoCaja($manager->get('principal'));
}
/**
* Obtener todos los movimientos de caja.
* Patron Batch/Accumulate: acumula resultados de todos los schemas.
*/
public function getAll(bool $multiSchema = true): array
{
return $this->queryAcrossSchemas(
queryCallback: fn(string $schema) => $this->model->getAll(),
tableName: 'movimi',
defaultLevels: [self::LEVEL_SUCURSAL, self::LEVEL_CAJA],
multiSchema: $multiSchema
);
}
/**
* Buscar movimiento por ID.
* Patron Early Exit: retorna el primer match.
*/
public function findById(string $id, bool $multiSchema = true): ?MovimientoCajaDTO
{
return $this->findFirstAcrossSchemas(
queryCallback: fn(string $schema) => $this->model->getById($id),
tableName: 'movimi',
defaultLevels: [self::LEVEL_SUCURSAL, self::LEVEL_CAJA],
multiSchema: $multiSchema
);
}
/**
* Buscar movimientos por numero de comprobante.
* Patron Batch/Accumulate: puede haber movimientos en multiples schemas.
*/
public function findByComprobante(
string $nroComprobante,
bool $multiSchema = true
): array {
return $this->queryAcrossSchemas(
queryCallback: fn(string $schema) => $this->model->getByComprobante($nroComprobante),
tableName: 'movimi',
defaultLevels: [self::LEVEL_SUCURSAL, self::LEVEL_CAJA],
multiSchema: $multiSchema
);
}
}Parametro $multiSchema
Todos los metodos del servicio deben exponer un parametro $multiSchema con valor default true:
php
public function getAll(bool $multiSchema = true): arrayEsto permite que:
- Controllers de listado: Usen
$multiSchema = true(busqueda consolidada) - Controllers de operacion puntual: Puedan pasar
$multiSchema = falsesi ya conocen el schema - Tests unitarios: Puedan desactivar multi-schema para simplificar mocks
Propiedad _schema en DTOs
Los DTOs usados en operaciones cross-schema deben incluir:
php
class MovimientoCajaDTO extends FullDTO
{
public function __construct(
public int $id,
public string $fecha,
public float $importe,
// ... otros campos ...
public ?string $_schema = null // Metadata de schema
) {}
}La propiedad _schema permite al frontend y otros servicios:
- Saber de que schema proviene cada registro
- Cambiar el contexto al schema correcto para operaciones relacionadas (RA-003)
- Mostrar informacion de origen al usuario
Dependencias
Diagrama de Dependencias
CrossSchemaQueryableInterface
│
▼
CrossSchemaQueryable (Trait)
│ │ │
▼ ▼ ▼
Conectable ConnectionUtils MultiSchemaService
│ │
▼ ▼
ConnectionManager SchemaService
│ │
▼ ▼
PDO information_schemaFlujo de Resolucion de Schemas
1. CrossSchemaQueryable.queryAcrossSchemas()
│
├─► MultiSchemaService.getCurrentSchema()
│ └─► Lee $GLOBALS['payload']['schema'] (JWT)
│
├─► CrossSchemaQueryable.resolveTargetSchemas()
│ │
│ ├─► MultiSchemaService.isMultiSchemaActive()
│ │ └─► MultiSchemaService.getEffectiveLevels()
│ │ └─► MultiSchemaService.getTableLevelConfig()
│ │ └─► SELECT FROM sistema WHERE bd = :database
│ │
│ └─► MultiSchemaService.getTargetSchemas()
│ └─► MultiSchemaService.buildSchemaList()
│ ├─► SchemaService.getSucursales()
│ ├─► SchemaService.getCajas()
│ └─► SchemaService.getSchemasWithTable()
│
├─► CrossSchemaQueryable.prioritizeCurrentSchema()
│
└─► Para cada schema:
├─► ConnectionUtils.setSchemaContext() → SET search_path
├─► $queryCallback($schema)
└─► CrossSchemaQueryable.attachSchemaMetadata()Testing
Estrategia de Testing
El patron esta disenado para ser testeable en aislamiento:
- Trait tests: Usan clase anonima para probar el trait directamente
- MultiSchemaService tests: Mockean PDO y SchemaService
- Service tests: Mockean MultiSchemaService y Models
Tests del Trait (CrossSchemaQueryableTest)
Ubicacion: Tests/Unit/Traits/CrossSchemaQueryableTest.php
Setup: Usa clase anonima que combina Conectable + CrossSchemaQueryable:
php
$this->testService = new class {
use Conectable;
use CrossSchemaQueryable;
// Expose protected methods for testing
public function publicResolveTargetSchemas(...) { ... }
public function publicAttachSchemaMetadata(...) { ... }
public function publicPrioritizeCurrentSchema(...) { ... }
};Casos de prueba cubiertos:
| Categoria | Test | Descripcion |
|---|---|---|
| queryAcrossSchemas | testQueryAcrossSchemas_AccumulatesResultsFromMultipleSchemas | Verifica acumulacion de resultados de 3 schemas |
testQueryAcrossSchemas_MultiSchemaFalse_UsesOnlyCurrentSchema | Verifica que multiSchema=false usa solo schema actual | |
testQueryAcrossSchemas_HandlesEmptyResultsFromSomeSchemas | Maneja schemas que retornan arrays vacios | |
| findFirstAcrossSchemas | testFindFirstAcrossSchemas_ReturnsFirstMatch | Retorna primer resultado no-null y detiene iteracion |
testFindFirstAcrossSchemas_ReturnsNullWhenNoMatchFound | Retorna null cuando ningun schema tiene resultados | |
testFindFirstAcrossSchemas_MultiSchemaFalse_UsesOnlyCurrentSchema | Usa solo schema actual con flag deshabilitado | |
| resolveTargetSchemas | testResolveTargetSchemas_MultiSchemaFalse_ReturnsCurrentSchema | Flag false retorna solo schema actual |
testResolveTargetSchemas_MultiSchemaTrue_ReturnsMultipleSchemas | Flag true retorna multiples schemas | |
testResolveTargetSchemas_IsMultiSchemaActiveFalse_ReturnsCurrentSchema | Tabla de un solo nivel retorna schema actual | |
| attachSchemaMetadata | testAttachSchemaMetadata_SetsSchemaProperty | Asigna _schema cuando la propiedad existe |
testAttachSchemaMetadata_DoesNothingIfPropertyDoesNotExist | No agrega _schema si el objeto no tiene la propiedad | |
| prioritizeCurrentSchema | testPrioritizeCurrentSchema_MovesCurrentSchemaToFront | Mueve schema actual al inicio |
testPrioritizeCurrentSchema_DoesNothingIfCurrentSchemaNotInList | No modifica si schema actual no esta en la lista | |
testPrioritizeCurrentSchema_HandlesCurrentSchemaAlreadyFirst | No modifica si ya esta primero |
Tests del MultiSchemaService (MultiSchemaServiceTest)
Ubicacion: Tests/Unit/Config/MultiSchemaServiceTest.php
Casos de prueba cubiertos:
| Test | Descripcion |
|---|---|
testGetTargetSchemas_SingleLevel_ReturnsCurrentSchemaOnly | Tabla con un nivel retorna solo schema actual (RA-001) |
testGetTargetSchemas_MultipleLevels_ReturnsAllSucursalSchemas | Multiples niveles retorna todos los schemas de la sucursal |
testGetTargetSchemas_RespectsSucursalBoundary | Nunca retorna schemas de otras sucursales (RA-002) |
testIsMultiSchemaActive_SingleLevel_ReturnsFalse | Un solo nivel (no-caja) retorna false |
testIsMultiSchemaActive_MultipleLevels_ReturnsTrue | Multiples niveles retorna true |
testGetCurrentSchema_ReturnsSchemaFromGlobals | Lee schema del JWT payload |
testGetCurrentSchema_ThrowsExceptionWhenNotSet | Lanza RuntimeException sin schema |
testGetTargetSchemas_UsesCustomConfiguration | Usa configuracion personalizada cuando existe |
testGetTargetSchemas_LevelEmpresa_ReturnsPublic | Nivel empresa incluye schema public |
testGetTargetSchemas_RemovesDuplicates | Elimina schemas duplicados |
Ejecucion de Tests
bash
# Tests del trait
vendor/bin/phpunit Tests/Unit/Traits/CrossSchemaQueryableTest.php --testdox
# Tests del MultiSchemaService
vendor/bin/phpunit Tests/Unit/Config/MultiSchemaServiceTest.php --testdox
# Todos los tests relacionados
vendor/bin/phpunit Tests/Unit/Traits/ Tests/Unit/Config/ --testdoxRendimiento
Optimizaciones Implementadas
Priorizacion de schema actual:
prioritizeCurrentSchema()mueve el schema actual al inicio del array. Esto significa que para la estrategia early-exit, en el caso mas comun (registro en schema actual) solo se ejecuta una consulta.Flag
$multiSchema: Permite desactivar la busqueda multi-schema cuando no es necesaria, evitando completamente la resolucion de schemas.Resolucion condicional:
resolveTargetSchemas()solo consultaMultiSchemaServicecuandomultiSchema=trueY la tabla esta configurada para multi-schema.
Complejidad por Operacion
| Escenario | Consultas a BD | Complejidad |
|---|---|---|
multiSchema=false | 1 | O(1) |
| Early exit, registro en schema actual | 1 | O(1) |
| Early exit, registro en otro schema | 2-N | O(N) peor caso |
| Batch, N schemas | N | O(N) siempre |
Donde N = cantidad de schemas configurados (tipicamente 2-5 para una sucursal).
Overhead del Patron
- Resolucion de schemas: 1 consulta a tabla
sistema+ 1-2 consultas ainformation_schema - Cambio de search_path: 1
SET search_pathpor schema - Overhead total: Minimo comparado con las consultas de negocio
Extension a Nuevos Modulos
Checklist para Agregar un Nuevo Servicio
Para agregar soporte cross-schema a un servicio existente:
1. Modificar el servicio:
php
// ANTES
class MiServicio
{
use Conectable;
public function __construct(ConnectionManager $manager)
{
$this->setConnectionManager($manager);
}
public function getAll(): array
{
return $this->model->getAll();
}
}
// DESPUES
class MiServicio implements CrossSchemaQueryableInterface
{
use Conectable;
use CrossSchemaQueryable;
private const LEVEL_SUCURSAL = 2;
private const LEVEL_CAJA = 3;
public function __construct(ConnectionManager $manager)
{
$this->setConnectionManager($manager);
$this->multiSchemaService = new MultiSchemaService($manager->get('principal'));
}
public function getAll(bool $multiSchema = true): array
{
return $this->queryAcrossSchemas(
queryCallback: fn(string $schema) => $this->model->getAll(),
tableName: 'mi_tabla',
defaultLevels: [self::LEVEL_SUCURSAL, self::LEVEL_CAJA],
multiSchema: $multiSchema
);
}
}2. Agregar _schema al DTO:
php
class MiDTO extends FullDTO
{
public function __construct(
// ... campos existentes ...
public ?string $_schema = null
) {}
}3. Agregar tests:
- Mockear
MultiSchemaServiceen los tests del servicio - Verificar que
multiSchema=trueconsulta multiples schemas - Verificar que
multiSchema=falseconsulta solo schema actual
4. No se requieren cambios en:
- La interface
CrossSchemaQueryableInterface(no modificar) - El trait
CrossSchemaQueryable(no modificar) - El
MultiSchemaService(no modificar) - La infraestructura base (RA-005)
Modulos Candidatos
| Modulo | Tablas | Niveles Tipicos | Estado |
|---|---|---|---|
| Tesoreria | movimi, caja | [2, 3] | ✅ Implementado |
| CtaCte | recfac, rectra, recche | [1, 2, 3] | ✅ Implementado |
| Tesoreria | iteban | [1, 2] | Pendiente |
| Ventas | Tablas transaccionales | Por definir | Pendiente |
| Compras | Tablas transaccionales | Por definir | Pendiente |
| Stock | Tablas transaccionales | Por definir | Pendiente |
Referencia de API
CrossSchemaQueryableInterface
| Metodo | Parametros | Retorno | Descripcion |
|---|---|---|---|
queryAcrossSchemas | callable, string, array, bool | array | Batch: acumula resultados de todos los schemas |
findFirstAcrossSchemas | callable, string, array, bool | mixed|null | Early exit: retorna primer match |
CrossSchemaQueryable (Trait) - Metodos Protegidos
| Metodo | Parametros | Retorno | Descripcion |
|---|---|---|---|
resolveTargetSchemas | string, array, string, bool | array | Resuelve lista de schemas objetivo |
prioritizeCurrentSchema | array, string | array | Mueve schema actual al inicio |
attachSchemaMetadata | object, string | void | Adjunta _schema al resultado |
MultiSchemaService
| Metodo | Parametros | Retorno | Descripcion |
|---|---|---|---|
getCurrentSchema | - | string | Lee schema actual del JWT |
isMultiSchemaActive | string, array | bool | Verifica si multi-schema esta activo |
getTargetSchemas | string, array, string | array | Resuelve schemas objetivo |
SchemaService
| Metodo | Parametros | Retorno | Descripcion |
|---|---|---|---|
getSchemasWithTable | string | array | Schemas que contienen una tabla |
getSucursales | - | array | Schemas de tipo sucursal |
getCajas | string | array | Schemas de caja para una sucursal |
ConnectionUtils (Trait) - Metodos Estaticos
| Metodo | Parametros | Retorno | Descripcion |
|---|---|---|---|
extractSucursalSchema | string | string | Extrae sucursal de schema de caja |
buildSearchPath | string | string | Construye search_path jerarquico |
setSchemaContext | PDO, string | void | Ejecuta SET search_path |
formatSchemaName | string | string | Formato legible para usuario |
Reglas Arquitecturales Implementadas
Este patron implementa directamente las siguientes reglas del documento arquitectural:
- RA-001: Activacion basada en configuracion de niveles (via
resolveTargetSchemas+MultiSchemaService.isMultiSchemaActive) - RA-002: Alcance limitado por sucursal (via
MultiSchemaService.getTargetSchemasque filtra por sucursal) - RA-003: Consistencia de schema en recursos relacionados (via propiedad
_schemaen DTOs) - RA-005: Extensibilidad por modulo (nuevos servicios solo implementan interface + trait)
Historial de Cambios
| Fecha | Version | Descripcion |
|---|---|---|
| 2027-01-27 | 1.1 | Agregado ReciboRelationsService como ejemplo de implementación exitosa. Actualizada tabla de módulos candidatos. |
| 2027-01-27 | 1.0 | Creacion del documento tecnico. Documenta interface, trait, servicios de soporte, estrategias de consulta, testing y patron de extension. |