Contexts
Mayd uses two related, but separate concepts it calls *Context
and this page tries to explain them.
Request Context
As only Page
entities have a slug, only Page
s can be accessed by the user. Every Page
is connected to a Website
and therefor to the whole cluster of Locale
, Language
,
Country
and PageTreeApplication
.
The request context is the context the page was requested in. This doesn’t change much for things like the Page
itself,
as it is hard-linked to a website. However it is possible that you access an entity that has no connection to eg. a Language
itself.
This way you can switch for example the loaded news entries for a NewsBlock
depending on the request context.
The request context is essential for rendering templates and the context itself is one of the required global template variables.
Depending on how much info there is inside the request context, the request context will implement different interfaces, you can check for different interfaces. Depending on the amount of included data, the interfaces (and therefore the guarantees) will change:
RequestContextInterface
: an empty request context (also called “detached request context”), does guarantee nothingWebsiteRequestContextInterface
: guarantees that there is a website (and with that a language, country, locale and page tree application)PageRequestContextInterface
: the same as the website context, except that the page and content is guaranteed to be included as well.
Creating a Request Context
Normally you get the context for free, as they are passed to your page controller actions as $context
.
If you need to manually create a context, there are two ways:
-
Semi-automatically in your
FrontendController
by using$this->initializeRequestContext($localeCode);
in your action. This will take a look at the current domain + the given locale url code and try to match it. So you can add custom symfony routes by just including the locale code.
- Fully manual by using
RequestContextFactory::create*()
.
Content Context
A content context is similar to the request context, but not the same. While the request context tells you what the page dynamically was requested with, the content context tells you what the entity is statically associated with (via entity relations).
Why not just use Doctrine Relations?
Because of slots. The entities that most use ContentContext
s are probably blocks, and they are attached to a Slot
.
However, as slots itself are abstract, they contain no relation anywhere. The relations come from the concrete implementations
of these slots.
So the slot attached to a NewsEntry
has the news entry as context, while a slot attached to a Content
has the page
and the content as context.
The idea is that when implementing the content context, you first let your “parent” entities create their context and add the entity itself to it:
class MyBlock extends Block
{
public function getContext () : ContentContext
{
// this is just an example
// normally you only add structurally relevant elements to the context,
// and not blocks.
$context = $this->slot->getContext();
$context->add($this);
return $context;
}
}
This way the getContext()
call is propagated up to to a concrete implementation of an abstract entity (like your
news article slot). It can add the news article to the context and your block can react to it (or bail out, if there is
no news article).
“But isn’t using the content context enough? What do we need the request context for?”
We need the request context, because not everything is connected to everything. For example, it is possible to have news articles, that have a slot and the articles itself are only attached to a language.
But the news articles contain a slot and there they can contain a “job offers” block. The “job offers” block lists all offers in the current country + current language. So you need to fetch the country from the request context, as there is no country attached to this block / slot / news article.
Using the Content Context
Usage of the content context is straight-forward: just ask for the entity of the type you want:
$newsArticle = $context->get(NewsArticle::class);
assert($newsArticle instanceof NewsArticle || null === $newsArticle);
The content context searches with an instanceof
check, so you can ask for base types and will get the first match.
This can be a sub type or an object of the type itself.