Warum muss das Hinzufügen von Konstruktorparametern gelöscht / generiert werden?

7

Ich verwende Magento 2.2 im Entwicklungsmodus.

Ich habe eine Controller-Klasse

class MyController
{
   public function __construct(
      \Magento\Framework\App\Action\Context $context,
      \Magento\Framework\Message\ManagerInterface $messageManager)
   {
      // stuff
   }
}

Das funktioniert richtig. Wenn ich jedoch einen zusätzlichen Konstruktorparameter wie diesen hinzufüge:

class MyController
{
   public function __construct(
      \Magento\Framework\App\Action\Context $context,
      \Magento\Framework\View\Result\PageFactory $resultPageFactory,
      \Magento\Framework\Message\ManagerInterface $messageManager)
   {
      // stuff
   }
}

Ich bekomme den Fehler

PHP Fatal error: Uncaught TypeError: Argument 2 passed to
Ben\Testing\Controller\Test::__construct() must be an instance of 
Magento\Framework\View\Result\PageFactory, instance of 
Magento\Framework\Message\ManagerInterface given, called in 
/magento-dev/magento2/generated/code/Ben/Testing/Controller/Test/Interceptor.php
on line 7 and defined in /magento-dev/magento2/app/code/Ben/Testing/Controller/Test.php:7
...

Wenn ich den /generatedOrdner lösche und die Seite aktualisiere, funktioniert es.

Meine Frage ist, wie Magento mit Caching und generiertem Code umgeht. Ich kann Nicht-Konstruktor-Funktionen zusätzlichen Code hinzufügen, ohne sie löschen zu müssen /generated, und es funktioniert. Warum funktioniert das, aber wenn ich zusätzliche Konstruktorparameter hinzufüge, muss ich den /generatedOrdner löschen ?

Ben Rubin
quelle

Antworten:

7

Kurze Antwort: Weil Magento nicht die Klasse verwendet, von der Sie glauben, dass sie verwendet wird.
Lange Antwort:
Es liegt an Plugins / Interceptors.
Für jede Klasse mit Methoden, die Plugins enthalten, generiert Magento eine Klasse mit demselben Namen wie die ursprüngliche Klasse und fügt sie \Interceptoram Ende hinzu.
Sie können das in Ihrer Fehlermeldung sehen.
Diese Interceptors erweitern die ursprünglichen Klassen

use \Magento\Framework\Interception\Interceptor;

public function __construct(list of main  class parameters in here)
{
    $this->___init();
    parent::__construct(list of main class parameters in here); //THIS LINE IS IMPORTANT FOR YOUR PROBLEM.  
}

/**
 * {@inheritdoc}
 * This is added for every interceptable method in the main class and it's named exactly like the method
 */
public function interceptableMethod(parameters of interceptable method)
{
    $pluginInfo = $this->pluginList->getNext($this->subjectType, 'interceptableMethod');
    if (!$pluginInfo) {
        return parent::interceptableMethod(parameters of interceptable method);
    } else {
        return $this->___callPlugins('interceptableMethod', func_get_args(), $pluginInfo);
    }
}

Die zweite zu berücksichtigende Sache ist, dass eine solche Interceptor-Klasse nur generiert wird, wenn sie noch nicht existiert.

Wenn Sie also die Konstruktorsignatur Ihrer Klasse ändern und die Interceptor-Klasse generiert wird, geschieht dies.

Ihr neuer Klassenkonstruktor benötigt 3 Parameter.
Der generierte Interceptor hat noch den alten Konstruktor mit 2 Parametern.
Dies ist kein Problem für die Interceptor-Klasse selbst, da sie mit zwei Abhängigkeiten instanziiert wird.
Aber dann ruft es parent::__construct(die Zeile, die ich im obigen Beispiel markiert habe) mit denselben 2 Parametern auf. und parentist Ihre eigene Klasse, die jetzt 3 Parameter benötigt.
Dies wird also einen Fehler auslösen. Wenn Sie
die Interceptor-Klasse aus dem generatedOrdner entfernen, wird sie von Magento beim nächsten Aufruf neu generiert. Dieses Mal verfügt sie über die richtige Konstruktorsignatur.

Marius
quelle
Tolle Erklärung. Danke für deine Hilfe.
Ben Rubin