Ergebnis 1 bis 16 von 16

Thema: Korrekte $GLOBALS Variablen in Page Controller holen

  1. #1
    Contao-Nutzer
    Registriert seit
    17.11.2016.
    Beiträge
    25

    Frage Korrekte $GLOBALS Variablen in Page Controller holen

    Guten Abend zusammen,

    ich habe einen eigenen Page Controller nach dem Beispiel in der Developer Dokumentation per Attribute #[AsPage] erstellt (https://docs.contao.org/dev/framework/page-controllers/). Das funktioniert soweit auch ganz gut, allerdings bekomme ich bei einem Dump der $GLOBALS die falschen Variablen angezeigt. Beispielsweise steht in TL_LANGUAGE der Wert "en" statt der in der Website-Startseite angegebenen Sprache "de". Viel schlimmer ist allerdings, dass im Array TL_LANG nur CTE enthalten ist und alle anderen Übersetzungen gänzlich fehlen.

    Gibt es eine Möglichkeit, die korrekten Daten in einem registrierten Page Controller nachzuladen? Im Core, beispielsweise bei /core-bundle/contao/pages/PageRegular.php, scheint das in der Funktion getResponse() per $this->prepare($objPage); zu erfolgen. Die steht mir im PageController aber leider nicht zur Verfügung.

    Hat jemand eine Idee, wie man das lösen kann?

    Danke und Gruß
    Tim

  2. #2
    Contao-Fan
    Registriert seit
    24.02.2021.
    Beiträge
    455

    Standard

    Poste deinen Code (Das würde Spooky sagen ) - Hilft schon ungemein, sodass man hier auch genau sieht + selber testen kann

  3. #3
    Contao-Nutzer
    Registriert seit
    17.11.2016.
    Beiträge
    25

    Standard

    Da hast du recht, ich hatte nur darauf verzichtet, weil ich es ja genau wie im Beispiel umgesetzt habe. Ich poste den Code aber gerne noch mal. :-)

    Erst den Page Controller in vendor/example/contao-example-bundle/src/Controller/Page/ExamplePageController.php angelegt (lediglich mit eingefügtem dump($GLOBALS)):

    Code:
    namespace Example\ContaoExampleBundle\Controller\Page;
    
    use Contao\CoreBundle\DependencyInjection\Attribute\AsPage;
    use Symfony\Component\HttpFoundation\Response;
    
    #[AsPage]
    class ExamplePageController
    {
        public function __invoke(): Response
        {
            dump($GLOBALS);
    
            return new Response('Hello World!');
        }
    }
    Anschließend diese Zeile in vendor/example/contao-example-bundle/contao/dca/tl_page.php:

    Code:
    $GLOBALS['TL_DCA']['tl_page']['palettes']['example'] = '{title_legend},title,alias,type;{publish_legend},published,start,stop';
    Und außerdem noch in vendor/example/contao-example-bundle/contao/languages/de/default.php:

    Code:
    $GLOBALS['TL_LANG']['PTY']['example'] = ['Example', 'Example page type.'];
    Zum Schluss den Cache leeren und eine neue Seite mit dem Example-Seitentyp erstellen.

    Ich habe es auch schon mit AbstractController und ContentCompositionInterface versucht, weil so auch das Seitenlayout mit ausgegeben wird.
    Dazu den ExamplePageController entsprechend ändern:

    Code:
    namespace Example\ContaoExampleBundle\Controller\Page;
    
    use Contao\CoreBundle\Controller\AbstractController;
    use Contao\CoreBundle\DependencyInjection\Attribute\AsPage;
    use Contao\CoreBundle\Framework\ContaoFramework;
    use Contao\CoreBundle\Routing\Page\ContentCompositionInterface;
    use Contao\FrontendIndex;
    use Contao\PageModel;
    use Symfony\Component\HttpFoundation\Response;
    
    #[AsPage]
    class ExamplePageController extends AbstractController implements ContentCompositionInterface
    {
    	public function __construct(private readonly ContaoFramework $framework)
    	{
    	}
    
    	public function __invoke(PageModel $pageModel): Response
    	{
    		$this->framework->initialize();
    
    		dump($GLOBALS);
    
    		return $this->framework
    			->createInstance(FrontendIndex::class)
    			->renderPage($pageModel)
    		;
    	}
    
    	public function supportsContentComposition(PageModel $pageModel): bool
    	{
    		return true;
    	}
    }
    In vendor/example/contao-example-bundle/config/services.yaml (die im Bundle dann natürlich entsprechend geladen werden muss):

    Code:
    services:
        Example\ContaoExampleBundle\Controller\Page\ExamplePageController:
            arguments:
                - '@contao.framework'
    Aber auch hier sind die Variablen in der $GLOBALS leider nicht korrekt. Um Fehler auszuschließen, habe ich mittlerweile alle anderen Erweiterungen deinstalliert. Dabei ist mir aufgefallen, dass TL_LANG nun gänzlich fehlt.

    Außerdem gibt es ein seltsames Phänomen: Wenn ich in der Konsole den Cache per "contao-console cache:clear --env=prod" anfange zu leeren, was rund 20 Sekunden dauert, sind in dieser Zeit in der $GLOBALS sowohl TL_LANG (in englisch) als auch TL_DCA (mit "tl_page", "tl_article" und "tl_content") enthalten. Sobald der Vorgang abgeschlossen ist, fehlen diese beiden wieder.

  4. #4
    Wandelndes Contao-Lexikon Avatar von BugBuster
    Registriert seit
    15.06.2009.
    Ort
    Berlin
    Beiträge
    10.513
    User beschenken
    Wunschliste

    Standard

    Aus meinen Notizen, die stammen noch getestet aus Contao 5.2 Zeiten (AbstractController):
    PHP-Code:
            // de, wenn BE / FE Deutsch ist
            
    $lang $GLOBALS['TL_LANGUAGE'];

            
    // bringt 'en' zurück statt 'de', wenn BE / FE Deutsch ist.
            
    $lang $this->translator->getLocale(); 
    "translator" ist hier per DI "Symfony\Contracts\Translation\TranslatorInterface ".
    Grüße, BugBuster
    "view source" is your guide.
    Danke an alle Amazon Wunschlisten Erfüller

  5. #5
    Community-Moderator
    Wandelndes Contao-Lexikon
    Avatar von Spooky
    Registriert seit
    12.04.2012.
    Ort
    Scotland
    Beiträge
    34.109
    Partner-ID
    10107

    Standard

    PHP-Code:
    $request->getLocale() 
    » sponsor me via GitHub or PayPal or Revolut

  6. #6
    Contao-Nutzer
    Registriert seit
    17.11.2016.
    Beiträge
    25

    Standard

    Danke BugBuster und Spooky für eure Tipps. Damit kann ich mir zwar die korrekte Seitensprache holen, allerdings löst das nicht das Hauptproblem mit den fehlenden Daten in der $GLOBALS. Wieso
    sind TL_LANG und TL_DCA nur während des Löschens des Caches vorhanden und verschwinden anschließend beim nächsten Seitenaufruf wieder? Und warum ist dort "en" hinterlegt und nicht die in der Website-Startseite eingegebene Sprache. Das dort eingestellte Layout verwendet die Seite ja schließlich auch.

    Letztendlich würde es mir auch reichen, wenn ich irgendwie wieder die deutschen Sprach-Variablen in die $GLOBALS bekommen würde, weil ich die an einigen Stellen benötige (z. B. für die Paginierung).

  7. #7
    Community-Moderator
    Wandelndes Contao-Lexikon
    Avatar von Spooky
    Registriert seit
    12.04.2012.
    Ort
    Scotland
    Beiträge
    34.109
    Partner-ID
    10107

    Standard

    Dazu nutzt du Controller::loadDataContainer und System::loadLanguageFile. Letzteres brauchst du nicht wenn du den Translator nutzt.
    » sponsor me via GitHub or PayPal or Revolut

  8. #8
    Contao-Nutzer
    Registriert seit
    17.11.2016.
    Beiträge
    25

    Standard

    Dank eurer Tipps habe ich es jetzt so gelöst:

    Code:
    public function __invoke(Request $request): Response
    {
    	// 'en' mit der Sprache aus der Website-Startseite überschreiben
    	$GLOBALS['TL_LANGUAGE'] = $request->getLocale();
    	// Korrekte Sprache wieder zurückholen
    	System::loadLanguageFile('default');
    Nun funktioniert es zum Glück wieder, auch wenn ich denke, dass Contao bei Verwendung eines eigenen Page Controllers es eigentlich selbst lösen sollte.

    Nur noch eine letzte Frage: Die bereits angesprochene Paginierung wird jetzt fehlerfrei ausgegeben, allerdings mit dem Standard-Template und nicht mit dem überschriebenen pagination.html5 im meinem Template-Ordner. In anderen Modulen funktioniert es einwandfrei, daher kann es nicht am Template liegen.

    Wenn ich mir zusätzlich das PageModel hole, fehlen dort die letzten Variablen, die bei normalen Seiten enthalten sind:

    "hasJQuery" => true
    "hasMooTools" => false
    "layoutId" => 1
    "template" => "fe_page"
    "templateGroup" => "templates/example"
    "minifyMarkup" => true

    Ich habe versucht, sie einfach mal hinzuzufügen, aber das ändert nichts am Template. Zumal der Quelltext auch minified wird, obwohl die Variable nicht enthalten ist.

    Der neue Seitentyp verwendet korrekt das von der Hauptseite vererbte Template. Warum wird nur das Paginierungstemplate nicht überschrieben?

  9. #9
    Community-Moderator
    Wandelndes Contao-Lexikon
    Avatar von Spooky
    Registriert seit
    12.04.2012.
    Ort
    Scotland
    Beiträge
    34.109
    Partner-ID
    10107

    Standard

    Zitat Zitat von Silent-Bob Beitrag anzeigen
    Dank eurer Tipps habe ich es jetzt so gelöst:

    PHP-Code:
    // 'en' mit der Sprache aus der Website-Startseite überschreiben
    $GLOBALS['TL_LANGUAGE'] = $request->getLocale(); 
    Warum machst du das?
    » sponsor me via GitHub or PayPal or Revolut

  10. #10
    Contao-Nutzer
    Registriert seit
    17.11.2016.
    Beiträge
    25

    Standard

    Wenn ich das nicht tue, dann holt er mir zwar mit System::loadLanguageFile('default'); das fehlende Sprach-Array zurück, allerdings nur in englisch.

  11. #11
    Community-Moderator
    Wandelndes Contao-Lexikon
    Avatar von Spooky
    Registriert seit
    12.04.2012.
    Ort
    Scotland
    Beiträge
    34.109
    Partner-ID
    10107

    Standard

    Poste mal deinen gesamten Code um zu verstehen was du in deinem Controller überhaupt machst bzw. machen willst.
    » sponsor me via GitHub or PayPal or Revolut

  12. #12
    Contao-Nutzer
    Registriert seit
    17.11.2016.
    Beiträge
    25

    Standard

    Ich schreibe eine Erweiterung, die Kategorien, Produkte, Shops, Tags, etc. ausgeben soll. Dafür habe ich einen Page Controller und ein Frontend Modul geschrieben, wie du es in einem anderen Beitrag empfohlen hast. Die URLs sehen bspw. so aus:

    /seite/produkt
    /seite/kategorien
    /seite/kategorien/kategorie1
    /seite/kategorien/kategorie1/neuheiten
    /seite/shops
    /seite/shops/shop1
    /seite/tags
    /seite/tags/tag1

    Der Page Controller nimmt die URL und analysiert die einzelnen Fragmente. Die übergibt er dann an die entsprechenden Klassen, die die gewünschten Daten holen und als geparstes Template zurückgeben. Das übergibt der Page Controller als Variable an den Request und rendert die Seite.

    Das Frontend-Modul in der Seite holt sich schließlich diese Variable, packt die ins Module-Template und gibt den Response dann zurück.

    Alles zu posten, würde den Rahmen sprengen. Hier mal ein Ausschnitt aus meinem Page Controller:

    Code:
    namespace Example\ContaoExampleBundle\Controller\Page;
    
    use Contao\CoreBundle\DependencyInjection\Attribute\AsPage;
    use Contao\CoreBundle\Exception\PageNotFoundException;
    use Contao\Environment;
    use Contao\FrontendIndex;
    use Contao\ModuleModel;
    use Contao\PageModel;
    use Contao\System;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\HttpFoundation\Response;
    
    #[AsPage(type: 'example_page', path: '{slugs}', requirements: ['slugs' => '.+'], defaults: ['slugs' => ''])]
    class ExamplePageController
    {
    	public function __invoke(Request $request, PageModel $pageModel, string $slugs): Response
    	{
    		$GLOBALS['TL_LANGUAGE'] = $request->getLocale();
    		System::loadLanguageFile('default');
    
    		// Slugs in Array aufteilen
    		$arrSlugs = explode('/', $slugs);
    
    		// Einstellungen des Frontend Modules holen (dort sind Bildgrößen festgelegt, die Anzahl Produkte pro Seite, etc.)
    		$moduleModel = ModuleModel::findOneByType('examplepage');
    
    		// Wenn keine Slugs, dann die Suche ausgeben
    		if ($slugs === '')
    		{
    			$search = new SearchController();
    			$response = $search->search($pageModel, $moduleModel);
    		}
    		// Kategorien ausgeben
    		elseif (substr($arrSlugs[0], 0, 6) === 'categories')
    		{
    			// Einzelne Kategorie ausgeben
    			if (isset($arrSlugs[1]) && preg_match('/^[a-z0-9\-]+$/', $arrSlugs[1]) === 1)
    			{
    				$categories = new CategoriesController();
    				$response = $categories->category($pageModel, $moduleModel, $arrSlugs);
    			}
    			// Übersicht aller Kategorien ausgeben
    			else
    			{
    				$categories = new CategoriesController();
    				$response = $categories->categories($pageModel, $moduleModel, $arrSlugs);
    			}
    		}
    
    ...
    
    		$request->attributes->set('output', $response);
    
    		return (new FrontendIndex())->renderPage($pageModel);
    	}
    Und so sieht das Frontend Modul aus:

    Code:
    namespace Example\ContaoExampleBundle\Controller\FrontendModule;
    
    use Contao\CoreBundle\Controller\FrontendModule\AbstractFrontendModuleController;
    use Contao\CoreBundle\DependencyInjection\Attribute\AsFrontendModule;
    use Contao\ModuleModel;
    use Contao\PageModel;
    use Contao\Template;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\HttpFoundation\Response;
    
    #[AsFrontendModule(type:'examplepage', category:'example', template:'mod_examplepage')]
    class ExamplePageModuleController extends AbstractFrontendModuleController
    {
    	public function __invoke(Request $request, ModuleModel $model, string $section, array $classes = null, PageModel $page = null): Response
    	{
    		return parent::__invoke($request, $model, $section, $classes);
    	}
    
    	protected function getResponse(Template $template, ModuleModel $model, Request $request): Response
    	{
    		$output = $request->attributes->get('output');
    
    		$template->output = $output;
    
    		return $template->getResponse();
    	}
    }
    Das Ganze steckt noch mitten in der Entwicklung, daher gibt es noch etliches zu verbessern. Ich bin aber froh, dass es bis hierhin schon mal funktioniert.

  13. #13
    Community-Moderator
    Wandelndes Contao-Lexikon
    Avatar von Spooky
    Registriert seit
    12.04.2012.
    Ort
    Scotland
    Beiträge
    34.109
    Partner-ID
    10107

    Standard

    Grundsätzlich sollte dein PageController, wenn er contentComposition unterstützt, nur Daten aufbreiten und als Request Attribut speichern, damit die jeweiligen Module dann damit umgehen können. Du scheinst aber einen weiteren "CategoryController" zu nutzen. Was genau macht der?

    Rein von deinem Code den du gepostet hast scheinst du System::loadLanguageFile und Controller::loadDataContiner nicht wirklich zu benötigen.
    Geändert von Spooky (26.02.2024 um 13:01 Uhr)
    » sponsor me via GitHub or PayPal or Revolut

  14. #14
    Contao-Nutzer
    Registriert seit
    17.11.2016.
    Beiträge
    25

    Standard

    Ich habe die Klassen, die für das Holen der Daten zuständig sind, ebenfalls unter /src/Controller/Page abgelegt. Im Grunde handelt es sich dabei aber nur um normale Klassen, die die Funktionen zum Holen der Daten enthalten. Beim Aufruf von /seite/kategorien/kategorie1 wird bspw. geprüft, ob kategorie1 überhaupt existiert. Dann werden die Daten zur Kategorie und die enthaltenen Produkte (ggf. paginiert) geholt, u. a. der Seitentitel und die -beschreibung an $pageModel übergeben und alles ein eigenes Template eingefügt ($objTemplate = new FrontendTemplate($this->strTemplate)). Zurückgegeben wird das Ganze per return $objTemplate->parse();. Also nichts besonderes eigentlich.

    Controller::loadDataContiner habe ich bislang noch nicht gebraucht. Wenn ich aber System::loadLanguageFile('default'); weglassen, dann fehlen mir die Texte für die Pagination-Klasse.

  15. #15
    Community-Moderator
    Wandelndes Contao-Lexikon
    Avatar von Spooky
    Registriert seit
    12.04.2012.
    Ort
    Scotland
    Beiträge
    34.109
    Partner-ID
    10107

    Standard

    Zitat Zitat von Silent-Bob Beitrag anzeigen
    Ich habe die Klassen, die für das Holen der Daten zuständig sind, ebenfalls unter /src/Controller/Page abgelegt. Im Grunde handelt es sich dabei aber nur um normale Klassen, die die Funktionen zum Holen der Daten enthalten. Beim Aufruf von /seite/kategorien/kategorie1 wird bspw. geprüft, ob kategorie1 überhaupt existiert. Dann werden die Daten zur Kategorie und die enthaltenen Produkte (ggf. paginiert) geholt, u. a. der Seitentitel und die -beschreibung an $pageModel übergeben und alles ein eigenes Template eingefügt ($objTemplate = new FrontendTemplate($this->strTemplate)). Zurückgegeben wird das Ganze per return $objTemplate->parse();. Also nichts besonderes eigentlich.
    Das solltest du dann alles in deinem Modul machen, nicht direkt im PageController. Denn erst wenn du (new FrontenIndex())->renderPage() aufrufst, werden alle notwendigen Dinge zum Rendern von Modulen & Templates gesetzt.
    » sponsor me via GitHub or PayPal or Revolut

  16. #16
    Contao-Nutzer
    Registriert seit
    17.11.2016.
    Beiträge
    25

    Standard

    Super, vielen Dank für den Tipp! Jetzt funktioniert es auch, ohne die Sprache zu setzen.

    Der Page Controller übergibt jetzt nur noch die aktuelle URL per $request->attributes->set('slugs', $slugs);. Den Rest habe ich in den Frontend Controller kopiert.

Aktive Benutzer

Aktive Benutzer

Aktive Benutzer in diesem Thema: 3 (Registrierte Benutzer: 0, Gäste: 3)

Lesezeichen

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •