Carregamento de XML do layout de depuração

36

TL; DR: existe uma maneira eu posso depurar o carregamento do layout? Como acredito que o layout de um módulo está em conflito com outro.

Relacionado a uma pergunta anterior que fiz: Como criar um layout de módulo para ser mostrado em todos os temas

Carreguei meu módulo com sucesso no meu ambiente de teste local (também conhecido como PC de desenvolvimento), testei a alternância entre três temas diferentes e está tudo bem. Atualizei o módulo no ambiente de teste ou "pré-produção" que possuímos, onde existem muitos módulos diferentes, alguns proprietários outros criados por nós. Nesse ambiente, o módulo não mostra o que é necessário na página inicial do produto. Após alguns testes, finalmente chego à conclusão de que o problema deve estar no processo de carregamento do layout.

Então, existe uma maneira de depurar o carregamento do layout, como diferentes módulos substituem ou adicionam seus próprios blocos? O que quero dizer é que acredito que há pelo menos um módulo que deveria estar em conflito com o meu. E como temos tantos módulos, estou procurando uma abordagem diferente para desativar os módulos um por um e ver qual é o problemático.

Meu arquivo config.xml é:

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <modules>
        <Dts_Banners>
            <version>0.1.0</version>
        </Dts_Banners>
    </modules>
    <global>
        <blocks>
            <banners>
                <class>Dts_Banners_Block</class>
            </banners>
        </blocks>
  ....
        <events>
            <controller_action_layout_load_before>
                <observers>
                    <attributesethandle>
                        <class>Dts_Banners_Model_Observer</class>
                        <method>addAttributeSetHandle</method>
                    </attributesethandle>
                </observers>
            </controller_action_layout_load_before>
        </events>
    </global>    
  ....
</config>

Meu arquivo Observer:

<?php
class Dts_Banners_Model_Observer
{
    /**
     * Checks if the search text on the list of active campaigns (dts_banners_admin table) has some of the comma separated text on the product name
     * If text found, add a layout handle PRODUCT_CAMPAIGN_BANNER after PRODUCT_TYPE_<product_type_id> handle
     * This handle is handled on the banners.xml layout file that triggers the use of the Front.php frontend block
     *
     * Event: controller_action_layout_load_before
     *
     * @param Varien_Event_Observer $observer
     */
    public function addAttributeSetHandle(Varien_Event_Observer $observer) {
        $product = Mage::registry('current_product');
        if (!($product instanceof Mage_Catalog_Model_Product)) return;
      ....
      ....
}

Este é o meu arquivo de layout:

<?xml version="1.0" encoding="UTF-8"?>
<layout version="0.1.0">
    <default>
        <reference name="content">
            <block type="banners/front" name="banners.front" as="banners_front" template="banners/product.phtml" before="-"/>
        </reference>
    </default>
</layout>

Anteriormente tinha um pouco diferente, onde em vez de <default></default>eu tinha <Product_Campaign_Banner></Product_Campaign_Banner>. Também funcionou.

Meu arquivo product.phtml:

<div class="visual">
    <?php echo $this->showCampaign(); ?>
</div>

O product.phtmlarquivo não é carregado e, portanto, o showCampaignnão é executado e é aí que todo o HTML necessário é criado.

Yaroslav
fonte
2
O melhor seria ter env locais, tanto quanto possível mesmo que env pré-produção
Fra
É isso que estou fazendo agora, mas não é fácil, temos mais de 20 módulos de terceiros e até alguns deles não funcionam no ambiente de pré-produção e seus desenvolvedores estão verificando o código.
Yaroslav
4
Estou muito curioso para saber as razões por trás desta pergunta sendo sinalizada para fechar como localizada demais. A pergunta fala sobre a depuração de layout geral, que se você não tiver feito, é bastante útil e amplamente aplicável.
benmarks
Eu também estou curioso. Mas acho que, como resultado, depois de várias edições para outras pessoas, parece que estou apenas tentando resolver meu próprio problema muito localizado. E, de fato, sou, mas, ao mesmo tempo, ainda espero que, ao depurar o processo de geração de layout, seja capaz de descobrir onde está localizado o meu erro. Portanto, a solução será útil para outros.
Yaroslav

Respostas:

55

Você pode registrar as diretivas XML de layout compiladas usadas para gerar blocos. Crie um observador controller_action_layout_generate_blocks_beforee, no método observador, registre o XML de atualização a partir do objeto de layout transportado:

public function logCompiledLayout($o)
{
    $req  = Mage::app()->getRequest();
    $info = sprintf(
        "\nRequest: %s\nFull Action Name: %s_%s_%s\nHandles:\n\t%s\nUpdate XML:\n%s",
        $req->getRouteName(),
        $req->getRequestedRouteName(),      //full action name 1/3
        $req->getRequestedControllerName(), //full action name 2/3
        $req->getRequestedActionName(),     //full action name 3/3
        implode("\n\t",$o->getLayout()->getUpdate()->getHandles()),
        $o->getLayout()->getUpdate()->asString()
    );

    // Force logging to var/log/layout.log
    Mage::log($info, Zend_Log::INFO, 'layout.log', true);
}

A saída será semelhante a:

2013-01-23T16:24:26+00:00 INFO (6): 
Request: cms
Full Action Name: cms_index_index
Handles:
    default
    cms_page
    STORE_default
    THEME_frontend_default_default
    cms_index_index
    page_two_columns_right
    customer_logged_out
Update XML:
<block name="formkey" type="core/template" template="core/formkey.phtml"/>
<label>All Pages</label>
<!-- ... ->
benmarks
fonte
Parece útil, vai experimentá-lo amanhã na primeira hora
Yaroslav
Sua resposta foi a certa, exatamente o que eu estava procurando. O log criado gera todos os identificadores, solicitações, etc. no carregamento da página. Confirmei que meu identificador está carregado corretamente na matriz de identificadores principal, mas por algum motivo o bloco correspondente não é carregado / exibido.
precisa
1
E isso deve ser mais fácil de solucionar, agora que o layout foi descartado :-).
benmarks
Estou assumindo que você está colocando isso dentro do arquivo Action.php? Além disso, como isso está sendo chamado pelo magento?
Metropolis
"Criar um observador em controller_action_layout_generate_blocks_before" - esta é uma pergunta M1.
benmarks
23

