netzmacht / contao-page-context
This library provides tools to bootstrap the contao page contexts for custom routes.
Fund package maintenance!
dmolineus
Installs: 16 413
Dependents: 2
Suggesters: 0
Security: 0
Stars: 3
Watchers: 2
Forks: 1
Open Issues: 0
Type:contao-bundle
Requires
- php: ^8.1
- beberlei/assert: ^2.7 || ^3.0
- contao/core-bundle: ^4.13 || ^5.2
- netzmacht/contao-toolkit: ^3.9 || ^4.0
- psr/log: ^1.0 || ^2.0 || ^3.0
- symfony/config: ^5.4 || ^6.0
- symfony/dependency-injection: ^5.4 || ^6.0
- symfony/http-foundation: ^5.4 || ^6.0
- symfony/http-kernel: ^5.4 || ^6.0
- symfony/security-core: ^5.4 || ^6.0
- symfony/translation-contracts: ^1.1 || ^2.0 || ^3.0
Requires (Dev)
- contao/manager-plugin: ^2.0
- doctrine/coding-standard: ^12.0
- friends-of-phpspec/phpspec-expect: ^4.0
- netzmacht/phpspec-phpcq-plugin: @dev
- phpcq/runner-bootstrap: ^1.0@dev
- phpspec/phpspec: ^7.0
This package is auto-updated.
Last update: 2024-10-07 17:08:04 UTC
README
This Contao extension allows developer manually boot the page context of Contao when using custom routes.
Parts of the Contao CMS relies on the existing of global state initialized when rendering a page. Modules, content elements, insert tags and custom extensions might rely that this state is initialized.
For instance Contao developers access the $GLOBALS['objPage']
as there is no other way to get the current page.
However, when using a custom entrypoint, for example for an API, you don't have this state initialized. Using the Contao library and functionality might end in unexpected errors.
This is the point there this extension steps in. It allows you to boot the page context manually for your route.
In detail it, initialize following steps:
- The Contao framework
- Constant
BE_USER_LOGGED_IN
andFE_USER_LOGGED_IN
tofalse
if not defined. - Loading the page from the database
- Globals
objPage
,TL_ADMIN_NAME
,TL_ADMIN_EMAIL
,TL_KEYWORDS
,TL_LANGUAGE
- Initialize the locale of the request and the translator
- Loads the default language file
- Calls
Controller::initializeStaticUrls()
- Initializes the page layout (triggers
getPageLayout
hook)
Requirements
- Contao
^4.9
- PHP
^7.1 || ^8.0
Installation
php composer.phar require netzmacht/contao-page-context --update-no-dev -o
Usage
1. Implement a PageIdDeterminator and register it properly
First you have to provide a PageIdDeterminator. It's responsible to extract the page id from the given request.
You should limit the determinator to your special use case, that's why there is the match()
method.
<?php declare(strict_types=1); namespace My\Bundle; use Netzmacht\Contao\PageContext\Request\PageIdDeterminator; use Netzmacht\Contao\PageContext\Exception\DeterminePageIdFailed; use Symfony\Component\HttpFoundation\Request; final class MyPageIdDeterminator implements PageIdDeterminator { public function match(Request $request): bool { return ($request->attributes->get('_my_context') === 'page'); } public function determinate(Request $request): int { if (!$request->attributes->has('pageId')) { throw new DeterminePageIdFailed('Could not determine page id for from request.'); } return $request->attributes->getInt('pageId'); } }
Now you have to register it as a service and tag it as Netzmacht\Contao\PageContext\Request\PageIdDeterminator
.
<?xml version="1.0" encoding="UTF-8" ?> <container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd"> <services> <service id="My\Bundle\MyPageIdDeterminator"> <tag name="Netzmacht\Contao\PageContext\Request\PageIdDeterminator" /> </service> </services> </container>
2. Prepare your route
As already seen in the example above, a custom route attribute is accessed, here _my_context
. You should define it in
your route configuration:
<?xml version="1.0" encoding="UTF-8" ?> <routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing https://symfony.com/schema/routing/routing-1.0.xsd"> <route id="my_route" controller="My\Bundle\Action\ApiAction" path="/my/api/{pageId}" > <default key="_my_context">page</default> <default key="_scope">frontend</default> <requirement key="pageId">\d+</requirement> </route> </routes>
3. Accessing the page object
That's it. If you try to access $GLOBALS['objPage']
you should have the page object. Good news, you can avoid
accessing the global state. Your current Request have a new attribute, called _page_context
.
<?php declare(strict_types=1); namespace My\Bundle\Action; use Netzmacht\Contao\PageContext\Request\PageContext; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; final class ApiAction { public function __invoke(Request $request): Response { /** @var PageContext $context */ $context = $request->attributes->get('_page_context'); return new JsonResponse( [ 'pageId' => $context->page()->id, 'rootId' => $context->rootPage()->id, ] ); } }