Prawidłowy sposób aktualizacji rodzica motywu w Magento 2

14

W Magento 2 możesz określić motyw nadrzędny w motywie theme.xml pliku .

<theme xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Config/etc/theme.xsd">
    <title>Theme Title</title>
    <parent>Package/base-theme</parent>
    <media>
        <preview_image>media/preview.jpg</preview_image>
    </media>
</theme>

Gdy Magento po raz pierwszy widzi motyw, używa tej wartości do ustawienia parent_id w themetabeli. To jest źródło prawdy dla tego, gdzie jest rodzic tematu.

Jeśli jednak spróbujesz zmienić tę wartość po dodaniu kompozycji do systemu , Magento nie zaktualizuje parent_idkolumny, a Magento\Theme\Model\Themeobiekty utworzone w postaci instancji nadal będą miały oryginalny motyw nadrzędny. (Nawet jeśli wyczyścisz pamięć podręczną).

Mogę to naprawić, ręcznie zmieniając parent_idwartość - to wygląda na włamanie. Gdzie parent_idzwykle jest ustawiony w głównym kodzie Magento i jakie działania użytkownika to powodują? tzn. czy istnieje sposób, aby powiedzieć Magento „ponownie załaduj ten motyw”

Alan Storm
źródło
2
Tak, też to zauważyłem i jedynym sposobem, w jaki znalazłem to zmodyfikować po zarejestrowaniu kompozycji, jest bezpośrednia modyfikacja bazy danych. Być może błąd?
Gareth Daine

Odpowiedzi:

2

ZAKTUALIZOWANO W 20160310

Wniosek

Jest zawsze ustawiany za pośrednictwem updateTheme()lub z kolekcji (przez DB), jeśli maszappState->getMode() == AppState::MODE_PRODUCTION

Odpowiedź

Aby odpowiedzieć na pytanie Jaki jest sposób na to, aby Magento ponownie załadował plik theme.xml, odpowiedź brzmi:

Ustaw stan aplikacji na developerużycie SetEnv MAGE_MODE developerw .htaccess(lub odpowiednik nginx), a następnie zaloguj się do obszaru administratora (lub odśwież dowolną trasę administratora), aby uruchomićMagento\Theme\Model\Theme\Plugin\Registration::beforeDispatch() .

Tabela motywów w bazie danych została zaktualizowana z powodu