Você pode recuperar todas as alças de layout no seu controlador, fazendo o seguinte:

var_dump($this->getLayout()->getUpdate()->getHandles());

Ou em qualquer lugar (desde que o layout tenha sido inicializado) usando este:

var_dump(Mage::app()->getLayout()->getUpdate()->getHandles());

Talvez isso ajude você a depurar.

EDITAR

Você configurou seu config.xml para especificar a classe de bloco?

    <blocks>
        <banners>
            <class>My_Banners_Block</class>
        </banners>
    </blocks>
Rick Kuipers
fonte
Ambos testados, meu identificador é adicionado corretamente ao método observador, mas o layout não é carregado. Vou atualizar minha pergunta com algum código, talvez isso ajude.
Yaroslav
@Yaroslav atualizou minha resposta
Rick Kuipers
Sim, eu tenho que na configuração, irá atualizar minha pergunta.
Yaroslav
@Yaroslav Você pode verificar se o product.phtml é carregado ao alterar o tipo de bloco para core/template? Isso é apenas para cancelar erros nas configurações do seu módulo.
21413 Rick Kipers
1
@Yaroslav, parece que o problema é um pouco difundido demais e difícil de depurar aqui no stackexchange. Não está muito claro para mim o que poderia causar o problema.
precisa
12

Estou usando o PhpStorm com Magicento e, por isso, pensei em adaptar a @benmarks ótima resposta ao meu uso.

No PhpStorm, abra app/code/core/Mage/Core/Controller/Varien/Action.phpe coloque um ponto de interrupção no método generateLayoutBlocks(). Eu acho que o objetivo é inseri-lo em qualquer lugar antes $this->getLayout()->generateBlocks();. Coloquei na linha anterior.

Depois de inserir o ponto de interrupção, indicado pelo ponto vermelho à esquerda pelo número da linha, você pode clicar com o botão direito do mouse para personalizar o comportamento. Clique em "Mais" na parte inferior para abrir todas as opções. insira a descrição da imagem aqui

Depois de abrir, marque a caixa de seleção "Mensagem de log para console" (opcional) e "Expressão avaliada por log" (onde a mágica acontece). Em seguida, copie e cole esta adaptação do código da benmark na caixa de texto. A única coisa que mudei é soletrar a $requestvariável como Mage::app()->getRequest()sempre, e alterei a $ovariável para $this(b / c, não estamos no contexto do observador aqui).

sprintf("\nRequest: %s\nFull Action Name: %s_%s_%s\nHandles:\n\t%s\nUpdate XML:\n%s",Mage::app()->getRequest()->getRouteName(),Mage::app()->getRequest()->getRequestedRouteName(),Mage::app()->getRequest()->getRequestedControllerName(),Mage::app()->getRequest()->getRequestedActionName(),implode("\n\t",$this->getLayout()->getUpdate()->getHandles()),$this->getLayout()->getUpdate()->asString())

Então agora fica assim: A imagem mostra configurações avançadas de ponto de interrupção

Depois de executar o programa (usando o xdebug ou o zend debugger), você irá parar no ponto de interrupção e verá isso no log:

