Search by

elcommerce / magento2-app-emulation

elcommerce

A drop-in replacement for Magento App Emulation that supports nested environment emulation

Package info

github.com/elcommerce/magento2-app-emulation

Type:magento2-module

pkg:composer/elcommerce/magento2-app-emulation

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

1.0.0 2026-08-28 18:47 UTC

This package is auto-updated.

Last update: 2026-08-28 18:53:08 UTC


README

A drop-in replacement for Magento\Store\Model\App\Emulation that supports nested environment emulation.

Magento's standard implementation allows only one active emulation. If code that is already emulating a store calls another service that starts emulation, the inner call is ignored and its matching stop can restore the environment too early. This module keeps a stack of environment states so every start can be paired with a stop safely.

Features

  • Supports nested store-environment emulation.
  • Restores the preceding environment when each nested call finishes.
  • Preserves store, area, theme, locale, inline-translation state, and phrase renderer.
  • Replaces the Magento service through dependency injection, so existing consumers do not need to change their injected class.
  • Retains the public startEnvironmentEmulation() and stopEnvironmentEmulation() API.

Requirements

  • Magento 2 with magento/module-store
  • PHP 7.4 or later

Installation

Install the Composer package from a repository that provides it:

composer require elcommerce/magento2-app-emulation
bin/magento module:enable Elcommerce_AppEmulation
bin/magento setup:upgrade
bin/magento cache:clean

In production mode, regenerate dependency-injection code after installation:

bin/magento setup:di:compile

Confirm that the module is enabled:

bin/magento module:status Elcommerce_AppEmulation

Usage

Continue to inject Magento's standard emulation class. The module's DI preference supplies the nested-capable implementation automatically.

<?php

declare(strict_types=1);

namespace Vendor\Module\Model;

use Magento\Framework\App\Area;
use Magento\Store\Model\App\Emulation;

class StorefrontOperation
{
    private Emulation $appEmulation;

    public function __construct(Emulation $appEmulation)
    {
        $this->appEmulation = $appEmulation;
    }

    public function execute(int $storeId): void
    {
        $this->appEmulation->startEnvironmentEmulation(
            $storeId,
            Area::AREA_FRONTEND,
            true
        );

        try {
            // Run code that needs the selected store's design and locale.
            // Services called here may start their own emulation safely.
        } finally {
            $this->appEmulation->stopEnvironmentEmulation();
        }
    }
}

Always place the stop call in a finally block. Every call to startEnvironmentEmulation() creates a stack entry and must have exactly one matching call to stopEnvironmentEmulation().

Nested behavior

Given the following sequence:

$emulation->startEnvironmentEmulation($storeA);
$emulation->startEnvironmentEmulation($storeB);

$emulation->stopEnvironmentEmulation(); // Restores store A.
$emulation->stopEnvironmentEmulation(); // Restores the original environment.

The inner stop restores the outer emulated environment instead of ending all emulation. Calls may use different stores or areas.

The $force argument retains Magento's standard behavior. When it is false and the requested store and area are already active, the module records a balanced no-op frame. Passing true applies the requested environment unconditionally. In both cases, start and stop calls must remain balanced.

How it works

The module declares a DI preference from Magento\Store\Model\App\Emulation to Elcommerce\AppEmulation\Model\Emulation. Before applying a requested environment, it pushes the current state onto an in-process stack. Stopping emulation pops and restores the most recent state.

No configuration is required.

License

Licensed under the GNU General Public License v3.0.