$context
variable in Shopware 6?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.
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:
$, €, £, ¥
$9.99
€9.99
(before)9.99 €
(after)100,000.00
100.000,00
(there are even variations among countries)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.
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.
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
.
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.
$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!
Shout out to Joshua Behrens, whom kindly provided some insights. Thank you for your support.