定制 mongoose-studio/phobos-framework-database-postgres 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

mongoose-studio/phobos-framework-database-postgres

Composer 安装命令:

composer require mongoose-studio/phobos-framework-database-postgres

包简介

Phobos Framework PostgreSQL Connector for Database Layer

README 文档

README

PHP Version License Phobos Framework

Phobos Framework

Driver PostgreSQL para Phobos Framework Database Layer. Aprovecha las características propias de PostgreSQL: schemas reales (search_path), INSERT ... RETURNING para leer el id autogenerado, columnas JSONB mapeadas a arrays de PHP, y claves primarias UUIDv7 generadas en la aplicación.

Características

  • 🐘 Conectividad PostgreSQL - DSN, sslmode, y configuración de sesión
  • 🗂️ Schemas reales - Configuración de search_path y nombres calificados schema.tabla
  • 🔄 Schema-per-tenant - Re-apuntado de schemas en runtime vía SchemaRegistry
  • ↩️ INSERT ... RETURNING - El id autogenerado (SERIAL/IDENTITY/uuid) se lee en el INSERT
  • 🧬 UUIDv7 - Claves primarias ordenadas por tiempo, generadas sin round-trip
  • 📦 JSONB - Mapeo automático entre arrays de PHP y columnas JSONB vía $casts
  • 🔀 Transaction Isolation - Los cuatro niveles estándar
  • 🎯 Savepoints - Transacciones anidadas completas

Instalación

composer require mongoose-studio/phobos-framework-database-postgres

Dependencias

Este driver requiere:

  • mongoose-studio/phobos-framework ^3.2
  • mongoose-studio/phobos-framework-database ^3.2
  • Extensión ext-pdo habilitada
  • Extensión ext-pdo_pgsql habilitada

Configuración

1. Registrar el Driver

En tu config/database.php:

<?php

return [
    'default' => 'pgsql',

    'drivers' => [
        'pgsql' => PhobosFramework\Database\Drivers\Postgres\PostgresDriver::class,
    ],

    'connections' => [
        'pgsql' => [
            'driver' => 'pgsql',
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', 5432),
            'database' => env('DB_DATABASE', 'app'),
            'username' => env('DB_USERNAME', 'postgres'),
            'password' => env('DB_PASSWORD', ''),
            'schema' => 'public',        // Opcional: search_path
        ],
    ],
];

2. Variables de Entorno

DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=app
DB_USERNAME=postgres
DB_PASSWORD=secret

Opciones de Configuración

Clave Tipo Descripción
host string Servidor PostgreSQL (requerido)
database string Nombre de la base de datos (requerido)
port int Puerto (opcional, por defecto 5432)
username string Usuario
password string Contraseña
sslmode string disable/allow/prefer/require/verify-ca/verify-full
schema string Un único schema para el search_path (ej: app)
search_path string Lista de schemas separada por comas (ej: app,public)
timezone string Zona horaria de la sesión (ej: UTC, America/Santiago)
application_name string Nombre de la aplicación (visible en pg_stat_activity)
client_encoding string Encoding del cliente (ej: UTF8)
options array Atributos PDO adicionales

Características Específicas de PostgreSQL

Schemas y search_path

PostgreSQL organiza las tablas en schemas dentro de una misma base de datos. Hay dos formas de trabajar con ellos:

A) search_path a nivel de conexión — la entidad no declara schema y se resuelve por el orden del search_path:

// config: 'search_path' => 'app,public'

class User extends TableEntity {
    protected static ?string $schema = null;  // resuelto por search_path
    protected static string $entity = 'users';
}

B) Nombre calificado por entidad — la entidad declara su schema; la capa genera "schema"."tabla":

class Invoice extends TableEntity {
    protected static ?string $schema = 'ventas';
    protected static string $entity = 'invoices';   // -> "ventas"."invoices"
}

Schema-per-tenant (re-apuntado en runtime)

El $schema de la entidad es un alias lógico. Con SchemaRegistry puedes mapearlo a un schema físico distinto por request, sin tocar el código de las entidades:

