🗄️

Doctrine ORM en modulos PrestaShop 8/9

Actualizado: 2024-12-01

Doctrine ORM es el sistema de persistencia moderno para modulos de PrestaShop 8/9. A diferencia de ObjectModel, Doctrine usa mapeo objeto-relacional con anotaciones PHP y el EntityManager de Symfony para gestionar el ciclo de vida de los objetos.

AspectoObjectModelDoctrine ORM
CompatibilidadPS 1.5+PS 1.7.6+
ParadigmaActiveRecord (heredar de ObjectModel)DataMapper (POPO + anotaciones)
Multilenguaje$definition con 'lang'=>trueEntidad separada MyEntityLang
Multishop$definition con 'shop'=>trueTrait/asociacion por id_shop
ConsultasObjectModel::getByIdLang()QueryBuilder de Doctrine DBAL
Instalacion BDSql manual en install()SchemaTool::createSchema()
Recomendado paraCompatibilidad amplia, CRUD simplePS 8/9, arquitectura moderna, DI

#Definir una entidad

src/Entity/MyEntity.php — entidad Doctrine
php
<?php

declare(strict_types=1);

namespace MyModule\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Table(name="ps_my_entity")
 * @ORM\Entity(repositoryClass="MyModule\Repository\MyEntityRepository")
 */
class MyEntity
{
    /**
     * @ORM\Id
     * @ORM\Column(name="id_my_entity", type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private ?int $id = null;

    /**
     * @ORM\Column(name="name", type="string", length=255)
     */
    private string $name = '';

    /**
     * @ORM\Column(name="active", type="boolean", options={"default": true})
     */
    private bool $active = true;

    /**
     * @ORM\Column(name="date_add", type="datetime")
     */
    private \DateTimeInterface $dateAdd;

    public function __construct()
    {
        $this->dateAdd = new \DateTime();
    }

    // Getters
    public function getId(): ?int    { return $this->id; }
    public function getName(): string { return $this->name; }
    public function isActive(): bool  { return $this->active; }

    // Setters
    public function setName(string $name): self   { $this->name = $name; return $this; }
    public function setActive(bool $active): self  { $this->active = $active; return $this; }
}

#Instalar/desinstalar schema

mymodule.php — instalar y desinstalar tablas con SchemaTool
php
<?php

use Doctrine\ORM\Tools\SchemaTool;

public function install(): bool
{
    return parent::install()
        && $this->registerHook('actionFrontControllerSetMedia')
        && $this->installEntities();
}

public function uninstall(): bool
{
    $this->uninstallEntities();
    return parent::uninstall();
}

private function installEntities(): bool
{
    try {
        $em         = $this->get('doctrine.orm.entity_manager');
        $schemaTool = new SchemaTool($em);
        $classes    = [
            $em->getClassMetadata(\MyModule\Entity\MyEntity::class),
            $em->getClassMetadata(\MyModule\Entity\MyEntityLang::class),
        ];
        $schemaTool->updateSchema($classes, true); // true = safe mode
        return true;
    } catch (\Throwable $e) {
        $this->_errors[] = $e->getMessage();
        return false;
    }
}

private function uninstallEntities(): void
{
    try {
        $em         = $this->get('doctrine.orm.entity_manager');
        $schemaTool = new SchemaTool($em);
        $classes    = [
            $em->getClassMetadata(\MyModule\Entity\MyEntity::class),
            $em->getClassMetadata(\MyModule\Entity\MyEntityLang::class),
        ];
        $schemaTool->dropSchema($classes);
    } catch (\Throwable $e) {
        // Log but don't block uninstall
    }
}

#Acceder al Entity Manager

Acceder al EntityManager y operaciones CRUD
php
<?php

// Desde el modulo principal (acceso a container)
$em = $this->get('doctrine.orm.entity_manager');

// --- CREATE ---
$entity = new \MyModule\Entity\MyEntity();
$entity->setName('Mi entidad');
$entity->setActive(true);
$em->persist($entity);
$em->flush();
// $entity->getId() ahora tiene el ID generado

// --- READ ---
$repo   = $em->getRepository(\MyModule\Entity\MyEntity::class);
$entity = $repo->find(42);                          // Por ID
$all    = $repo->findAll();                          // Todos
$active = $repo->findBy(['active' => true]);         // Con filtro
$one    = $repo->findOneBy(['name' => 'Mi nombre']); // Primero que coincide

// --- UPDATE ---
$entity->setName('Nuevo nombre');
$em->flush(); // No necesita persist si ya esta gestionado

// --- DELETE ---
$em->remove($entity);
$em->flush();

#Repositorios y queries

src/Repository/MyEntityRepository.php — queries personalizadas
php
<?php

declare(strict_types=1);

namespace MyModule\Repository;

use Doctrine\ORM\EntityRepository;
use MyModule\Entity\MyEntity;

class MyEntityRepository extends EntityRepository
{
    /**
     * Buscar entidades activas con paginacion.
     *
     * @return MyEntity[]
     */
    public function findActivePaginated(int $page = 1, int $limit = 20): array
    {
        return $this->createQueryBuilder('e')
            ->where('e.active = :active')
            ->setParameter('active', true)
            ->orderBy('e.id', 'DESC')
            ->setFirstResult(($page - 1) * $limit)
            ->setMaxResults($limit)
            ->getQuery()
            ->getResult();
    }

    /**
     * Busqueda por nombre con LIKE.
     */
    public function searchByName(string $term): array
    {
        return $this->createQueryBuilder('e')
            ->where('e.name LIKE :term')
            ->setParameter('term', '%' . $term . '%')
            ->getQuery()
            ->getResult();
    }
}

#services.yml — configuracion

config/services.yml — registrar el repositorio como servicio
yaml
services:
  _defaults:
    autowire: true
    autoconfigure: true
    public: true

  MyModule\:
    resource: '../src/'
    exclude:
      - '../src/Entity/'

  MyModule\Repository\MyEntityRepository:
    factory: ['@doctrine.orm.entity_manager', 'getRepository']
    arguments:
      - MyModule\Entity\MyEntity
Descargar en Markdown Pensado para pegar en ChatGPT, Claude u otra IA. Incluye solo el contenido de esta pagina.