\\Magento\Theme\Model\Theme\Plugin\Registration::updateThemeData()
\\...
$themeData->setParentId($parentTheme->getId());`.
\\...

Zobacz szczegóły poniżej.

Analiza

Wow, kod Magento 2 wydaje mi się naprawdę skomplikowany. Czy studiowałeś tę funkcję, beforeDispatch()która wywołuje, updateThemeData()ale tylkoif ($this->appState->getMode() != AppState::MODE_PRODUCTION)

//namespace: namespace Magento\Theme\Model\Theme\Plugin;
//class: Registration
//file: app/code/Magento/Theme/Model/Theme/Plugin/Registration.php 

     /**
     * Add new theme from filesystem and update existing
     *
     * @param AbstractAction $subject
     * @param RequestInterface $request
     *
     * @return void
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function beforeDispatch(
        AbstractAction $subject,
        RequestInterface $request
    ) {
        try {
            if ($this->appState->getMode() != AppState::MODE_PRODUCTION) {
                $this->themeRegistration->register();
                $this->updateThemeData();
            }
        } catch (LocalizedException $e) {
            $this->logger->critical($e);
        }
    }

Prawdopodobnie przeszedłeś przez ten kod.

beforeDispatch()jest wywoływany tylko przez trasy administracyjne, a nie na trasach frontonu. Oto ślad:

#0 [internal function]: Magento\Theme\Model\Theme\Plugin\Registration->beforeDispatch(Object(Magento\Backend\Controller\Adminhtml\Dashboard\Index\Interceptor), Object(Magento\Framework\App\Request\Http))
#1 \magento2\lib\internal\Magento\Framework\Interception\Interceptor.php(122): call_user_func_array(Array, Array)
#2 \magento2\var\generation\Magento\Backend\Controller\Adminhtml\Dashboard\Index\Interceptor.php(39): Magento\Backend\Controller\Adminhtml\Dashboard\Index\Interceptor->___callPlugins('dispatch', Array, Array)
#3 \magento2\lib\internal\Magento\Framework\App\FrontController.php(55): Magento\Backend\Controller\Adminhtml\Dashboard\Index\Interceptor->dispatch(Object(Magento\Framework\App\Request\Http))
#4 [internal function]: Magento\Framework\App\FrontController->dispatch(Object(Magento\Framework\App\Request\Http))
#5 \magento2\lib\internal\Magento\Framework\Interception\Interceptor.php(74): call_user_func_array(Array, Array)
#6 \magento2\lib\internal\Magento\Framework\Interception\Chain\Chain.php(70): Magento\Framework\App\FrontController\Interceptor->___callParent('dispatch', Array)
#7 \magento2\lib\internal\Magento\Framework\Interception\Interceptor.php(136): Magento\Framework\Interception\Chain\Chain->invokeNext('Magento\\Framewo...', 'dispatch', Object(Magento\Framework\App\FrontController\Interceptor), Array, 'install')
#8 \magento2\lib\internal\Magento\Framework\Module\Plugin\DbStatusValidator.php(69): Magento\Framework\App\FrontController\Interceptor->Magento\Framework\Interception\{closure}(Object(Magento\Framework\App\Request\Http))
#9 [internal function]: Magento\Framework\Module\Plugin\DbStatusValidator->aroundDispatch(Object(Magento\Framework\App\FrontController\Interceptor), Object(Closure), Object(Magento\Framework\App\Request\Http))
#10 \magento2\lib\internal\Magento\Framework\Interception\Interceptor.php(141): call_user_func_array(Array, Array)
#11 \magento2\var\generation\Magento\Framework\App\FrontController\Interceptor.php(26): Magento\Framework\App\FrontController\Interceptor->___callPlugins('dispatch', Array, Array)
#12 \magento2\lib\internal\Magento\Framework\App\Http.php(115): Magento\Framework\App\FrontController\Interceptor->dispatch(Object(Magento\Framework\App\Request\Http))
#13 \magento2\lib\internal\Magento\Framework\App\Bootstrap.php(258): Magento\Framework\App\Http->launch()
#14 \magento2\index.php(39): Magento\Framework\App\Bootstrap->run(Object(Magento\Framework\App\Http))

Właściwie widzę beforeDispatch()połączenia, updateThemeData()które zawierają ten samorodek:

//namespace: namespace Magento\Theme\Model\Theme\Plugin;
//class: Registration
//file: app/code/Magento/Theme/Model/Theme/Plugin/Registration.php 
//function: updateThemeData()

//...
            if ($themeData->getParentTheme()) {
                $parentTheme = $this->themeLoader->getThemeByFullPath(
                    $themeData->getParentTheme()->getFullPath()
                );
                $themeData->setParentId($parentTheme->getId());
            }
//...

Co wydaje się faktycznie (w końcu) odwoływać się do ścieżki XML konfiguracji, $themeData->getParentTheme()->getFullPath()ale ta funkcja nadal używa $themeData->getParentTheme(). Och, myślę, że logika brzmi: „ Jeśli aktualizuję zarejestrowany motyw, który ma ParentId w kolekcji (poprzez DB), to poszukaj ścieżki nadrzędnej w konfiguracji i zaktualizuj kolekcję ”.Więc może to jest to.

W przeciwnym razie mam całkowitą utratę tego, jak Magento\Theme\Model\Theme::getParentTheme()implementuje getParentId()deklarowane w interfejsie kompozycji. Na pewno to nie jest magia. Jak mówisz, musi pochodzić albo z DB poprzez kolekcję, albo ze ścieżki XML konfiguracji motywu (jeśli się zmieniło lub nie zostało jeszcze zdefiniowane), ale nie mogę znaleźć definicji getParentId(). Może zawsze jest ustawiony przez updateTheme()OR z kolekcji (przez DB), więc szkoda, jeśli masz appState->getMode() == AppState::MODE_PRODUCTION.

Za przydatne uznałem zbieranie informacji od wewnątrz updateThemeData()poprzez dodanie danych wyjściowych dziennika:

//namespace: namespace Magento\Theme\Model\Theme\Plugin;
//class: Registration
//file: app/code/Magento/Theme/Model/Theme/Plugin/Registration.php 
//function: updateThemeData()

//...
            if ($themeData->getParentTheme()) {
                $parentTheme = $this->themeLoader->getThemeByFullPath(
                    $themeData->getParentTheme()->getFullPath()
                );
            $this->logger->addDebug("Theme parent full path ".$themeData->getParentTheme()->getFullPath());
            $this->logger->addDebug("Theme parent new ID ".$parentTheme->getId());                    $themeData->setParentId($parentTheme->getId());
            }
//...

Który zaloguje się do /var/log/debug.log. Po ustawieniu stanu aplikacji na developerWidzę, że identyfikator nadrzędny jest zawsze ustawiony na każdym odświeżeniu strony administratora, niezależnie od tego, czy został zmieniony theme.xmlczy nie. Ze stanem aplikacji productionfunkcja nigdy nie jest uruchamiana, więc wnioskuję:

Zawsze jest ustawiane przez updateTheme()OR z kolekcji (przez DB), więc szkoda, jeśli takappState->getMode() == AppState::MODE_PRODUCTION

Myślę, że prawdopodobnie wszyscy jesteście w developerstanie aplikacji. Oczywiście defaultstan aplikacji również się uruchomi updateThemeData(). Podczas dalszego debugowania zapisałem pełną ścieżkę motywu dla motywu nadrzędnego Luma, który był frontend/Magento/blank. Stolica Mmnie zaskoczyła, więc może warto na nią uważać.

Malachy
źródło
0

Powyższe wydaje się nie działać dla mnie, więc poszedłem z hakiem.

Mam nadzieję, że to komuś pomoże.

using the command line

 mysql

 SHOW databases;

 use magento; (or whatever your DB's name is)

 SHOW tables

 SELECT * FROM theme; 

(Check the **parent_id** of theme in question, it should be the same number as **theme_id** of theme you want as the parent)

jeśli nie jest, zmień to.

 UPDATE theme SET parent_id  = '[value]' WHERE theme_title = '[Theme name]';

then quit mysql;

 bin/magento setup:static-content:deploy 

lub

grunt clean:[theme] (For example:  grunt clean:blank)

grunt exec:[theme]

grunt less:[theme]
wwsiv2
źródło