💡 Buenas practicas en overrides de PrestaShop

Actualizado: 2024-12-01

Cuando los overrides son inevitables, seguir buenas practicas los hace mas seguros y mantenibles. El principio fundamental es: un override debe hacer lo minimo posible y delegar el resto al core original.

#Documentar los overrides

Documentacion obligatoria en cada override
php
<?php

if (!defined('_PS_VERSION_')) { exit; }

/**
 * Override de Product para mymodule.
 *
 * MODULO:   mymodule v1.2.0
 * RAZON:    Añadir campo de garantia extendida al producto.
 *           No hay hook disponible para este campo especifico.
 * METODOS:  getProductProperties() — añade 'warranty_months' al array de propiedades
 * TABLAS:   Lee de ps_mymodule_warranty (creada por mymodule)
 * PROBADO:  PS 8.1.x, PHP 8.2
 * CONTACTO: info@gmartos.es
 */
class Product extends ProductCore
{
    /**
     * Override minimo: llama al padre y añade solo lo necesario.
     */
    public static function getProductProperties($idLang, $product, Context $context = null): array
    {
        // 1. SIEMPRE llamar al padre primero
        $props = parent::getProductProperties($idLang, $product, $context);

        // 2. Solo añadir nuestro dato
        $props['warranty_months'] = (int) Db::getInstance()->getValue(
            'SELECT months FROM `' . _DB_PREFIX_ . 'mymodule_warranty`
             WHERE id_product = ' . (int) $product['id_product']
        );

        return $props;
    }
}

#Siempre llamar al padre

Patron correcto: delegar al padre y extender
php
<?php

// BIEN: llamar al padre y extender su resultado
public function getOrderTotal($withTaxes = true, $type = Cart::BOTH, $products = null, $idCarrier = null, $use_cache = true)
{
    // Llamar al padre primero
    $total = parent::getOrderTotal($withTaxes, $type, $products, $idCarrier, $use_cache);

    // Añadir logica solo si corresponde
    if ($type == Cart::BOTH && $this->id) {
        $extra = $this->getExtraCharge();
        $total += $extra;
    }

    return $total;
}

// MAL: sobreescribir completamente sin llamar al padre
// (perdemos todas las mejoras del core en futuras versiones)
// public function getOrderTotal(...) {
//     return 0.0;  // NUNCA HACER ESTO
// }

#Proteger contra actualizaciones de PS

Verificar la version de PS antes de aplicar override
php
<?php

// En el metodo overrideado, verificar la version si usas APIs internas
public function someMethod(): mixed
{
    // Verificar que el metodo del padre existe y tiene la firma esperada
    if (version_compare(_PS_VERSION_, '8.1.0', '>=')) {
        // Logica para PS 8.1+
        return parent::someMethod();
    } else {
        // Fallback para versiones anteriores
        return parent::someMethod();
    }
}

// Script de upgrade del modulo para re-instalar el override si PS cambia
// upgrade/upgrade-1.x.x.php:
function upgrade_module_1_x_x(Module $module): bool
{
    // Reinstalar el override si PS fue actualizado
    if (file_exists(_PS_ROOT_DIR_ . '/cache/class_index.php')) {
        unlink(_PS_ROOT_DIR_ . '/cache/class_index.php');
    }
    return true;
}

#Lo que nunca debes hacer

Nunca hacerPor queAlternativa
Sobreescribir sin llamar a parent::Rompe toda la logica del coreLlamar parent:: siempre
Override de __construct sin parent::__construct()El objeto queda en estado invalidoSiempre llamar parent::__construct()
Hardcodear IDs de tienda/idiomaFalla en multishop/multilingueUsar Context::getContext()
Override de clases Doctrine/SymfonyIncompatible con el container DIUsar Service Decoration
Override de interfaces del coreRompe el type system de PHPImplementar la misma interfaz
Modificar el archivo de override de otro moduloConflictos garantizadosFusion manual o uso de hooks
Descargar en Markdown Pensado para pegar en ChatGPT, Claude u otra IA. Incluye solo el contenido de esta pagina.