Update XML:
<block name="formkey" type="core/template" template="core/formkey.phtml"/>
<label>All Pages</label>
<block type="page/html" name="root" output="toHtml" template="page/2columns-left.phtml">
   <block type="page/html_head" name="head" as="head">
      <action method="addJs">
         <script>jquery/jquery-migrate-1.2.1.min.js</script>
      </action>
      <action method="addJs">
         <script>jquery/jquery-ui/jquery-ui.min.js</script>
      </action>
      <action method="addJs">
         <script>prototype/prototype.js</script>
      </action>
      <action method="addJs" ifconfig="dev/js/deprecation">
         <script>prototype/deprecation.js</script>
      </action>
      <action method="addJs">
         <script>lib/ccard.js</scrip

Parece haver um limite de tamanho para as entradas de log que podem ser determinadas pela idea.cycle.buffer.sizepropriedade no idea.propertiesarquivo do PhpStorm, de acordo com isso . Você pode mudar isso, ou apenas clicar com o botão direito do mouse na janela de código e selecionar "Avaliar Expressão" no menu suspenso, copiar e colar o código para executar lá e obterá a saída completa.

No pop-up "Avaliar expressão", você pode clicar com o botão direito do mouse (Windows) no resultado e selecionar "Copiar valor" para obter toda a saída e colá-la em outro lugar para análise.

PhpStorm - copiar do pop-up Avaliar Expressão

Buttle Butkus
fonte
5

Utilizamos a extensão Commerce Bug de Alan Storm e consideramos indispensável a depuração de várias coisas no Magento, incluindo problemas de layout. Para layouts, é possível ver quais identificadores de layout estão ativos em cada página e quais configurações xml de layout estão sendo aplicadas à página.

Não é gratuito, mas economizará muito tempo depurando esse tipo de coisa.

Nota: não sou afiliado ao Alan Storm ou ao Commerce Bug, mas apenas um cliente satisfeito.

Luke Mills
fonte
9
Sou afiliado a Alan Storm (por ser ele) e só queria ressaltar que o Commerce Bug 2 também oferece a capacidade de produzir um diagrama gráfico direcionado de seus layouts. alanstorm.com/find_magento_block_name
Alan Storm
Também somos clientes satisfeitos do bug do comércio Alan Storm. Mas no sistema em que estou tendo esses problemas, ele não está instalado e não temos licenças suficientes para todos os sistemas de teste e pré-produção. A propósito, @ AlanStorm, como podemos obter a atualização para o Commerce Bug 2?
precisa
1
@Yaroslav apoio Contato e vamos começá-lo resolvido com atualizações e upgrades de pulsestorm.net/contact-us
Alan Storm
3

Thanx Ben Marks! Esta é a minha versão do logger de layout xml que você descreveu.

É um arquivo muito longo, então eu criei XML dele ... :-) Você pode abrir com um editor normal ....

    <?php

class Gn_Optimization_Model_Debug_Layout {
  public function logCompiledLayout($o) {
    $req = Mage::app()->getRequest();

    $routeName = $req->getRouteName();
    $fullname = $req->getRequestedRouteName() . '_' . $req->getRequestedControllerName() . '_' . $req->getRequestedActionName();

    $info = sprintf(
      "\nRequest: %s\nFull Action Name: %s\nHandles:\n\t%s\n",
      $routeName, $fullname, implode("\n\t", $o->getLayout()->getUpdate()->getHandles())
    );

    Mage::log($info, Zend_Log::DEBUG, 'debug.'.$routeName.'.layout.log', true);
    file_put_contents(Mage::getBaseDir('log').DS.'debug.'.$routeName.'.layout.xml',
                      '<?xml version="1.0" encoding="utf-8"?>'.PHP_EOL
                      .'<layout>'.PHP_EOL.
                      $o->getLayout()->getUpdate()->asString().
                      '</layout>');
  }
}

E meu config.xml se parece com isso no nó:

<events>
  <controller_action_layout_generate_blocks_before>
    <observers>
      <gn_optimization_controller_action_layout_generate_blocks_before>
        <type>singleton</type>
        <class>gn_optimization/debug_layout</class>
        <method>logCompiledLayout</method>
      </gn_optimization_controller_action_layout_generate_blocks_before>
    </observers>
  </controller_action_layout_generate_blocks_before>
</events>

Agora, espero que meu designer possa explicar tudo isso ... \ o /

Roger Keulen
fonte
0

Você pode adicionar isso à sua ação do controlador. Ele mostrará alças de maneira mais elegante que var_dump.

Zend_Debug::dump($this->getLayout()->getUpdate()->getHandles());
TheKitMurkit
fonte