ecoco/magento_profiler

View on GitHub
app/code/community/Ecocode/Profiler/Model/Collector/LayoutDataCollector.php

Summary

Maintainability
A
1 hr
Test Coverage
<?php

class Ecocode_Profiler_Model_Collector_LayoutDataCollector
    extends Ecocode_Profiler_Model_Collector_AbstractDataCollector
{
    protected $renderLog      = [];
    protected $renderedBlocks = [];
    protected $currentBlock;

    public function beforeToHtml(Varien_Event_Observer $observer)
    {
        /** @var Mage_Core_Block_Abstract $block */
        $block = $observer->getEvent()->getData('block');
        $id    = uniqid();
        $block->setData('profiler_id', $id);

        $data = [
            'id'           => $id,
            'start_render' => microtime(true),
            'hash'         => spl_object_hash($block),
            'children'     => [],
            'parent_id'    => false,
        ];

        if ($parentBlock = $block->getParentBlock()) {

        } else if ($block instanceof Mage_Widget_Block_Interface) {
            $parentBlock = $this->currentBlock;
        }

        if ($parentBlock && $parentId = $parentBlock->getData('profiler_id')) {
            $this->renderLog[$parentId]['children'][] = $id;
            $data['parent_id']                        = $parentId;
        }

        if (!$block instanceof Mage_Widget_Block_Interface) {
            $this->currentBlock = $block;
        }
        $this->renderLog[$id] = $data;
    }

    public function afterToHtml(Varien_Event_Observer $observer)
    {
        /** @var Mage_Core_Block_Abstract $block */
        $block = $observer->getEvent()->getData('block');
        $id    = $block->getData('profiler_id');
        $data  = $this->renderLog[$id];

        $data += $this->getBaseBlockData($block);
        $data['stop_render']      = microtime(true);
        $data['render_time_incl'] = $data['stop_render'] - $data['start_render'];

        if ($block instanceof Mage_Core_Block_Template) {
            $data['template'] = $block->getTemplate();
        }

        $this->renderedBlocks[$id] = $block;
        $this->renderLog[$id]      = $data;
    }

    /**
     * {@inheritdoc}
     */
    public function collect(Mage_Core_Controller_Request_Http $request, Mage_Core_Controller_Response_Http $response, \Exception $exception = null)
    {
        $outputProperties = new ReflectionProperty('Mage_Core_Model_Layout', '_output');
        $outputProperties->setAccessible(true);

        $layout       = $this->getLayout();
        $outputBlocks = [];

        foreach (array_keys($outputProperties->getValue($layout)) as $name) {
            $block          = $layout->getBlock($name);
            $outputBlocks[] = $block->getData('profiler_id');
        }

        $this->clearRenderLog();
        $totalTime         = $this->collectTimingData();
        $notRenderedBlocks = $this->collectNotRenderedBlocks();

        $this->data = [
            'handles'                   => $layout->getUpdate()->getHandles(),
            'blocks_created_count'      => count($layout->getAllBlocks()),
            'blocks_rendered_count'     => count($this->renderLog),
            'blocks_not_rendered_count' => count($notRenderedBlocks),
            'blocks_not_rendered'       => $notRenderedBlocks,
            'output_blocks'             => $outputBlocks,
            'render_log'                => $this->renderLog,
            'render_time'               => $totalTime

        ];

        return $this;
    }

    protected function collectNotRenderedBlocks()
    {
        $notRenderedBlocks = [];

        foreach ($this->getLayout()->getAllBlocks() as $block) {
            /** @var Mage_Core_Block_Abstract $block */
            if (!$block->getData('profiler_id')) {
                $notRenderedBlocks[] = $this->getBaseBlockData($block);
            }
        }

        return $notRenderedBlocks;
    }

    protected function clearRenderLog()
    {
        foreach ($this->renderLog as $id => &$data) {
            if (!isset($data['stop_render'])) {
                //block is not rendered, so unset it
                unset($this->renderLog[$id]);
                continue;
            }
        }
    }

    protected function collectTimingData()
    {
        $totalTime = 0;
        foreach ($this->renderLog as &$data) {
            $renderTimeExcl = $data['render_time_incl'];
            foreach ($data['children'] as $childId) {
                if (!isset($this->renderLog[$childId])) {
                    //if the block was unset continue
                    continue;
                }
                $child = $this->renderLog[$childId];
                $renderTimeExcl -= $child['render_time_incl'];
            }
            $data['render_time'] = $renderTimeExcl;

            $totalTime += $data['render_time'];
        }

        return $totalTime;
    }

    protected function getBaseBlockData(Mage_Core_Block_Abstract $block)
    {
        return [
            'name'       => $block->getNameInLayout(),
            'class'      => get_class($block),
            'module'     => $block->getModuleName(),
            'type'       => $block->getData('type'),
            'cacheable'  => $block->getCacheLifetime() !== null,
            'cache_time' => $block->getCacheLifetime(),
        ];
    }

    public function getTotalRenderTime()
    {
        return $this->getData('render_time', 0);
    }

    public function getRenderLog()
    {
        return $this->getData('render_log', []);
    }

    public function getBlocksNotRendered()
    {
        return $this->getData('blocks_not_rendered', []);
    }

    public function getLayoutHandles()
    {
        return $this->getData('handles', []);
    }

    public function getBlocksCreatedCount()
    {
        return $this->getData('blocks_created_count', []);
    }

    public function getBlocksRenderedCount()
    {
        return $this->getData('blocks_rendered_count', 0);
    }


    /**
     * @codeCoverageIgnore
     * @return Mage_Core_Model_Layout
     */
    public function getLayout()
    {
        return Mage::app()->getLayout();
    }

    /**
     * @codeCoverageIgnore
     * @return string
     */
    public function getName()
    {
        return 'layout';
    }

}