Home Blog Contact

What is $context variable in Shopware 6?

Jan 26th 2022

The variable $context is everywhere in Shopware 6 — it's omnipresent. If you want to create a product, list customers or place an order the $context variable will be there! But why? Simple. Depending on the given context (source, rules, language, currency... etc) Shopware will behave differently and perform specific operations. Uhmm, abstract. Let me give you some examples.

Example: language and currency for products

Entities in Shopware 6 (such product, category, cms page... among other) can have different data according to the language and currency. Please, notice that even the same language (English, in our example) data might differ from country to country. Let's give a product example:

Sales Channel Name Price Description
Storefront (German DE) Fußball €84.71 Das ist ein Fußball.
Storefront (English US) Soccer ball $99.99 This is a soccer ball.
Storefront (English UK) Football ball £72.59 This is a football ball.
Point of Sale (Spanish ES) Pelota de fútbol 77.12 € Esta es una pelota de fútbol.
ERP (Italian IT) Pallone da calcio 39.44 € Questo è un pallone da calcio.

In addition to that, please notice that currencies will be displayed differently:


Those were simple examples why $context is necessary. Shopware needs to know what source, rules, language, currency (... and other information) you are referring to while displaying, creating, updating and delete information, for example. That's why $context is basically requested everywhere in the code. It could be easily set up globally, however from an architectural stand point, that would be a bad decision, as any code would be highly tied to the Shopware application. Also that would create countless inconsistencies, making extremely difficult to debug and fix them.

Show me the code

Hopefully at this point you already understood why $context is necessary. The good news is that $context will be instantiated just one single time, right in the beginning of the each request. Either Storefront or API. The $context variable will be passed automatically from class to class throughout the entire system and it will be available most of the time. So you shouldn't worry about passing by yourself the language or currencies or making them displaying correctly the prices all over the system. Shopware will take care of that all for you.

Using $context (Shopware\Core\Framework\Context) in my controller HelloWorldController:

<?php declare(strict_types=1);

namespace MatheusGontijo\HelloWorld\Controller;

use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\Routing\Annotation\RouteScope;
use Shopware\Core\Framework\Routing\Annotation\Since;
use Shopware\Storefront\Controller\StorefrontController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

/**
 * @RouteScope(scopes={"storefront"})
 */
class HelloWorldController extends StorefrontController
{
    /**
     * @Route("/hello-world", name="frontend.helloworld", methods={"GET"})
     */
    public function helloworld(Context $context, Request $request)
    {
        echo 'Currency: ' . $context->getCurrencyId() . PHP_EOL;
        echo 'Language: ' . $context->getLanguageId() . PHP_EOL . PHP_EOL;

        echo $this->countToFiveService->doIt($context);

        exit;
    }
}

The browser output:

Currency: b7d2554b0ce847cd82f3ac9bd1c0dfca
Language: 2fbb5fe2e29a4d70aa5854ce7ce3e20b
12345

As said before, the $context will be available in every controller and event subscriber, so you can pass it to services. However, there are places where $context will not be available. I'll address that on the next section.


Be careful with Context::createDefaultContext()

There are places where $context will not be available, such as command lines, cron jobs and testing. Yes, in those scenarios you could use Context::createDefaultContext(). This method will create the default context using the default language and currency (among others variables) for you.

What is the problem of using Context::createDefaultContext() all the time? Simple. It does NOT carry important context variables. This will potentially break things so badly.

It's important to highlight that the first option (in most of the cases) should be the Shopware's default $context. By creating a $context instance by yourself there is a high chance of forgetting to setup important variables or even set it up incorrectly. That would create *serious* inconsistencies. Different context's, different operations. A great example of that would be forget to set up rules in $context. Shopware enables admin users to create dynamic rules through admin Rule Builder. These rules can drastically change how things work together. Let's say that admin users create a rule: 90% discount for customers from a specific country (Switzerland) during a specific holiday (The Swiss National Day 2022-08-01). This huge promotion will not be applied while placing an order.

Keep always in mind the $context concept. That's very important. It will be instantiated one single time and should be reused throughout the entire application as much as possible. It will be setup once on the highest level of your application and be passed down to lower levels.

Important: Please, don't abuse of Context::createDefaultContext() use. Enjoyed in moderation. If you are using many many times, there is a high chance you are using it inappropriately. That's why it's been marked as @internal.


But I need other context... not the default

That's fine, no problems. You can chose any other context. You can create the object and pass the params you wish.

$germanContext = new Context(
    new SystemSource(),                    // source
    [],                                    // rule ids
    'b7d2554b0ce847cd82f3ac9bd1c0dfca',    // currency ID
    ['2b6036f22dea4e5b931d449305a8d519'],  // language ID chain
);

$this->productRepository->update(
    [ /* update product using German data */ ],
    $germanContext
);

Of course there are other params to be passed while creating $context, but for the sake of simplicity I only passed those params. For the other params, please take a look at Shopware\Core\Framework\Context on the __construct method.

What about $salesChannelContext?

Good question. It's the very same idea of $context but $salesChannelContext carries more variables related to the sales context. Take a look on Shopware\Core\System\SalesChannel\SalesChannelContext.

Hope this post helps you to understand why $context variable is everywhere in Shopware 6. Thank you so much!


Extra links:




Shout out to Joshua Behrens, whom kindly provided some insights. Thank you for your support.