Програмно видалити перегляд магазину в сценарії оновлення


12

Я хочу видалити подання магазину програмно . Дивлячись Mage_Adminhtml_System_StoreController::deleteStorePostAction(), це досить просто (трохи скорочений код):

$model = Mage::getModel('core/store')->load($id);

if ($model->getId() && $model->isCanDelete()) {
    $model->delete();
    Mage::dispatchEvent('store_delete', array('store' => $model));
}

Я хочу помістити цей код у скрипт оновлення даних, щоб видалення виконувалось автоматично.

Проблема полягає в тому, що під час виконання скриптів оновлення в data/Magento викликає лише спостерігачів подій, налаштованих у цій globalобласті (див. Оновлення структури Magento проти оновлень даних ). Деякі спостерігачі на зразок enterprise_cmsта enterprise_searchподії store_delete_afterвизначені в цій adminhtmlмісцевості, тому вони не будуть страчені. Видалення з представлення магазину не буде оброблятися, як видалення, виконане в бекенде.

Як ви впораєтесь з такими операціями? Завантажте додаткові області подій у сценарії оновлення (я боюся цього)? Чи не робіть подібних модифікацій даних у скрипті оновлення, але покладіть свої магічні скрипти у священне приховане місце та виконайте його вручну?


1
Чому потрібно видалити вигляд магазину проблематично?
oleksii.svarychevskyi

Оскільки у нас є кілька середовищ, і все зміни конфігурації робити швидше і надійніше програматично.
Маттіас Зейс

Ви коли-небудь знайшли рішення для цього? Як часто ви робили це? Особисто я хотів би скористатися другим варіантом: "Не робіть подібних модифікацій даних у скрипті оновлення, але поставте свої магічні скрипти в священне приховане місце та виконайте це вручну?"
ProxiBlue

Я відклав це питання, тому що було важливіше робити. Власне Magento SE @philwinkle відповів у Twitter: "Я це роблю в черзі; або слухаю та запускаю диспетчерську подію адміністратора тандему (він же фальшивий)" ( twitter.com/philwinkle/status/428183845985210369 ). Я вважаю, що це занадто ризиково для мене, і хоча мені не подобається такий підхід, я це зроблю вручну.
Маттіас Зейс

@MatthiasZeis Ви можете додати, що як відповідь і прийміть її, щоб не враховувати відповіді на запитання?
Сандер Мангел

Відповіді:


6

Тому незабаром після того, як я написав це Маттіасу, я продовжив радіо тишу. Я сподіваюся, що ви відчули напруженість, коли ви чекали цієї відповіді пару тижнів.

Що я маю на увазі під "Я роблю це в черзі" - це пряма відповідь на:

Деякі спостерігачі, такі як Enterprise_cms та enterprise_search для події store_delete_after, визначені в області адміністратора, тому вони не будуть виконані. Видалення з представлення магазину не буде оброблятися, як видалення, виконане в бекенде.

Метод черги:

Коли я знаю, що є певні події, які не спрацюють у правильному контексті (в основному для ЕЕ, але можуть застосовуватись і в інших контекстах), я зазвичай висуваю видалення в чергу, щоб воно запускалося в контексті, який йому потрібно .

Іншими словами, створіть таблицю черги (або чергу / тему в RabbitMQ тощо), яка б містила деталі транзакції та гачки подій, які її слід слухати. Це може бути настільки елегантно або настільки просто, як ви хочете. Ось основна

$queue = Mage::getModel('yourcompany/queue_job')
         ->setJobType('delete')
         ->setEntityType('core/store')
         ->setEntityId(12)
         ->setDispatchEvent('store_delete')
         ->setDispatchEventDataKey('store')
         ->save();

А потім працюйте чергою пізніше в CRON, де ви тепер маєте контроль над тим, який магазин "працює" (він же просто запущений, як ніби адміністратор, зберігайте 0):

foreach(Mage::getModel('yourcompany/queue_job')->getCollection() as $job){
    if($job->getJobType()=='delete'){

        $model = Mage::getModel($this->getEntityType())->load($this->getEntityId());

        if ($model->getId() && $model->isCanDelete()) {
            $model->delete();
            Mage::dispatchEvent($job->getDispatchEvent(), array($job->setDispatchEventDataKey() => $model));
        }
    }
}

Очевидно, якщо тобі було цікаво, ти завершуєш спробу / ловити та завершуєш транзакцію. Я думаю, ви отримаєте суть.

Це, можливо, єдиний спосіб контролювати контекст, у якому відбувається подія.

Метод подій у тандемі:

Ви можете запустити метод "adminhtml" самостійно вручну - Алан дає досить пристойне пояснення того, що ви зробили, щоб вплинути на це , але по суті це те саме, що це:

