shedeza/sybase-ase-orm-bundle

Symfony Bundle for Sybase ASE ORM

Installs: 4

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

Type:symfony-bundle

pkg:composer/shedeza/sybase-ase-orm-bundle

1.0.6 2025-11-07 19:35 UTC

This package is auto-updated.

Last update: 2025-11-07 20:26:57 UTC


README

Version License PHP Symfony

Un Bundle de Symfony que implementa un Object-Relational Mapper (ORM) para Sybase ASE.

Características

  • Mapeo de Entidades: Utiliza PHP Attributes para definir entidades y sus propiedades
  • Entity Manager: Manejo de persistencia con métodos persist(), remove(), flush()
  • Repositorios: Patrón Repository con métodos comunes (find(), findAll(), findBy(), etc.)
  • Relaciones: Soporte completo para OneToOne, OneToMany, ManyToOne y ManyToMany con cascadas
  • OQL: Lenguaje de consulta orientado a objetos
  • Transacciones: Manejo automático de transacciones
  • Lazy Loading: Carga perezosa de relaciones (implementación básica)

Instalación

composer require shedeza/sybase-ase-orm-bundle

Configuración

Agregar en config/bundles.php:

return [
    // ...
    Shedeza\SybaseAseOrmBundle\SybaseAseOrmBundle::class => ['all' => true],
];

Configurar en config/packages/sybase_ase_orm.yaml:

sybase_ase_orm:
  default_connection: default
  default_entity_manager: default
  
  connections:
    default: '%env(resolve:DATABASE_SYBASE_URL)%'
  
  entity_managers:
    default:
      connection: default
      mappings:
        App:
          type: attribute
          dir: '%kernel.project_dir%/src/Entity'
          prefix: 'App\Entity'

Agregar en tu archivo .env:

# Format: sybase://username:password@host:port/database?charset=utf8
DATABASE_SYBASE_URL=sybase://sa:your_password@localhost:5000/mydb?charset=utf8

Configuración Alternativa (Detallada)

También puedes usar la configuración detallada:

sybase_ase_orm:
  connections:
    default:
      host: '%env(SYBASE_HOST)%'
      port: '%env(int:SYBASE_PORT)%'
      database: '%env(SYBASE_DATABASE)%'
      username: '%env(SYBASE_USERNAME)%'
      password: '%env(SYBASE_PASSWORD)%'
      charset: '%env(SYBASE_CHARSET)%'

Uso Básico

Definir una Entidad

Entidad con Llave Primaria Simple

<?php

namespace App\Entity;

use Shedeza\SybaseAseOrmBundle\ORM\Mapping as ORM;

#[ORM\Entity]
#[ORM\Table(name: 'users')]
class User
{
    #[ORM\Id]
    #[ORM\GeneratedValue(strategy: ORM\GeneratedValue::IDENTITY)]
    #[ORM\Column(type: 'integer')]
    private ?int $id = null;

    #[ORM\Column(type: 'string', length: 100)]
    private string $username;

    #[ORM\Column(type: 'string', length: 255)]
    private string $email;

    // getters y setters...
}

Entidad con Llave Primaria Compuesta

<?php

namespace App\Entity;

use Shedeza\SybaseAseOrmBundle\ORM\Mapping as ORM;

#[ORM\Entity]
#[ORM\Table(name: 'user_roles')]
class UserRole
{
    #[ORM\Id]
    #[ORM\Column(type: 'integer')]
    private ?int $userId = null;

    #[ORM\Id]
    #[ORM\Column(type: 'integer')]
    private ?int $roleId = null;

    #[ORM\Column(type: 'datetime')]
    private ?\DateTime $assignedAt = null;

    // getters y setters...
}

Usar el Entity Manager

<?php

namespace App\Controller;

use Shedeza\SybaseAseOrmBundle\ORM\EntityManager;
use App\Entity\User;

