Completed
Pull Request — devel (#1263)
by
unknown
02:42
created

_getEsiBlock()   D

Complexity

Conditions 15
Paths 132

Size

Total Lines 94
Code Lines 59

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 3 Features 0
Metric Value
c 4
b 3
f 0
dl 0
loc 94
rs 4.597
cc 15
eloc 59
nc 132
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Nexcess.net Turpentine Extension for Magento
5
 * Copyright (C) 2012  Nexcess.net L.L.C.
6
 *
7
 * This program is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License along
18
 * with this program; if not, write to the Free Software Foundation, Inc.,
19
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
 */
21
22
class Nexcessnet_Turpentine_EsiController extends Mage_Core_Controller_Front_Action {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
23
    /**
24
     * It seems this has to exist so we just make it redirect to the base URL
25
     * for lack of anything better to do.
26
     *
27
     * @return null
28
     */
29
    public function indexAction() {
30
        $this->getResponse()->setRedirect(Mage::getBaseUrl());
31
    }
32
33
    /**
34
     * Spit out the form key for this session
35
     *
36
     * @return null
37
     */
38
    public function getFormKeyAction() {
39
        $resp = $this->getResponse();
40
        $resp->setBody(
41
            Mage::getSingleton('core/session')->real_getFormKey() );
42
        $resp->setHeader('X-Turpentine-Cache', '1');
43
        $resp->setHeader('X-Turpentine-Flush-Events',
44
            implode(',', Mage::helper('turpentine/esi')
45
                ->getDefaultCacheClearEvents()));
46
        $resp->setHeader('X-Turpentine-Block', 'form_key');
47
        Mage::register('turpentine_nocache_flag', false, true);
48
49
        Mage::helper('turpentine/debug')->logDebug('Generated form_key: %s',
50
            $resp->getBody());
51
    }
52
53
    /**
54
     * Spit out the rendered block from the URL-encoded data
55
     *
56
     * @return null
57
     */
58
    public function getBlockAction() {
59
        $resp = $this->getResponse();
60
        $cacheFlag = false;
61
        if (Mage::helper('turpentine/esi')->shouldResponseUseEsi()) {
62
            $req = $this->getRequest();
63
            $esiHelper = Mage::helper('turpentine/esi');
64
            $dataHelper = Mage::helper('turpentine/data');
65
            $debugHelper = Mage::helper('turpentine/debug');
66
            $esiDataHmac = $req->getParam($esiHelper->getEsiHmacParam());
67
            $esiDataParamValue = $req->getParam($esiHelper->getEsiDataParam());
68
            if ($esiDataHmac !== ($hmac = $dataHelper->getHmac($esiDataParamValue))) {
69
                $debugHelper->logWarn('ESI data HMAC mismatch, expected (%s) but received (%s)',
70
                    $hmac, $esiDataHmac);
71
                $resp->setHttpResponseCode(500);
72
                $resp->setBody('ESI data is not valid');
73
            } elseif ( ! ($esiDataArray = $dataHelper->thaw($esiDataParamValue))) {
74
                $debugHelper->logWarn('Invalid ESI data in URL: %s',
75
                    $esiDataParamValue);
76
                $resp->setHttpResponseCode(500);
77
                $resp->setBody('ESI data is not valid');
78
            } elseif ( ! $esiHelper->getEsiDebugEnabled() &&
79
                    $esiDataArray['esi_method'] !==
80
                    $req->getParam($esiHelper->getEsiMethodParam())) {
81
                $resp->setHttpResponseCode(403);
82
                $resp->setBody('ESI method mismatch');
83
                $debugHelper->logWarn('Blocking change of ESI method: %s -> %s',
84
                    $esiDataArray['esi_method'],
85
                    $req->getParam($esiHelper->getEsiMethodParam()));
86
            } else {
87
                $esiData = new Varien_Object($esiDataArray);
88
                $origRequest = Mage::app()->getRequest();
89
                Mage::app()->setCurrentStore(
90
                    Mage::app()->getStore($esiData->getStoreId()) );
91
                $appShim = Mage::getModel('turpentine/shim_mage_core_app');
92
                if ($referer = $this->_getRefererUrl()) {
93
                    $referer = htmlspecialchars_decode($referer);
94
                    $dummyRequest = Mage::helper('turpentine/esi')
95
                        ->getDummyRequest($referer);
96
                } else {
97
                    $dummyRequest = Mage::helper('turpentine/esi')
98
                        ->getDummyRequest();
99
                }
100
                $appShim->shim_setRequest($dummyRequest);
101
                $block = $this->_getEsiBlock($esiData);
102
                if ($block) {
103
                    $blockEsiOptions = $block->getEsiOptions();
104
                    $block->setEsiOptions(false);
105
                    $resp->setBody($block->toHtml());
106
                    if ((int) $req->getParam($esiHelper->getEsiTtlParam()) > 0) {
107
                        $cacheFlag = true;
108
                        if (isset($blockEsiOptions['only_cache_if'])) {
109
                            switch ($blockEsiOptions['only_cache_if']) {
110
                                case 'empty':
111
                                    $cacheFlag = ('' === $resp->getBody());
112
                                    break;
113
                                case 'no_text':
114
                                    $cacheFlag = ('' === trim(strip_tags($resp->getBody())));
115
                                    break;
116
                                default:
117
                                    $cacheFlag = false;
118
                            }
119
                        }
120
                    }
121
                    if ($esiData->getEsiMethod() == 'ajax') {
122
                        $resp->setHeader('Access-Control-Allow-Origin',
123
                            $esiHelper->getCorsOrigin());
124
                    }
125
                    if ( ! is_null($flushEvents = $esiData->getFlushEvents())) {
126
                        $resp->setHeader('X-Turpentine-Flush-Events',
127
                            implode(',', $flushEvents));
128
                    }
129
                    if ($esiHelper->getEsiDebugEnabled()) {
130
                        $resp->setHeader('X-Turpentine-Block',
131
                            $block->getNameInLayout());
132
                    }
133
                } else {
134
                    $resp->setHttpResponseCode(404);
135
                    $resp->setBody('ESI block not found');
136
                }
137
                $appShim->shim_setRequest($origRequest);
138
            }
139
        } else {
140
            $resp->setHttpResponseCode(403);
141
            $resp->setBody('ESI includes are not enabled');
142
        }
143
        Mage::register('turpentine_nocache_flag', ! $cacheFlag, true);
144
    }
145
146
    /**
147
     * Need to disable this flag to prevent setting the last URL but we
148
     * don't want to completely break sessions.
149
     *
150
     * see Mage_Core_Controller_Front_Action::postDispatch
151
     *
152
     * @return null
153
     */
154
    public function postDispatch() {
155
        $flag = $this->getFlag('', self::FLAG_NO_START_SESSION);
156
        $this->setFlag('', self::FLAG_NO_START_SESSION, true);
157
        parent::postDispatch();
158
        $this->setFlag('', self::FLAG_NO_START_SESSION, $flag);
159
    }
160
161
    /**
162
     * Generate the ESI block
163
     *
164
     * @param  Varien_Object $esiData
165
     * @return Mage_Core_Block_Template|null
166
     */
167
    protected function _getEsiBlock($esiData) {
168
        $block = null;
0 ignored issues
show
Unused Code introduced by
$block is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
169
        Varien_Profiler::start('turpentine::controller::esi::_getEsiBlock');
170
        foreach ($esiData->getSimpleRegistry() as $key => $value) {
171
            Mage::register($key, $value, true);
172
        }
173
        foreach ($esiData->getComplexRegistry() as $key => $data) {
174
            $value = Mage::getModel($data['model']);
175
            if ( ! is_object($value)) {
176
                Mage::helper('turpentine/debug')->logWarn(
177
                    'Failed to register key/model: %s as %s(%s)',
178
                    $key, $data['model'], $data['id'] );
179
                continue;
180
            } else {
181
                $value->load($data['id']);
182
                Mage::register($key, $value, true);
183
            }
184
        }
185
186
187
        /** @var Mage_Core_Model_Layout $layout */
188
        $layout = Mage::getSingleton('core/layout');
189
        $layout->getUpdate()->addHandle(
190
            $this->_swapCustomerHandles(
191
                $esiData->getLayoutHandles()
192
            )
193
        );
194
        $this->loadLayoutUpdates();
195
196
        foreach ($esiData->getDummyBlocks() as $blockName) {
197
            $layout->createBlock('Mage_Core_Block_Template', $blockName);
198
        }
199
200
        $this->generateLayoutXml();
201
202
        /** @var Nexcessnet_Turpentine_Helper_Data $turpentineHelper */
203
        $turpentineHelper = Mage::helper('turpentine/data')
204
            ->setLayout($layout);
205
206
        $blockNode = current($layout->getNode()->xpath(
207
                sprintf('//block[@name=\'%s\']', $esiData->getNameInLayout())
208
            ));
209
210
        if ( ! ($blockNode instanceof Mage_Core_Model_Layout_Element)) {
0 ignored issues
show
Bug introduced by
The class Mage_Core_Model_Layout_Element does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
211
            Mage::helper('turpentine/debug')->logWarn(
212
                            'No block node found with @name="%s"',
213
                            $esiData->getNameInLayout() );
214
            return null;
215
        }
216
217
        $nodesToGenerate = $turpentineHelper->getChildBlockNames($blockNode);
218
        Mage::getModel('turpentine/shim_mage_core_layout')
219
            ->shim_generateFullBlock($blockNode);
220
221
        //find addional blocks that aren't defined in the <block/> but via <reference name="%s">
222
        $referenceNodes = $layout->getNode()->xpath(sprintf(
223
            '//reference[@name=\'%s\']',
224
            $esiData->getNameInLayout() ));
225
        if ($referenceNodes) {
226
            foreach ($referenceNodes as $referenceNode) {
227
                if ($referenceNode instanceof Mage_Core_Model_Layout_Element) {
0 ignored issues
show
Bug introduced by
The class Mage_Core_Model_Layout_Element does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
228
                    $referencesToGenerate = $turpentineHelper
229
                        ->getChildBlockNames($referenceNode);
230
                    $nodesToGenerate =
231
                        array_merge($nodesToGenerate, $referencesToGenerate);
232
                }
233
            }
234
        }
235
236
        // Global blocks to generate
237
        $globalBlocks = array('formkey');
238
239
        // Add ignore attribute to all nodes that don't need to be generated
240
        foreach ($layout->getNode() as $node) {
241
            $attributes = $node->attributes();
242
            if ((bool)$attributes->ignore) {
243
                continue;
244
            } elseif ($node->getName() == 'block' && !in_array($attributes->name, $globalBlocks)) {
245
                $node->addAttribute('ignore', true);
246
            } elseif ($node->getName() == 'reference' && !in_array($attributes->name, $nodesToGenerate)) {
247
                $node->addAttribute('ignore', true);
248
            }
249
        }
250
251
        // Generate layout block that aren't ignored
252
        $this->generateLayoutBlocks();
253
254
        // Get the requested ESI block
255
        $block = $layout->getBlock($esiData->getNameInLayout());
256
257
        $this->_isLayoutLoaded = true;
258
        Varien_Profiler::stop('turpentine::controller::esi::_getEsiBlock');
259
        return $block;
260
    }
261
262
    /**
263
     * Swap customer_logged_in and customer_logged_out cached handles based on
264
     * actual customer login status. Fixes stale Login/Logout links (and
265
     * probably other things).
266
     *
267
     * This is definitely a hack, need a more general solution to this problem.
268
     *
269
     * @param  array $handles
270
     * @return array
271
     */
272
    protected function _swapCustomerHandles($handles) {
273
        if (Mage::helper('customer')->isLoggedIn()) {
274
            $replacement = array('customer_logged_out', 'customer_logged_in');
275
        } else {
276
            $replacement = array('customer_logged_in', 'customer_logged_out');
277
        }
278
        if (($pos = array_search($replacement[0], $handles)) !== false) {
279
            $handles[$pos] = $replacement[1];
280
        }
281
        return $handles;
282
    }
283
}
284