Le magasin actuel est 1 lors de l'exécution des scripts de mise à niveau

15

Une idée pourquoi Mage::app()->getStore()retourne la vue du magasin avec l'ID 1 lorsque dans les scripts de mise à niveau indépendamment de la vue du magasin dans laquelle j'exécute le script de mise à niveau (même administrateur)?
Je veux dire, je sais où est le code qui fait ça. Il Mage_Core_Model_App::getStore()y a ceci:

    if (!Mage::isInstalled() || $this->getUpdateMode()) {
        return $this->_getDefaultStore();
    }

et _getDefaultStoreressemble à ceci:

   if (empty($this->_store)) {
        $this->_store = Mage::getModel('core/store')
            ->setId(self::DISTRO_STORE_ID)
            ->setCode(self::DISTRO_STORE_CODE);
    }
    return $this->_store;

$this->_store est toujours vide lorsque vous atteignez la méthode ci-dessus.

J'obtiens le même résultat même si j'ajoute ceci en haut du script de mise à niveau:

Mage::app()->setCurrentStore(Mage::getModel('core/store')->load(Mage_Core_Model_App::ADMIN_STORE_ID));

Je suis curieux de savoir la logique métier d'avoir cette «fonctionnalité».

Marius
la source
Je pensais que les scripts de mise à niveau s'exécutent toujours dans la portée frontend. Souvent, je dis explicitement aux scripts de mise à niveau d'utiliser le magasin d'administration pour les lignes suivantes.
bukart
@bukart. J'ai essayé de dire explicitement au script de mise à niveau d'exécuter la vue du magasin d'administration, mais j'obtiens le même résultat. Voir mes 3 dernières lignes dans la question.
Marius
J'ai essayé de répondre à votre question ci
bukart

Réponses:

5

NB: n'oubliez pas que la portée du magasin d'administration n'est pas définie tant que la répartition n'a pas lieu et qu'un contrôleur d'extension ne Mage_Adminhtml_Controller_Actions'exécute (voir l' adminhtml_controller_action_predispatch_startévénement et l'observateur associé dans Mage_Adminhtml_Controller_Action::preDispatch()).

Je suis curieux de savoir la logique métier d'avoir cette «fonctionnalité».

Vous n'êtes pas le seul; Cela dit, nous ne le saurons peut-être jamais à moins que Moshe ou Dima ne veuillent discuter.

Les scripts d'installation s'exécutent tôt dans l'initialisation de l'application. La conception de ceci est probablement due pour que, au moment où le reste de la pile soit exécuté, les migrations et autres travaux nécessaires soient "effectués" - ce qui signifie que le système était prêt à être utilisé immédiatement même lorsqu'un module était en cours d'installation. ou mis à niveau. Je me demande si les architectes originaux ont d'abord pensé qu'il y aurait besoin d'un système plus initialisé. Je suppose que, alors qu'une grande partie du code suppose qu'une instance de magasin est disponible, la _getDefaultStore()logique garantit qu'il existe une instance de magasin.

Les paramètres complets sont disponibles dans 1.4.0.0 et versions ultérieures via des scripts de configuration des données.

Benmarks
la source
3

Ok, pour utiliser le magasin d'administration dans vos scripts de mise à niveau, utilisez simplement

Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);

Votre approche Mage::app()->setCurrentStore(Mage::getModel('core/store')->load(Mage_Core_Model_App::ADMIN_STORE_ID)); ne peut pas réussir, car il n'y a aucune vue de magasin chargeable réellement existante pour l'administrateur

J'utilise souvent un modèle comme celui-ci:

// remembering old current store
$currentStore = Mage::app()->getCurrentStore();

// switching to admin store
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);

// switching back to old current store
Mage::app()->setCurrentStore($currentStore->getStoreId());

Sinon, parfois, après l'exécution d'un script de mise à niveau, vos visiteurs seront parfois redirigés vers la page d'administration au lieu du frontend.


Mise à jour:

J'ai mal interprété la question ci-dessous, alors voici une nouvelle tentative d'expliquer ^^

Les scripts de mise à niveau sont appelés à partir d'une méthode plus profonde dans le core ( Mage_Core_Model_Resource_Setup::_modifyResourceDb(...))

Ici, j'ai essayé de lister la pile

  • Mage_Core_Model_App::run($params)

  • Mage_Core_Model_App::_initModules()

  • Mage_Core_Model_Resource_Setup::applyAllUpdates()

  • Mage_Core_Model_Resource_Setup::applyUpdates()

  • Mage_Core_Model_Resource_Setup::_upgradeResourceDb($oldVersion, $newVersion)

  • Mage_Core_Model_Resource_Setup::_modifyResourceDb($actionType, $fromVersion, $toVersion)

et maintenant regardez Mage_Core_model_App::run($params):

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();
        $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();
            Mage_Core_Model_Resource_Setup::applyAllDataUpdates();
        }

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