class UserController
{
    public function create(EntityManager $entityManager): void
    {
        $user = new User();
        $user->setUsername('john_doe');
        $user->setEmail('john@example.com');

        $entityManager->persist($user);
        $entityManager->flush();
    }

    public function find(EntityManager $entityManager, int $id): ?User
    {
        return $entityManager->find(User::class, $id);
    }
    
    public function findComposite(EntityManager $entityManager): ?UserRole
    {
        // Buscar por llave primaria compuesta
        $compositeId = ['userId' => 1, 'roleId' => 2];
        return $entityManager->find(UserRole::class, $compositeId);
    }
}

Usar Repositorios

Repositorio Básico

<?php

$repository = $entityManager->getRepository(User::class);

// Buscar por ID
$user = $repository->find(1);

// Buscar todos
$users = $repository->findAll();

// Buscar con criterios
$users = $repository->findBy(['username' => 'john_doe']);

// Buscar uno con criterios
$user = $repository->findOneBy(['email' => 'john@example.com']);

Repositorios Personalizados

<?php

namespace App\Repository;

use Shedeza\SybaseAseOrmBundle\ORM\Repository\AbstractRepository;
use App\Entity\User;

class UserRepository extends AbstractRepository
{
    public function findByUsername(string $username): ?User
    {
        $query = $this->createQuery('SELECT u FROM User u WHERE u.username = :username');
        $query->setParameter('username', $username);
        return $query->getSingleResult();
    }

    public function findActiveUsers(): array
    {
        $query = $this->createQuery('SELECT u FROM User u WHERE u.createdAt IS NOT NULL ORDER BY u.createdAt DESC');
        return $query->getResult();
    }
}

Inyección Directa de Repositorios

<?php

// Los repositorios se pueden inyectar directamente
use App\Repository\UserRepository;

class UserService
{
    public function __construct(
        private UserRepository $userRepository
    ) {}
    
    public function getActiveUsers(): array
    {
        return $this->userRepository->findActiveUsers();
    }
}
<?php

namespace App\Entity;

use Shedeza\SybaseAseOrmBundle\ORM\Mapping as ORM;
use App\Repository\UserRepository;

#[ORM\Entity]
#[ORM\Repository(repositoryClass: UserRepository::class)]
#[ORM\Table(name: 'users')]
class User
{
    // ...
}

Consultas OQL

Consultas Básicas

<?php

$query = $entityManager->createQuery('SELECT u FROM User u WHERE u.username = :username');
$query->setParameter('username', 'john_doe');
$users = $query->getResult();

Consultas con JOINs

Sintaxis tradicional con ON
<?php

