Skip to content

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

  1. Problema Tecnico
  2. Descripcion del Patron
  3. Componentes
  4. Estrategias de Consulta
  5. Metodos Helper
  6. Uso en Servicios
  7. Dependencias
  8. Testing
  9. Rendimiento
  10. Extension a Nuevos Modulos
  11. 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:

  1. Determinar el schema actual del usuario desde el JWT
  2. Consultar la configuracion de niveles de la tabla
  3. Resolver los schemas objetivo segun la configuracion
  4. Iterar por cada schema cambiando el search_path
  5. Ejecutar la consulta en cada schema
  6. Acumular o retornar resultados
  7. 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:

  1. CrossSchemaQueryableInterface: Define el contrato que deben cumplir los servicios
  2. 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:

ParametroTipoDescripcion
$queryCallbackcallableFuncion que ejecuta la consulta especifica. Recibe string $schema como argumento.
$tableNamestringNombre de la tabla para determinar configuracion de niveles.
$defaultLevelsarrayNiveles de schema por defecto para esta tabla (ej: [2, 3]).
$multiSchemaboolHabilita/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 (para setSchemaContext())
  • Requiere propiedad $this->connections (via trait Conectable) con acceso a ConnectionManager
  • Requiere propiedad $this->multiSchemaService de tipo MultiSchemaService

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 payload
  • isMultiSchemaActive($tableName, $defaultLevels): Determina si multi-schema esta activo para una tabla
  • getTargetSchemas($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:

ConstanteValorSchema
LEVEL_EMPRESA1public
LEVEL_SUCURSAL2sucXXXX
LEVEL_CAJA3sucXXXXcajaXXXX

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 tabla
  • getSucursales(): 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 caja
  • buildSearchPath($schema): Construye el search_path jerarquico
  • setSchemaContext($conn, $schema): Ejecuta SET search_path en una conexion PDO
  • formatSchemaName($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 resultados

Implementacion:

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 null

Implementacion:

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:

ParametroTipoDescripcion
$tableNamestringTabla para consultar configuracion
$defaultLevelsarrayNiveles por defecto
$currentSchemastringSchema actual del usuario
$multiSchemaboolFlag 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:

  1. Implementar CrossSchemaQueryableInterface
  2. Usar los traits Conectable, CrossSchemaQueryable
  3. Inyectar ConnectionManager en el constructor
  4. Inicializar $this->multiSchemaService en 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): array

Esto permite que:

  • Controllers de listado: Usen $multiSchema = true (busqueda consolidada)
  • Controllers de operacion puntual: Puedan pasar $multiSchema = false si 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_schema

Flujo 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:

CategoriaTestDescripcion
queryAcrossSchemastestQueryAcrossSchemas_AccumulatesResultsFromMultipleSchemasVerifica acumulacion de resultados de 3 schemas
testQueryAcrossSchemas_MultiSchemaFalse_UsesOnlyCurrentSchemaVerifica que multiSchema=false usa solo schema actual
testQueryAcrossSchemas_HandlesEmptyResultsFromSomeSchemasManeja schemas que retornan arrays vacios
findFirstAcrossSchemastestFindFirstAcrossSchemas_ReturnsFirstMatchRetorna primer resultado no-null y detiene iteracion
testFindFirstAcrossSchemas_ReturnsNullWhenNoMatchFoundRetorna null cuando ningun schema tiene resultados
testFindFirstAcrossSchemas_MultiSchemaFalse_UsesOnlyCurrentSchemaUsa solo schema actual con flag deshabilitado
resolveTargetSchemastestResolveTargetSchemas_MultiSchemaFalse_ReturnsCurrentSchemaFlag false retorna solo schema actual
testResolveTargetSchemas_MultiSchemaTrue_ReturnsMultipleSchemasFlag true retorna multiples schemas
testResolveTargetSchemas_IsMultiSchemaActiveFalse_ReturnsCurrentSchemaTabla de un solo nivel retorna schema actual
attachSchemaMetadatatestAttachSchemaMetadata_SetsSchemaPropertyAsigna _schema cuando la propiedad existe
testAttachSchemaMetadata_DoesNothingIfPropertyDoesNotExistNo agrega _schema si el objeto no tiene la propiedad
prioritizeCurrentSchematestPrioritizeCurrentSchema_MovesCurrentSchemaToFrontMueve schema actual al inicio
testPrioritizeCurrentSchema_DoesNothingIfCurrentSchemaNotInListNo modifica si schema actual no esta en la lista
testPrioritizeCurrentSchema_HandlesCurrentSchemaAlreadyFirstNo modifica si ya esta primero

Tests del MultiSchemaService (MultiSchemaServiceTest)

Ubicacion: Tests/Unit/Config/MultiSchemaServiceTest.php

Casos de prueba cubiertos:

TestDescripcion
testGetTargetSchemas_SingleLevel_ReturnsCurrentSchemaOnlyTabla con un nivel retorna solo schema actual (RA-001)
testGetTargetSchemas_MultipleLevels_ReturnsAllSucursalSchemasMultiples niveles retorna todos los schemas de la sucursal
testGetTargetSchemas_RespectsSucursalBoundaryNunca retorna schemas de otras sucursales (RA-002)
testIsMultiSchemaActive_SingleLevel_ReturnsFalseUn solo nivel (no-caja) retorna false
testIsMultiSchemaActive_MultipleLevels_ReturnsTrueMultiples niveles retorna true
testGetCurrentSchema_ReturnsSchemaFromGlobalsLee schema del JWT payload
testGetCurrentSchema_ThrowsExceptionWhenNotSetLanza RuntimeException sin schema
testGetTargetSchemas_UsesCustomConfigurationUsa configuracion personalizada cuando existe
testGetTargetSchemas_LevelEmpresa_ReturnsPublicNivel empresa incluye schema public
testGetTargetSchemas_RemovesDuplicatesElimina 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/ --testdox

Rendimiento

Optimizaciones Implementadas

  1. 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.

  2. Flag $multiSchema: Permite desactivar la busqueda multi-schema cuando no es necesaria, evitando completamente la resolucion de schemas.

  3. Resolucion condicional: resolveTargetSchemas() solo consulta MultiSchemaService cuando multiSchema=true Y la tabla esta configurada para multi-schema.

Complejidad por Operacion

EscenarioConsultas a BDComplejidad
multiSchema=false1O(1)
Early exit, registro en schema actual1O(1)
Early exit, registro en otro schema2-NO(N) peor caso
Batch, N schemasNO(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 a information_schema
  • Cambio de search_path: 1 SET search_path por 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 MultiSchemaService en los tests del servicio
  • Verificar que multiSchema=true consulta multiples schemas
  • Verificar que multiSchema=false consulta 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

ModuloTablasNiveles TipicosEstado
Tesoreriamovimi, caja[2, 3]✅ Implementado
CtaCterecfac, rectra, recche[1, 2, 3]✅ Implementado
Tesoreriaiteban[1, 2]Pendiente
VentasTablas transaccionalesPor definirPendiente
ComprasTablas transaccionalesPor definirPendiente
StockTablas transaccionalesPor definirPendiente

Referencia de API

CrossSchemaQueryableInterface

MetodoParametrosRetornoDescripcion
queryAcrossSchemascallable, string, array, boolarrayBatch: acumula resultados de todos los schemas
findFirstAcrossSchemascallable, string, array, boolmixed|nullEarly exit: retorna primer match

CrossSchemaQueryable (Trait) - Metodos Protegidos

MetodoParametrosRetornoDescripcion
resolveTargetSchemasstring, array, string, boolarrayResuelve lista de schemas objetivo
prioritizeCurrentSchemaarray, stringarrayMueve schema actual al inicio
attachSchemaMetadataobject, stringvoidAdjunta _schema al resultado

MultiSchemaService

MetodoParametrosRetornoDescripcion
getCurrentSchema-stringLee schema actual del JWT
isMultiSchemaActivestring, arrayboolVerifica si multi-schema esta activo
getTargetSchemasstring, array, stringarrayResuelve schemas objetivo

SchemaService

MetodoParametrosRetornoDescripcion
getSchemasWithTablestringarraySchemas que contienen una tabla
getSucursales-arraySchemas de tipo sucursal
getCajasstringarraySchemas de caja para una sucursal

ConnectionUtils (Trait) - Metodos Estaticos

MetodoParametrosRetornoDescripcion
extractSucursalSchemastringstringExtrae sucursal de schema de caja
buildSearchPathstringstringConstruye search_path jerarquico
setSchemaContextPDO, stringvoidEjecuta SET search_path
formatSchemaNamestringstringFormato 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.getTargetSchemas que filtra por sucursal)
  • RA-003: Consistencia de schema en recursos relacionados (via propiedad _schema en DTOs)
  • RA-005: Extensibilidad por modulo (nuevos servicios solo implementan interface + trait)

Historial de Cambios

FechaVersionDescripcion
2027-01-271.1Agregado ReciboRelationsService como ejemplo de implementación exitosa. Actualizada tabla de módulos candidatos.
2027-01-271.0Creacion del documento tecnico. Documenta interface, trait, servicios de soporte, estrategias de consulta, testing y patron de extension.