use PhobosFramework\Database\Schema\SchemaRegistry;

// En un middleware, según el tenant del request:
SchemaRegistry::getInstance()->register('ventas', "tenant_{$tenantId}");

// Ahora toda entidad con $schema = 'ventas' escribe/lee en "tenant_42"."invoices"

Claves primarias

El driver soporta tres estrategias vía $keyStrategy en la entidad:

// 1. auto (por defecto): SERIAL/IDENTITY; el id se lee con INSERT ... RETURNING
class Account extends TableEntity {
    protected static array $pk = ['id'];
    protected static string $keyStrategy = 'auto';
    public ?int $id = null;
}

// 2. uuidv7: el framework genera un UUIDv7 en PHP antes del INSERT (sin round-trip)
class Document extends TableEntity {
    protected static array $pk = ['id'];
    protected static string $keyStrategy = 'uuidv7';
    public mixed $id = null;   // columna UUID
}

// 3. manual: la aplicación asigna el valor
class Setting extends TableEntity {
    protected static array $pk = ['key'];
    protected static string $keyStrategy = 'manual';
    public string $key = '';
}

Un PK ya asignado siempre gana: se persiste tal cual, sin generar ni releer.

JSONB y casteo de atributos

Declara $casts para mapear columnas automáticamente entre su forma en la base de datos y su tipo nativo en PHP:

class Account extends TableEntity {
    protected static string $entity = 'accounts';
    protected static array $casts = [
        'meta'       => 'json',      // JSONB  <-> array PHP
        'active'     => 'bool',      // boolean (entiende 't'/'f')
        'created_at' => 'datetime',  // timestamp <-> DateTimeImmutable
    ];

    public mixed $meta = null;
    public mixed $active = null;
}

$account = new Account();
$account->meta = ['plan' => 'pro', 'seats' => 5];
$account->save();                       // se persiste como JSONB

$found = Account::findByPk($account->id);
$found->meta['plan'];                   // 'pro' (array PHP)

Nota sobre operadores JSONB y placeholders: los operadores ?, ?| y ?& de JSONB chocan con los placeholders ? de PDO. Para consultar dentro de JSONB usa where() crudo con operadores que no colisionen (->>, @>, #>>), por ejemplo: Account::find(["meta->>'plan' = ?" => 'pro']).

DELETE ... LIMIT

PostgreSQL no soporta DELETE ... LIMIT. Si se intenta, la capa lanza una excepción clara (LogicException) en lugar de emitir SQL inválido. Acota las filas con un WHERE.

Niveles de aislamiento

$driver->getSetIsolationLevelSQL('SERIALIZABLE');
// SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

Niveles soportados: READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE.

Tests

# Unit (sin base de datos)
composer test-unit

# Integración (requiere PostgreSQL real; configurar DB_* en phpunit.xml)
composer test-integration

# Todo
composer test

Los tests de integración crean tablas y schemas temporales en la base phobos_test y los limpian al terminar.

Arquitectura

  • PostgresDriver (src/Drivers/Postgres/PostgresDriver.php): extiende AbstractDriver. Genera el DSN, configura search_path/timezone/application_name, y expone la gramática.
  • PostgresGrammar (src/Drivers/Postgres/PostgresGrammar.php): extiende AnsiGrammar (comillas dobles). Activa RETURNING y deshabilita DELETE ... LIMIT.

Compatibilidad

  • PostgreSQL 12+ (probado contra 18.x)
  • PHP 8.4+

Licencia

Este proyecto está licenciado bajo la Licencia MIT - ver el archivo LICENSE para más detalles.

Autor

Marcel Rojas
marcelrojas16@gmail.com
Mongoose Studio

Contribuciones

Las contribuciones son bienvenidas. Por favor:

  1. Fork el proyecto
  2. Crea una rama para tu feature (git checkout -b feature/amazing-feature)
  3. Commit tus cambios (git commit -m 'Add amazing feature')
  4. Push a la rama (git push origin feature/amazing-feature)
  5. Abre un Pull Request

Phobos Framework by Mongoose Studio

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 5
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-07-14

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固