la méthode _initModules()est appelée avant le $scopeCodeet $scopeTypeest déterminée.

Actuellement, je ne peux pas déterminer où le repli supposé est défini.

bukart
la source
Oh, mais il y a une vue de magasin chargeable pour l'administrateur. jetez un oeil dans le core_storetableau. Il existe un enregistrement avec id 0. De plus, si vous essayez cela, var_dump(Mage::getModel('core/store')->load(Mage_Core_Model_App::ADMIN_STORE_ID))vous obtiendrez une instance valide du magasin d'administration. Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);J'ai aussi essayé mais j'obtiens le même résultat. Mais ma question n'était pas de savoir comment définir le magasin d'administration dans les scripts de mise à niveau. Je demandais pourquoi Mage::app()->getStore()retourne le magasin avec l'ID 1 dans les scripts de mise à niveau.
Marius
oh ... bien ... il y a un magasin d'administration dans la base de données, en effet.
bukart
1
Hmm ... Je connaissais la pile mais maintenant que je l'ai vue dans ta réponse, elle m'a frappé. Les mises à jour devraient fonctionner d'une manière ou d'une autre «sans état». Mais pour exécuter quelque chose, vous avez besoin d'un magasin. D'où une valeur par défaut pour le magasin. Maintenant, la seule chose qui n'a pas de sens est: pourquoi ce magasin par défaut n'est-il pas 0(admin) et est-ce une vue de magasin qui pourrait facilement être supprimée de l'interface d'administration? +1 pour avoir ouvert les yeux. Si je n'obtiens pas d'autre réponse claire à ce sujet, je l'accepterai.
Marius
mhh ... bonne question ... peut-être qu'après le déjeuner je vais y jeter un coup d'oeil ... intéressant ^^
bukart
Depuis 1.9.3.6, Mage::app()->getCurrentStore();ne semble pas être défini et donne une erreur fatale lors de l'appel. Au lieu de cela, j'ai obtenu l'ID en utilisant $currentStoreId = Mage::app()->getStore()->getId();.
Eric Seastrand
2

Donc, la réponse de base est qu'il entre en fait dans le 3e si ..... attendez quoi :(

if (!isset($id) || ''===$id || $id === true) {
    $id = $this->_currentStore;
}

Pour moi, cela renvoie vrai pour Mage::isInstalled()et faux pour $this->getUpdateMode()ce qui sonne faux. Mais cela ne se produit que sur le premier hit de getStore.

Il semble donc qu'il configure le magasin avant la définition du mode de mise à jour, puis lorsqu'il revient dans le script de configuration, il utilise l'appel de magasin par défaut qui utilise le code suivant:

$this->_store = Mage::getModel('core/store')
    ->setId(self::DISTRO_STORE_ID)
    ->setCode(self::DISTRO_STORE_CODE);

La valeur de self::DISTRO_STORE_IDest 1, je suppose, car il a besoin de quelque chose et n'a pas été configuré pour nous le magasin d'administration :(

J'ai donc un système qui n'a pas été enregistré avec l'ID 1 et le script de mise à jour semble bien fonctionner. Si nous ajoutons des tables / attributs, c'est bien et même lors de l'ajout d'un bloc cms spécifique au site, cela fonctionne également, mais nous obtenons tous les identifiants de magasin et les définissons spécifiquement lors de l'enregistrement des données spécifiques au magasin.

David Manners
la source
J'ai déterré la même chose. Ce que je ne comprends pas, c'est "Magento pourquoi vous n'utilisez pas le magasin d'administration pour les mises à niveau?". Il semble plus raisonnable. J'ai peur de penser à ce qui se passe si je supprime le magasin avec l'identifiant 1.
Marius
Personne ne serait assez fou pour supprimer le magasin par défaut;)
David Manners
Maintenant que je le sais, je ne serai pas fou, mais le fait que c'est possible ... eh bien ... ne fais jamais confiance à un utilisateur.
Marius
Un de nos PM m'a demandé s'il pouvait retirer les anciens magasins la semaine dernière. Je pense avoir répondu "Quel est le pire qui puisse arriver" .... et encore plus étrange dans la configuration actuelle de notre projet, nous n'avons pas de magasin avec l'identifiant 1 :( dans le tableau core_storemais les scripts de configuration fonctionnent
David Manners
1
l'ajout d'un bloc cms doit être effectué dans un script de mise à niveau des données (pas d'installation) où la portée du magasin n'est pas verrouillée sur le Mage_Core_Model_App :: DISTRO_STORE_CODE; plus généralement, les scripts d'installation sont utilisés pour changer la structure des données (et la portée du magasin est verrouillée) tandis que la mise à niveau des données est utilisée pour changer le contenu des données (et la portée du magasin peut être modifiée pendant le script)
Alessandro Ronchi