shedeza/sybase-orm

Pure PHP ORM for Sybase ASE — framework-agnostic

Maintainers

Package info

github.com/shedeza/sybase-orm

pkg:composer/shedeza/sybase-orm

Statistics

Installs: 303

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

v4.0.1 2026-06-22 15:58 UTC

README

CI PHP 8.1+ Licencia MIT Estado

ORM puro en PHP para Sybase ASE, independiente de framework. Soporta mapeo de entidades con atributos PHP 8.1, consultas OQL, QueryBuilder, relaciones, herencia, caché de dos niveles, migraciones y más.

Estado: Este proyecto es estable y apto para uso en producción. Reporta cualquier problema en Issues.

Características

  • Mapeo de entidades con atributos nativos de PHP 8.1 (sin XML ni YAML)
  • Patrón Data Mapper con Unit of Work e Identity Map
  • Lenguaje de consultas OQL y QueryBuilder fluido
  • Relaciones ManyToOne, OneToMany, OneToOne, ManyToMany con lazy/eager loading
  • Herencia de entidades (TPH, TPT, TPC)
  • Caché de dos niveles (memoria + Redis)
  • Sistema de migraciones integrado
  • Soft delete declarativo
  • Hooks de ciclo de vida (PrePersist, PostPersist, PreUpdate, etc.)
  • Value Objects embebibles
  • Conexiones múltiples con EntityManagerRegistry
  • Soporte para conexiones de solo lectura
  • CLI de migraciones (bin/sybase-orm)
  • Timestamps automáticos (#[Timestamps])
  • Paginación con metadatos (paginate())
  • Query Scopes globales (#[GlobalScope])
  • Subqueries en QueryBuilder (whereIn, whereNotIn, whereExists)
  • BETWEEN, NOT BETWEEN, IS NULL, LIKE, NOT LIKE en OQL y QueryBuilder
  • Funciones SQL built-in (UPPER, LOWER, COALESCE, LEN, DATEADD, etc.)
  • UNION / UNION ALL entre queries
  • Todos los JOINs: INNER, LEFT, RIGHT, CROSS, FULL OUTER
  • Serialización (toArray()/toJson())
  • Mass assignment protection (fill()/forceFill())
  • Batch processing para grandes datasets
  • Native SQL mapping (createNativeQuery())
  • Entity listeners externos (#[EntityListener])
  • Read-only entities (#[Immutable])
  • Cache regions por entidad (#[CacheRegion])
  • Model factories para testing (EntityFactory)
  • Sistema de instrumentación/profiling
  • Query Explain Plan (SHOWPLAN)
  • Metadata introspection
  • Optimistic locking (#[Version])
  • Pessimistic locking (HOLDLOCK/UPDLOCK vía LockMode)
  • Connection pooling para workers long-running
  • Partial entity loading (cargar solo columnas específicas)
  • Result Set Mapping para Native SQL multi-entidad
  • Audit trail automático (#[Auditable])
  • Database seeders (SeederInterface)
  • Validación pre-persist (length, NOT NULL, precision)
  • #[UniqueEntity] — validación de unicidad antes de INSERT
  • #[Index], #[Check], #[UniqueConstraint] — DDL constraints
  • #[Column(default: value)] — valores por defecto
  • #[JoinColumn(onDelete: 'CASCADE')] — FK referential actions

Requisitos del sistema

  • PHP 8.1 o superior
  • Extensión ext-pdo_dblib
  • Servidor Sybase ASE

Instalación

composer require shedeza/sybase-orm

Configuración rápida

Configuración por array

use SybaseORM\ORM\OrmFactory;

$em = OrmFactory::create([
    'connection' => [
        'host'     => '192.168.1.100',
        'port'     => 5000,
        'dbname'   => 'mi_base',
        'username' => 'sa',
        'password' => 'secret',
        'charset'  => 'UTF-8',
    ],
    'entity_directories' => [__DIR__ . '/src/Entity'],
]);

Configuración por URL DSN

use SybaseORM\ORM\OrmFactory;

$em = OrmFactory::createFromUrl(
    'sybase://sa:secret@192.168.1.100:5000/mi_base?charset=UTF-8',
    entityDirectories: [__DIR__ . '/src/Entity'],
);

Los caracteres especiales en la contraseña deben codificarse con URL encoding (por ejemplo, p@ssp%40ss).

Uso básico

Persistir una entidad

$usuario = new Usuario();
$usuario->nombre = 'Juan';
$usuario->email = 'juan@example.com';

$em->persist($usuario);
$em->flush();

Buscar por ID

$usuario = $em->find(Usuario::class, 1);

Consultar con OQL

$usuarios = $em->query(
    'SELECT u FROM Usuario u WHERE u.activo = :activo',
    ['activo' => true]
);

QueryBuilder

$usuarios = $em->createQueryBuilder(Usuario::class)
    ->where('e.activo = :activo')
    ->andWhere('e.creadoEn > :fecha')
    ->setParameter('activo', true)
    ->setParameter('fecha', new \DateTime('-30 days'))
    ->orderBy('e.nombre', 'ASC')
    ->setMaxResults(10)
    ->getResult();

Transacciones

$em->transactional(function () use ($em) {
    $cuenta1 = $em->find(Cuenta::class, 1);
    $cuenta2 = $em->find(Cuenta::class, 2);

    $cuenta1->saldo -= 500;
    $cuenta2->saldo += 500;

    $em->flush();
});

Para manejo manual de transacciones:

$em->beginTransaction();
try {
    $em->persist($entidad);
    $em->flush();
    $em->commit();
} catch (\Throwable $e) {
    $em->rollback();
    throw $e;
}

Eliminar una entidad

$em->remove($usuario);
$em->flush();

Mapeo de entidades

use SybaseORM\Attribute\Entity;
use SybaseORM\Attribute\Id;
use SybaseORM\Attribute\Column;
use SybaseORM\Attribute\GeneratedValue;

#[Entity(table: 'usuarios')]
class Usuario
{
    #[Id]
    #[GeneratedValue]
    #[Column(type: 'integer')]
    public ?int $id = null;

    #[Column(type: 'string', length: 100)]
    public string $nombre = '';

    #[Column(type: 'string', length: 255, nullable: true)]
    public ?string $email = null;

    #[Column(type: 'datetime')]
    public ?\DateTimeInterface $creadoEn = null;
}

Atributos PHP principales

Atributo Destino Descripción
#[Entity] Clase Marca una clase como entidad mapeada. Parámetros: table, schema, repositoryClass, connection
#[Id] Propiedad Marca la propiedad como clave primaria
#[Column] Propiedad Mapea una propiedad a una columna. Parámetros: name, type, nullable, length, precision, scale
#[GeneratedValue] Propiedad Indica que el valor es generado por la base de datos. Parámetro: strategy
#[ManyToOne] Propiedad Relación muchos-a-uno. Parámetros: targetEntity, inversedBy, cascade, fetch
#[OneToMany] Propiedad Relación uno-a-muchos. Parámetros: targetEntity, mappedBy, cascade, fetch, orphanRemoval
#[SoftDelete] Clase Activa eliminación lógica. Parámetro: column (por defecto deleted_at)
#[HasLifecycleHooks] Clase Activa hooks de ciclo de vida en la entidad

Para la lista completa de atributos (OneToOne, ManyToMany, Embedded, herencia, hooks), consulte el manual de mapeo de entidades.

Relaciones

El ORM soporta relaciones #[ManyToOne], #[OneToMany], #[OneToOne] y #[ManyToMany] con lazy loading automático mediante proxies y eager loading vía QueryBuilder::with().

Para documentación detallada de relaciones, consulte el manual de relaciones.

Conexiones múltiples

Use EntityManagerRegistry para gestionar conexiones a múltiples bases de datos:

use SybaseORM\ORM\OrmFactory;
use SybaseORM\ORM\EntityManagerRegistry;

$emDefault = OrmFactory::create(['connection' => $configDefault, 'entity_directories' => $dirs]);
$emReportes = OrmFactory::create(['connection' => $configReportes, 'entity_directories' => $dirs]);

$registry = new EntityManagerRegistry([
    'default'  => $emDefault,
    'reportes' => $emReportes,
], defaultConnection: 'default');

// Obtener un manager específico
$em = $registry->getManager('reportes');

// Obtener el manager por defecto
$em = $registry->getDefaultManager();

// Obtener el manager que gestiona una entidad (por su atributo connection)
$em = $registry->getManagerForEntity(Reporte::class);

Opciones de configuración

Opción Tipo Valor por defecto Descripción
host string 'localhost' Host del servidor Sybase ASE
port int 5000 Puerto de conexión
dbname string (requerido) Nombre de la base de datos
username string '' Usuario de conexión
password string '' Contraseña de conexión
charset string 'UTF-8' Charset de la conexión
persistent bool false Usar conexiones persistentes
charset_conversion bool false Activar conversión automática UTF-8 ↔ ISO-8859-1
read_only bool false Modo solo lectura (previene escrituras)
entity_directories string[] [] Directorios donde buscar entidades
entity_classes string[] [] Clases de entidad explícitas
proxy_directory string sys_get_temp_dir() . '/sybase-orm-proxies' Directorio para proxies generados
metadata_cache_dir string|null null Directorio de caché de metadatos
redis array|null null Configuración de Redis para caché L2 (ver abajo)
second_level_cache SecondLevelCacheInterface|null null Instancia de caché L2 ya configurada
file_permissions int 0o666 Permisos de archivos generados (proxies, cache)
directory_permissions int 0o777 Permisos de directorios generados

Caché de segundo nivel (Redis)

Para activar el caché compartido entre requests:

$em = OrmFactory::create([
    'connection' => $connectionConfig,
    'entity_directories' => [__DIR__ . '/src/Entity'],
    'redis' => [
        'host' => '127.0.0.1',
        'port' => 6379,
        'password' => null,      // opcional
        'database' => 0,         // opcional
        'timeout' => 2.0,        // segundos
        'prefix' => 'myapp:',    // prefijo de keys
    ],
]);

O si ya tenés una instancia de Redis configurada:

use SybaseORM\Cache\RedisCacheAdapter;

$redis = new \Redis();
$redis->connect('127.0.0.1');

$em = OrmFactory::create([
    'connection' => $connectionConfig,
    'entity_directories' => [__DIR__ . '/src/Entity'],
    'second_level_cache' => new RedisCacheAdapter($redis),
]);

Documentación completa

Contribuir

Las contribuciones son bienvenidas. Antes de enviar un PR, consulta la guía de contribución para conocer el flujo de trabajo, estándares de código y convenciones del proyecto.

# Ejecutar tests
composer test

# Análisis estático
composer phpstan

# Formateo de código
composer cs-fix

CLI

php bin/sybase-orm help               # Show all commands

# Migrations
php bin/sybase-orm migrate            # Run pending migrations
php bin/sybase-orm migrate:rollback   # Rollback last migration
php bin/sybase-orm migrate:status     # Show migration status
php bin/sybase-orm migrate:generate   # Generate migration from entity diff
php bin/sybase-orm migrate:preview    # Preview SQL without executing
php bin/sybase-orm migrate:fresh      # Drop all + re-run (requires --force)
php bin/sybase-orm migrate:reset      # Rollback ALL migrations (requires --force)

# Generators
php bin/sybase-orm make:migration     # Auto-diff entities vs DB, generate migration
php bin/sybase-orm make:migration --empty  # Create empty migration for manual SQL
php bin/sybase-orm make:entity User   # Generate entity class skeleton

# Schema & Cache
php bin/sybase-orm schema:validate    # Validate mapping vs DB schema
php bin/sybase-orm cache:clear        # Clear proxy and metadata caches
php bin/sybase-orm orm:info           # Show all mapped entities

Seeders

use SybaseORM\Testing\SeederInterface;

class UserSeeder implements SeederInterface {
    public function run(\SybaseORM\ORM\EntityManagerInterface $em): void {
        $user = new User();
        $user->email = 'admin@app.com';
        $em->persist($user);
        $em->flush();
    }
}

// Run seeders
$runner = new \SybaseORM\Testing\SeederRunner($em);
$runner->run([new UserSeeder(), new ProductSeeder()]);

Licencia

Este proyecto está licenciado bajo la Licencia MIT.