// INNER JOIN
$query = $entityManager->createQuery('
    SELECT u FROM User u 
    INNER JOIN Post p ON p.author = u.id 
    WHERE p.title LIKE :title
');
$query->setParameter('title', '%post%');
$users = $query->getResult();

// LEFT JOIN
$query = $entityManager->createQuery('
    SELECT u FROM User u 
    LEFT JOIN Post p ON p.author = u.id 
    ORDER BY u.username ASC
');
$users = $query->getResult();
Sintaxis WITH (estilo Doctrine)
<?php

// JOIN usando asociaciones definidas en entidades
$query = $entityManager->createQuery('
    SELECT u FROM User u 
    INNER JOIN u.posts p
    ORDER BY u.username ASC
');
$users = $query->getResult();

// JOIN con condiciones WITH
$query = $entityManager->createQuery('
    SELECT u FROM User u 
    INNER JOIN u.posts p WITH p.title LIKE :title
    ORDER BY u.username ASC
');
$query->setParameter('title', '%post%');
$users = $query->getResult();

// LEFT JOIN con WITH
$query = $entityManager->createQuery('
    SELECT p FROM Post p
    LEFT JOIN p.author u WITH u.email LIKE :domain
    ORDER BY p.id DESC
');
$query->setParameter('domain', '%@example.com');
$posts = $query->getResult();

// JOINs anidados con WITH
$query = $entityManager->createQuery('
    SELECT p FROM Post p
    INNER JOIN p.author u WITH u.createdAt IS NOT NULL
    LEFT JOIN u.posts p2 WITH p2.id != p.id
    ORDER BY p.id DESC
');
$posts = $query->getResult();

Relaciones

<?php

#[ORM\Entity]
class Post
{
    #[ORM\ManyToOne(targetEntity: User::class, inversedBy: 'posts')]
    #[ORM\JoinColumn(name: 'author_id', referencedColumnName: 'id')]
    private ?User $author = null;
}

#[ORM\Entity]
class User
{
    #[ORM\OneToMany(targetEntity: Post::class, mappedBy: 'author')]
    private array $posts = [];
}

Atributos Disponibles

Entidades y Tablas

  • #[ORM\Entity]: Marca una clase como entidad
  • #[ORM\Repository(repositoryClass: MyRepository::class)]: Define repositorio personalizado
  • #[ORM\Table(name: 'table_name')]: Define el nombre de la tabla
  • #[ORM\Index(columns: ['field1', 'field2'])]: Define índices

Campos

  • #[ORM\Column(type: 'string', length: 255)]: Define una columna
  • #[ORM\Id]: Marca una propiedad como identificador
  • #[ORM\GeneratedValue]: Define estrategia de generación de ID

Relaciones

  • #[ORM\OneToOne]: Relación uno a uno
  • #[ORM\OneToMany]: Relación uno a muchos
  • #[ORM\ManyToOne]: Relación muchos a uno
  • #[ORM\ManyToMany]: Relación muchos a muchos
  • #[ORM\JoinColumn]: Define columna de unión
  • #[ORM\JoinTable]: Define tabla de unión para ManyToMany

Eventos del Ciclo de Vida

  • #[ORM\PrePersist]: Ejecuta antes de persistir
  • #[ORM\PostPersist]: Ejecuta después de persistir

Características Avanzadas

Manejo de Transacciones

<?php

// Transacción manual
$entityManager->getConnection()->beginTransaction();
try {
    $entityManager->persist($entity1);
    $entityManager->persist($entity2);
    $entityManager->flush();
    $entityManager->getConnection()->commit();
} catch (\Exception $e) {
    $entityManager->getConnection()->rollback();
    throw $e;
}

// Transacción automática
$result = $entityManager->transactional(function($em) {
    $em->persist($entity1);
    $em->persist($entity2);
    return $entity1->getId();
});

Gestión del Ciclo de Vida

<?php

// Limpiar todas las entidades del contexto
$entityManager->clear();

// Desconectar una entidad específica
$entityManager->detach($entity);

// Limpiar cache de metadatos
$entityManager->clearMetadataCache();

Logging de Consultas

<?php

use Shedeza\SybaseAseOrmBundle\DBAL\Logger\QueryLogger;

class MyQueryLogger implements QueryLogger
{
    public function logQuery(string $sql, array $params = [], float $executionTime = 0.0): void
    {
        error_log("SQL: {$sql} - Time: {$executionTime}s");
    }
}

$connection = new Connection($config, new MyQueryLogger());

Testing

# Ejecutar tests
composer test

# O directamente con PHPUnit
vendor/bin/phpunit

Requisitos

  • PHP 8.1+
  • Symfony 6.0+ o 7.0+
  • Extensión PDO_DBLIB
  • Sybase ASE 15.0+

Optimizaciones Incluidas

  • Cache de metadatos: Los metadatos de entidades se cachean automáticamente
  • Cache de parsing OQL: Las consultas parseadas se cachean para mejor rendimiento
  • Lazy loading: Carga perezosa de relaciones (implementación básica)
  • Identity Map: Previene duplicación de objetos en memoria
  • Transacciones optimizadas: Solo inicia transacciones cuando hay cambios pendientes

Contribuir

  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

Licencia

MIT