Elimina la vista dello store a livello di codice nello script di aggiornamento


12

Voglio eliminare una vista del negozio a livello di codice . Guardando Mage_Adminhtml_System_StoreController::deleteStorePostAction(), questo è abbastanza facile (codice abbreviato un po '):

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

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

Voglio inserire questo codice in uno script di aggiornamento dei dati in modo che l'eliminazione venga eseguita automaticamente.

Il problema è che durante l'esecuzione degli script di aggiornamento in data/Magento chiama solo osservatori di eventi configurati globalnell'area (vedi Aggiornamenti struttura Magento vs. Aggiornamenti dati ). Alcuni osservatori come enterprise_cmse enterprise_searchper l'evento store_delete_aftersono definiti adminhtmlnell'area in modo che non vengano eseguiti. La cancellazione della vista negozio non verrà gestita come una cancellazione eseguita nel back-end.

Come gestite operazioni come questa? Carica tu stesso aree di eventi aggiuntive negli script di aggiornamento (ne ho paura)? Non apportare modifiche di questo tipo nello script di aggiornamento ma metti i tuoi script magici in un luogo sacro nascosto ed eseguili manualmente?


1
Perché è necessario eliminare la vista negozio in modo problematico?
oleksii.svarychevskyi,

Perché abbiamo diversi ambienti ed è più rapido e affidabile eseguire tutte le modifiche alla configurazione a livello di codice.
Matthias Zeis,

Hai mai trovato una soluzione per questo? Quanto spesso lo faresti? Personalmente, sceglierei la seconda opzione "Non apportare modifiche di questo tipo nello script di aggiornamento ma mettere i tuoi script magici in un luogo sacro nascosto ed eseguirli manualmente?"
ProxiBlue,

Ho rinviato questo problema perché c'erano cose più importanti da fare. Lo stesso @philwinkle di Magento SE ha risposto su Twitter: "Faccio questi in coda; o ascolto e lancio un evento di invio in tandem adminhtml (noto anche come falso)" ( twitter.com/philwinkle/status/428183845985210369 ). Credo che questo sia troppo rischioso per me e anche se non amo questo approccio lo farò manualmente.
Matthias Zeis,

@MatthiasZeis puoi aggiungerlo come risposta e accettarlo per mantenere il conto alla rovescia delle domande senza risposta?
Sander Mangel

Risposte:


6

Così poco dopo aver twittato questo a Matthias sono andato in silenzio radio. Spero che tu abbia sentito la suspense mentre aspettavi questa risposta per un paio di settimane.

Quello che intendo con "Faccio questi in una coda" è una risposta diretta a:

Alcuni osservatori come enterprise_cms e enterprise_search per l'evento store_delete_after sono definiti nell'area adminhtml in modo da non essere eseguiti. La cancellazione della vista negozio non verrà gestita come una cancellazione eseguita nel back-end.

Metodo di coda:

Quando so che ci sono alcuni eventi che non si attivano nel contesto corretto (principalmente per EE, ma possono applicarsi in altri contesti) in genere spingo la cancellazione su una coda in modo che venga eseguita nel contesto che deve .

In altre parole, creare una tabella delle code (o coda / argomento in RabbitMQ, ecc.) Che contenga i dettagli della transazione e gli hook dell'evento che dovrebbe essere in ascolto. Questo può essere elegante o semplicistico come lo desideri. Ecco una base

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

E poi lavora la coda più tardi in un CRON, dove ora hai il controllo su quale negozio è "in esecuzione" (ovvero lo stai semplicemente eseguendo come se fosse l'amministratore, archivio 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));
        }
    }
}

Ovviamente se ti stavi immaginando, finisci in un tentativo / cattura e termina in una transazione. Penso che tu abbia capito.

Questo è fattibilmente l'unico modo per controllare il contesto in cui si verifica l'evento.

Metodo dell'evento tandem:

Puoi attivare manualmente il metodo "adminhtml" - Alan dà una spiegazione abbastanza decente di cosa faresti per influenzarlo , ma essenzialmente è lo stesso di questo:

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

La versione admin del salvataggio del cliente chiama il normale salvataggio del modello e in seguito invia l'evento adminhtml. Se lo desideri, potresti fare il contrario di questo in un osservatore.


5

Dannazione, mi amo un po 'di raggrinzimento, ma non sono d'accordo con la complessità / fragilità del trasporto dei parametri dell'attività e dell'area ( adminhtml | crontab | frontend | global | install ) in una coda, specialmente se quella coda verrà eseguita un contesto Magento. Se ci sono contesti misti che devono essere gestiti, la soluzione in coda è una reimplementazione dell'attuale "problema"!

Penso che l'approccio in coda sia fragile. La mia tesi è che il caricamento prematuro delle aree degli eventi non è affatto un problema. Per spiegare questo, facciamo un backup e guardiamo al problema:

Qual è il pericolo di caricare prematuramente un'area eventi in un ambito di esecuzione?

Per capirlo dobbiamo esaminare le aree degli eventi nel contesto dell'esecuzione. Matthias, immagino che tu lo sappia già, ma per l'edificazione degli altri:

Gli script di impostazione dei dati vengono eseguiti Mage_Core_Model_App::run()prima dell'invio della richiesta al Front Controller:

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

Quando gli script di impostazione dei dati vengono eseguiti, l' area degli eventi globali viene caricata. Le aree degli eventi contestuali di routing ( frontend o adminhtml ) vengono caricate in seguito in Mage_Core_Controller_Varien_Action::preDispatch()seguito alla corrispondenza del router con un'azione del controller (il areanome viene impostato tramite ereditarietà):

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

Quindi normalmente durante l'inizializzazione dell'app verranno eseguiti solo gli osservatori configurati nell'area degli eventi globali . Se lo script di installazione fa qualcosa del genere

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

quindi ci sono solo due pericoli:

  1. Un osservatore è stato configurato in modo errato in adminhtml per osservare un evento senza contesto come controller_front_init_beforeocontroller_front_init_routers
  2. La richiesta è una richiesta frontend .

Il numero 1 dovrebbe essere facile da sostenere. # 2 è la vera preoccupazione, e penso che Reflection possa risolvere il problema (nota che sono terribilmente inesperto nell'uso di reflection):

<?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()

Non l'ho provato, ma rimuove l'indice degli eventi adminhtml e l' Mage_Core_Model_App_Areaoggetto corrispondente .


1
Io non sono degno!! Io non sono degno!!!!
Filwinkle,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.