---
title: Doctrine, ObjectModel y Multistore — 3 modulos
section: sample-modules
slug: entities-data
description: "3 modulos de ejemplo: Doctrine ORM en PS 9, override de ObjectModel con campo custom y formularios CRUD compatibles con multitienda."
last_updated: 2026-04
source_url: "https://ayudaprestashop.es/sample-modules/entities-data"
---

# Doctrine, ObjectModel y Multistore — 3 modulos

> 3 modulos de ejemplo: Doctrine ORM en PS 9, override de ObjectModel con campo custom y formularios CRUD compatibles con multitienda.

## demodoctrine — Entidades Doctrine ORM

Demuestra como usar **entidades Doctrine** en PrestaShop 9.0+ en lugar de ObjectModel. Doctrine es el ORM recomendado para nuevos desarrollos en PS 9.x.

> **[I] Repositorio**
>
> `github.com/PrestaShop/example-modules/tree/master/demodoctrine`

### Definir entidad Doctrine

*Entidad Doctrine con atributos PHP 8*

```php
<?php
// src/Entity/DemoEntity.php

namespace PrestaShop\Module\DemoDoctrine\Entity;

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: DemoEntityRepository::class)]
#[ORM\Table(name: 'ps_demo_doctrine_entity')]
class DemoEntity
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private ?int $id = null;

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

    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $description = null;

    #[ORM\Column(type: 'boolean')]
    private bool $active = true;

    #[ORM\Column(type: 'datetime_immutable')]
    private \DateTimeImmutable $createdAt;

    public function __construct(string $name)
    {
        $this->name = $name;
        $this->createdAt = new \DateTimeImmutable();
    }

    public function getId(): ?int { return $this->id; }
    public function getName(): string { return $this->name; }
    public function setName(string $name): self { $this->name = $name; return $this; }
    public function getDescription(): ?string { return $this->description; }
    public function setDescription(?string $desc): self { $this->description = $desc; return $this; }
    public function isActive(): bool { return $this->active; }
    public function setActive(bool $active): self { $this->active = $active; return $this; }
}
```

### Repository y DQL

*Repository con metodos custom*

```php
<?php
// src/Repository/DemoEntityRepository.php

namespace PrestaShop\Module\DemoDoctrine\Repository;

use Doctrine\ORM\EntityRepository;
use PrestaShop\Module\DemoDoctrine\Entity\DemoEntity;

class DemoEntityRepository extends EntityRepository
{
    public function findActiveItems(): array
    {
        return $this->createQueryBuilder('d')
            ->where('d.active = :active')
            ->setParameter('active', true)
            ->orderBy('d.createdAt', 'DESC')
            ->getQuery()
            ->getResult();
    }

    public function findByNameLike(string $search): array
    {
        return $this->createQueryBuilder('d')
            ->where('d.name LIKE :search')
            ->setParameter('search', '%' . $search . '%')
            ->getQuery()
            ->getResult();
    }
}
```

*Registrar Doctrine mapping en services.yml*

```yaml
# config/services.yml
services:
  _defaults:
    autowire: true
    autoconfigure: true

# Doctrine mapping - registrar entidades del modulo
doctrine:
  orm:
    mappings:
      DemoDoctrine:
        type: attribute
        dir: '%kernel.project_dir%/modules/demodoctrine/src/Entity'
        prefix: 'PrestaShop\Module\DemoDoctrine\Entity'
        is_bundle: false
```

*Crear tabla en install() con Doctrine schema*

```php
<?php
public function install(): bool
{
    // Opcion 1: SQL directo
    $sql = 'CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'demo_doctrine_entity` (
        `id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
        `name` VARCHAR(255) NOT NULL,
        `description` TEXT NULL,
        `active` TINYINT(1) NOT NULL DEFAULT 1,
        `created_at` DATETIME NOT NULL
    ) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8mb4';

    return parent::install() && Db::getInstance()->execute($sql);

    // Opcion 2: Doctrine Schema Tool (PS 9.0+)
    // $entityManager = $this->get('doctrine.orm.entity_manager');
    // $schemaTool = new SchemaTool($entityManager);
    // $schemaTool->createSchema([
    //     $entityManager->getClassMetadata(DemoEntity::class)
    // ]);
}
```

## demooverrideobjectmodel — Override ObjectModel

Muestra como hacer un **override de ObjectModel** (ej: Manufacturer) y anadir un campo custom a la tabla de BD. Requiere PS 9.0+.

> **[I] Repositorio**
>
> `github.com/PrestaShop/example-modules/tree/master/demooverrideobjectmodel`

*Override de Manufacturer con campo custom*

```php
<?php
// override/classes/Manufacturer.php

class Manufacturer extends ManufacturerCore
{
    /** @var string Custom field added by module */
    public $demo_custom_field;
}

// Tambien actualizar $definition en el modulo:
public function install(): bool
{
    // 1. Anadir columna a la tabla
    $sql = 'ALTER TABLE `' . _DB_PREFIX_ . 'manufacturer`
            ADD `demo_custom_field` VARCHAR(255) NULL DEFAULT NULL';
    Db::getInstance()->execute($sql);

    // 2. Copiar el override
    return parent::install()
        && $this->registerHook('actionManufacturerFormBuilderModifier')
        && $this->registerHook('actionAfterUpdateManufacturerFormHandler')
        && $this->registerHook('actionAfterCreateManufacturerFormHandler');
}

public function uninstall(): bool
{
    // Limpiar: quitar columna y override
    Db::getInstance()->execute(
        'ALTER TABLE `' . _DB_PREFIX_ . 'manufacturer` DROP COLUMN `demo_custom_field`'
    );
    return parent::uninstall();
}
```

## demomultistoreform — Multitienda CRUD

Demuestra como hacer formularios **compatibles con multitienda** en un contexto CRUD. Compatible desde PS 1.7.8.

> **[I] Repositorio**
>
> `github.com/PrestaShop/example-modules/tree/master/demomultistoreform`

*Configuracion por tienda en CRUD*

```php
<?php
// Guardar configuracion respetando el contexto de tienda
public function postProcess(): void
{
    if (Tools::isSubmit('submitDemoConfig')) {
        // Configuration::updateValue() automaticamente
        // guarda para el shop context actual
        Configuration::updateValue(
            'DEMO_MULTISTORE_SETTING',
            Tools::getValue('demo_setting')
        );

        // Para guardar para una tienda especifica:
        Configuration::updateValue(
            'DEMO_MULTISTORE_SETTING',
            Tools::getValue('demo_setting'),
            false,  // html
            null,    // id_shop_group
            $shopId  // id_shop especifico
        );
    }
}

// Leer respetando contexto:
public function getConfigValue(): string
{
    // Automatico segun contexto actual del BO
    return Configuration::get('DEMO_MULTISTORE_SETTING');

    // O para una tienda especifica:
    // return Configuration::get('DEMO_MULTISTORE_SETTING', null, null, $shopId);
}
```

> **[TIP] Doctrine vs ObjectModel en PS 9.x**
>
> - **Nuevo modulo PS 9+ only**: usa **Doctrine** (demodoctrine)
> - **Modulo retro-compatible 1.7/8/9**: usa **ObjectModel** (sigue funcionando)
> - **Extender entidad core**: usa **override** (demooverrideobjectmodel)
> - **CRUD multitienda**: usa **Configuration con shop context** (demomultistoreform)


---

*Fuente: [https://ayudaprestashop.es/sample-modules/entities-data](https://ayudaprestashop.es/sample-modules/entities-data). Version Markdown generada automaticamente para consumo por LLMs.*
