Правильный способ обновить родителя темы в Magento 2

14

В Magento 2 вы можете указать родительскую тему в theme.xmlфайле темы .

<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>

Когда Magento видит тему в первый раз, она использует это значение для установки parent_idв themeтаблице. Это источник правды о том, где находится родитель темы.

Однако если вы попытаетесь изменить это значение после добавления темы в систему , Magento не удастся обновить parent_idстолбец, и у созданных Magento\Theme\Model\Themeобъектов все равно будет исходная родительская тема. (Даже если вы очистите кеш.)

Я могу исправить это, вручную изменив parent_idзначение - это похоже на взлом. Где parent_idобычно установлен основной код Magento, и какие действия пользователя вызывают это? т.е. есть ли способ сказать Magento "пожалуйста, перезагрузите эту тему"

Алан Сторм
источник
2
Да, я тоже это заметил, и единственный способ изменить это после регистрации темы - это напрямую изменить базу данных. Возможно, ошибка?
Гарет Дейн

Ответы:

2

ОБНОВЛЕНО В 20160310

Вывод

Он всегда устанавливается через updateTheme()или из коллекции (через БД), если вашappState->getMode() == AppState::MODE_PRODUCTION

Ответ

Чтобы ответить на вопрос, как заставить Magento перезагрузить файл theme.xml, ответ:

Установите состояние приложения на developerиспользование SetEnv MAGE_MODE developerin .htaccess(или эквивалент nginx), а затем войдите в административную область (или обновите любой маршрут администратора) для запуска Magento\Theme\Model\Theme\Plugin\Registration::beforeDispatch().

Таблица тем в базе данных обновляется в связи с

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

Смотрите анализ ниже для деталей.

Анализ

Ух ты, код Magento 2 кажется мне действительно сложным. Вы изучили эту функцию, beforeDispatch()которая вызывает, updateThemeData()но толькоif ($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);
        }
    }

Возможно, вы прошли через этот код.

beforeDispatch()вызывается только через маршруты администратора, а не на интерфейсных маршрутах. Вот след:

#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))

На самом деле я вижу beforeDispatch()вызовы, updateThemeData()которые содержат этот самородок:

//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());
            }
//...

Который, кажется, на самом деле (наконец) ссылается на путь конфигурации XML, $themeData->getParentTheme()->getFullPath()но эта функция все еще использует $themeData->getParentTheme(). О, я думаю, что логика такова: « Если я обновляю зарегистрированную тему, у которой есть родительский идентификатор в коллекции (через БД), тогда найдите родительский путь в конфигурации и обновите коллекцию ».Так что, возможно, это оно и есть.

Иначе я в полной растерянности относительно того, как Magento\Theme\Model\Theme::getParentTheme()реализуется, getParentId()что объявлено в интерфейсе темы. Конечно, это не волшебство. Как вы говорите, он должен поступать либо из БД через коллекцию, либо из XML-пути конфигурации темы (если он изменился или еще не определен), но я не могу найти определение getParentId(). Может быть, это всегда устанавливается через updateTheme()ИЛИ из коллекции (через БД), так что плохо, если ваш appState->getMode() == AppState::MODE_PRODUCTION.

Я нашел полезным получить информацию изнутри updateThemeData(), добавив некоторые выходные данные журнала:

//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());
            }
//...

Который будет входить в /var/log/debug.log. При установленном для приложения состоянии developerя вижу, что родительский идентификатор всегда устанавливается при каждом обновлении страницы администратора независимо от того, был ли он изменен theme.xmlили нет. С состоянием приложения productionфункция никогда не запускается, поэтому я заключаю:

Он всегда устанавливается через updateTheme()ИЛИ из коллекции (через БД), так что плохо, если вашappState->getMode() == AppState::MODE_PRODUCTION

Я думаю, что вы, вероятно, все в developerсостоянии приложения. defaultСостояние приложения updateThemeData()тоже сработает, конечно. В дальнейшей отладке я записал полный путь темы для родительской темы Luma frontend/Magento/blank. Столица Mудивила меня, так что, может быть, на что-то стоит обратить внимание.

Малахия
источник
0

Вышеупомянутое, похоже, не работает для меня, поэтому я пошел с взломать.

Надеюсь, это поможет кому-то.

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)

если это не так, измените его.

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

then quit mysql;

 bin/magento setup:static-content:deploy 

или

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

grunt exec:[theme]

grunt less:[theme]
wwsiv2
источник