🏪

Formularios multitienda — checkboxes y configuracion por tienda

Actualizado: 2024-12-01

En instalaciones multitienda, la configuracion de un modulo puede ser diferente por tienda. Un error comun es usar Configuration::updateValue('KEY', $value) sin tener en cuenta el contexto, lo que sobreescribe la configuracion de todas las tiendas a la vez.

#El problema multitienda en formularios

⚠️
Configuration::updateValue sin contexto afecta a todas las tiendas

Si guardas Configuration::updateValue('MYKEY', $value) en el contexto 'ALL SHOPS', todas las tiendas veran ese valor aunque tengan su propia configuracion. Siempre pasa el id_shop correspondiente.

#Detectar el contexto multitienda

Detectar contexto y obtener el id_shop activo
php
<?php

// ¿Esta activa la funcion multitienda?
$isMultistoreActive = Shop::isFeatureActive();

// ¿En que contexto estamos?
$shopContext = Shop::getContext();
// Shop::CONTEXT_ALL   → Todas las tiendas
// Shop::CONTEXT_GROUP → Grupo de tiendas
// Shop::CONTEXT_SHOP  → Tienda especifica

// Obtener el id_shop activo (0 = global, >0 = tienda especifica)
$idShop = $this->context->shop->id;       // ID de la tienda activa
$idShopGroup = $this->context->shop->id_shop_group;

// Para formularios de configuracion:
if (Shop::isFeatureActive() && Shop::getContext() == Shop::CONTEXT_SHOP) {
    $idShop = (int) $this->context->shop->id;
} else {
    $idShop = null; // Sin restriccion de tienda
}

#Guardar configuracion por tienda

Guardar configuracion respetando el contexto
php
<?php

/**
 * Guardar configuracion de forma multitienda-safe.
 */
private function saveConfiguration(array $values): bool
{
    foreach ($values as $key => $value) {
        if (Shop::isFeatureActive()) {
            $ctx = Shop::getContext();

            if ($ctx == Shop::CONTEXT_SHOP) {
                // Guardar solo para la tienda activa
                Configuration::updateValue(
                    $key,
                    $value,
                    false,           // html
                    null,            // id_shop_group
                    (int) $this->context->shop->id  // id_shop
                );
            } elseif ($ctx == Shop::CONTEXT_GROUP) {
                // Guardar para el grupo de tiendas
                Configuration::updateValue(
                    $key,
                    $value,
                    false,
                    (int) $this->context->shop->id_shop_group,
                    null
                );
            } else {
                // Contexto ALL → guardar globalmente
                Configuration::updateValue($key, $value);
            }
        } else {
            // Sin multitienda → guardar globalmente
            Configuration::updateValue($key, $value);
        }
    }
    return true;
}

#Leer configuracion segun contexto

Leer configuracion con herencia de tiendas
php
<?php

// Leer con herencia: primero busca valor especifico de la tienda,
// si no existe, busca el del grupo, si no, el global
$value = Configuration::get('MY_KEY');

// Leer para una tienda especifica (sin herencia)
$valueForShop = Configuration::get('MY_KEY', null, null, 1); // id_shop = 1

// Leer para un grupo
$valueForGroup = Configuration::get('MY_KEY', null, 2, null); // id_shop_group = 2

// Verificar si tiene valor propio (no heredado)
$hasOwnValue = Configuration::hasContext('MY_KEY', null, Shop::CONTEXT_SHOP);

#Checkboxes multitienda en HelperForm

HelperForm con soporte multitienda automatico
php
<?php

protected function getConfigForm(): array
{
    return [
        'form' => [
            'legend' => [
                'title' => $this->trans('Configuration', [], 'Admin.Global'),
                'icon'  => 'icon-cogs',
            ],
            'input' => [
                [
                    'type'  => 'switch',
                    'label' => $this->trans('Enable module', [], 'Admin.Global'),
                    'name'  => 'MY_MODULE_ENABLED',
                    // Activar checkbox multitienda para este campo:
                    'class' => 't',
                    'is_bool' => true,
                    // PS mostrara el checkbox 'Todas las tiendas' automaticamente
                    // cuando multitienda esta activo
                ],
            ],
            'submit' => ['title' => $this->trans('Save', [], 'Admin.Actions')],
        ],
    ];
}

protected function renderForm(): string
{
    $helper = new HelperForm();
    $helper->module = $this;
    $helper->name_controller = $this->name;
    $helper->token = Tools::getAdminTokenLite('AdminMyModule');
    $helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name;

    // IMPORTANTE: registrar los ids para multitienda
    if (Shop::isFeatureActive()) {
        $helper->id_shop_list = Shop::getContextListShopID();
    }

    $helper->default_form_language = (int) $this->context->language->id;
    $helper->fields_value = $this->getConfigValues();

    return $helper->generateForm([$this->getConfigForm()]);
}

#Buenas practicas

PracticaDescripcion
Siempre comprobar Shop::isFeatureActive()No asumir que multitienda esta activo
Usar Shop::getContext() antes de guardarDeterminar el contexto correcto antes de updateValue()
Registrar la tienda en HelperForm$helper->id_shop_list para los checkboxes automaticos
Definir valores por defecto en install()Configuration::updateValue() en install() para todas las tiendas
Desinstalar por tiendasIterar todas las tiendas en uninstall() y borrar la config de cada una
Descargar en Markdown Pensado para pegar en ChatGPT, Claude u otra IA. Incluye solo el contenido de esta pagina.