#File: app/code/core/Mage/Adminhtml/controllers/CustomerController.php
public function saveAction()
{
    //...
    $customer->save();
    //...
    Mage::dispatchEvent('adminhtml_customer_prepare_save', array(
        'customer'  => $customer,
        'request'   => $this->getRequest()
    ));        
    //..
}

Адміністраторська версія збереження клієнта викликає звичайну модель збереження і після цього відправляє події адміністратора. Ви могли зробити це зворотним шляхом у спостерігача самостійно, якщо цього хочете.


5

Чорт, я люблю мене, колись фільльвінкл, але я повинен не погоджуватися зі складністю / крихкістю транспортування параметрів завдання та області ( adminhtml | crontab | frontend | глобальний | встановити ) до черги, особливо якщо цю чергу буде виконуватися контекст Магенто. Якщо є змішані контексти, які потребують обробки, то рішення черги - це повторне реалізація поточної "проблеми"!

Я думаю, що підхід у черзі крихкий. Мій аргумент полягає в тому, що передчасне завантаження областей подій насправді взагалі не є проблемою. Щоб пояснити це, давайте створимо резервну копію та розглянемо проблему:

Яка небезпека передчасно завантажити область події у межах виконання?

Щоб зрозуміти це, ми повинні вивчити області подій у контексті виконання. Маттіас, я думаю, що ти це вже знаєш, але для повчання інших:

Сценарії налаштування даних виконуються Mage_Core_Model_App::run()перед відправленням запиту на передній контролер:

public function run($params)
{
    $options = isset($params['options']) ? $params['options'] : array();
    $this->baseInit($options);
    Mage::register('application_params', $params);

    if ($this->_cache->processRequest()) {
        $this->getResponse()->sendResponse();
    } else {
        $this->_initModules();
//Global event area is loaded here
        $this->loadAreaPart(Mage_Core_Model_App_Area::AREA_GLOBAL, Mage_Core_Model_App_Area::PART_EVENTS);

        if ($this->_config->isLocalConfigLoaded()) {
            $scopeCode = isset($params['scope_code']) ? $params['scope_code'] : '';
            $scopeType = isset($params['scope_type']) ? $params['scope_type'] : 'store';
            $this->_initCurrentStore($scopeCode, $scopeType);
            $this->_initRequest();
//Data setup scripts are executed here: 
            Mage_Core_Model_Resource_Setup::applyAllDataUpdates();
        }

        $this->getFrontController()->dispatch();
    }
    return $this;
}

На момент встановлення сценаріїв встановлення даних завантажується область глобальної події. Піктограми контекстних подій маршрутизації ( frontend або adminhtml ) пізніше завантажуються Mage_Core_Controller_Varien_Action::preDispatch()в результаті маршрутизатора, що відповідає дії контролера ( areaім'я встановлюється через успадкування):

public function preDispatch()
{
    //...
    Mage::app()->loadArea($this->getLayout()->getArea());
    //...
}

Тому зазвичай під час ініціалізації додатків будуть виконуватися лише спостерігачі, налаштовані під глобальну область подій. Якщо сценарій налаштування робить щось таке, як

$this->loadAreaPart(Mage_Core_Model_App_Area::AREA_ADMINHTML, Mage_Core_Model_App_Area::PART_EVENTS);

то є лише дві небезпеки:

  1. Спостерігач був неправильно налаштований під адміністратором admin, щоб спостерігати події без контексту, такі як controller_front_init_beforeабоcontroller_front_init_routers
  2. Запит - це запит на передній план .

№1 має бути легко схопитися. # 2 викликає справжнє занепокоєння, і я вважаю, що Рефлексія може вирішити проблему (зауважте, що я дуже недосвідчений у використанні рефлексії):

<?php

//Start setup script as normal
$installer = $this;
$installer->startSetup()

//Load adminhtml event area
Mage::app()->loadAreaPart(
    Mage_Core_Model_App_Area::AREA_ADMINHTML,
    Mage_Core_Model_App_Area::PART_EVENTS
);

// your setup script logic here

//I hope this isn't a bad idea.
$reflectedApp = new ReflectionClass('Mage_Core_Model_App');
$_areas = $reflectedApp->getProperty('_areas');
$_areas->setAccessible(true);
$areas = $_areas->getValue(Mage::app());
unset($areas['adminhtml']);
$_areas->setValue(Mage::app(),$areas); //reset areas

//End setup script as normal
$installer->endSetup()

Я цього не перевіряв, але він видаляє індекс події adminhtml та відповідний Mage_Core_Model_App_Areaоб'єкт.


1
Я не гідний !! Я не гідний !!!!
philwinkle
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.