CatalogueController   B
last analyzed

Complexity

Total Complexity 51

Size/Duplication

Total Lines 353
Duplicated Lines 0 %

Importance

Changes 7
Bugs 0 Features 2
Metric Value
eloc 147
c 7
b 0
f 2
dl 0
loc 353
rs 7.92
wmc 51

10 Methods

Rating   Name   Duplication   Size   Complexity  
B getViewer() 0 30 7
B CategoryMenu() 0 34 8
A PaginatedAllProducts() 0 13 2
A getFilter() 0 12 2
A init() 0 14 6
C handleRequest() 0 75 12
A ProductImage() 0 7 1
B MetaTags() 0 66 8
A __construct() 0 12 3
A PaginatedProducts() 0 13 2

How to fix   Complexity   

Complex Class

Complex classes like CatalogueController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CatalogueController, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace SilverCommerce\CatalogueFrontend\Control;
4
5
use \Page;
0 ignored issues
show
Bug introduced by
The type Page was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use SilverStripe\i18n\i18n;
7
use SilverStripe\View\HTML;
8
use SilverStripe\View\SSViewer;
9
use SilverStripe\Control\Director;
10
use SilverStripe\ORM\PaginatedList;
11
use SilverStripe\Core\Config\Config;
12
use SilverStripe\Control\HTTPRequest;
13
use SilverStripe\Security\Permission;
14
use SilverStripe\Control\HTTPResponse;
15
use SilverStripe\Subsites\Model\Subsite;
0 ignored issues
show
Bug introduced by
The type SilverStripe\Subsites\Model\Subsite was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
use SilverStripe\Control\ContentNegotiator;
17
use SilverStripe\Control\HTTPResponse_Exception;
18
use SilverStripe\CMS\Controllers\ContentController;
19
use SilverCommerce\CatalogueAdmin\Model\CatalogueProduct;
20
use SilverCommerce\CatalogueAdmin\Model\CatalogueCategory;
21
22
/**
23
 * Controller used to render pages in the catalogue (either categories or pages)
24
 *
25
 * @author  i-lateral (http://www.i-lateral.com)
26
 * @package catalogue
27
 */
28
class CatalogueController extends ContentController
29
{
30
31
    /**
32
     * Find a filter from the URL that we can apply to the products list
33
     *
34
     * @return array
35
     */
36
    public function getFilter()
37
    {
38
        $filter = ['Disabled' => 0];
39
        $tag = $this->getRequest()->getVar("t");
40
41
        if ($tag) {
42
            $filter["Tags.URLSegment"] = $tag;
43
        }
44
45
        $this->extend("updateFilter", $filter);
46
47
        return $filter;
48
    }
49
    
50
    /**
51
     * Get a paginated list of products contained in this category
52
     *
53
     * @return PaginatedList
54
     */
55
    public function PaginatedProducts($limit = 10)
56
    {
57
        $products = $this->SortedProducts();
0 ignored issues
show
Bug introduced by
The method SortedProducts() does not exist on SilverCommerce\Catalogue...rol\CatalogueController. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

57
        /** @scrutinizer ignore-call */ 
58
        $products = $this->SortedProducts();
Loading history...
58
        $filter = $this->getFilter();
59
60
        if (count($filter)) {
61
            $products = $products->filter($filter);
62
        }
63
64
        return PaginatedList::create(
65
            $products,
66
            $this->getRequest()
67
        )->setPageLength($limit);
68
    }
69
70
71
    /**
72
     * Get a paginated list of all products at this level and below
73
     *
74
     * @return PaginatedList
75
     */
76
    public function PaginatedAllProducts($limit = 10)
77
    {
78
        $products = $this->AllProducts();
0 ignored issues
show
Bug introduced by
The method AllProducts() does not exist on SilverCommerce\Catalogue...rol\CatalogueController. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

78
        /** @scrutinizer ignore-call */ 
79
        $products = $this->AllProducts();
Loading history...
79
        $filter = $this->getFilter();
80
81
        if (count($filter)) {
82
            $products = $products->filter($filter);
83
        }
84
85
        return PaginatedList::create(
86
            $products,
87
            $this->getRequest()
88
        )->setPageLength($limit);
89
    }
90
91
    /**
92
     * The Controller will take the URLSegment parameter from the URL
93
     * and use that to look up a record.
94
     */
95
    public function __construct($dataRecord = null)
96
    {
97
        if (!$dataRecord) {
98
            $dataRecord = new CatalogueCategory();
99
            if ($this->hasMethod("Title")) {
100
                $dataRecord->Title = $this->Title();
0 ignored issues
show
Bug introduced by
The method Title() does not exist on SilverCommerce\Catalogue...rol\CatalogueController. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

100
                /** @scrutinizer ignore-call */ 
101
                $dataRecord->Title = $this->Title();
Loading history...
101
            }
102
            $dataRecord->URLSegment = get_class($this);
103
            $dataRecord->ID = -1;
104
        }
105
        
106
        parent::__construct($dataRecord);
107
    }
108
109
    protected function init()
110
    {
111
        parent::init();
112
113
        // Check for subsites and add support
114
        if (class_exists(Subsite::class)) {
115
            $subsite = Subsite::currentSubsite();
116
117
            if ($subsite && $subsite->Theme) {
118
                SSViewer::add_themes([$subsite->Theme]);
119
            }
120
121
            if ($subsite && i18n::getData()->validate($subsite->Language)) {
122
                i18n::set_locale($subsite->Language);
123
            }
124
        }
125
    }
126
127
    /**
128
     * The productimage action is used to determine the default image that will
129
     * appear related to a product
130
     *
131
     * @return Image
0 ignored issues
show
Bug introduced by
The type SilverCommerce\CatalogueFrontend\Control\Image was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
132
     */
133
    public function ProductImage()
134
    {
135
        $image = $this->SortedImages()->first();
0 ignored issues
show
Bug introduced by
The method SortedImages() does not exist on SilverCommerce\Catalogue...rol\CatalogueController. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

135
        $image = $this->/** @scrutinizer ignore-call */ SortedImages()->first();
Loading history...
136
            
137
        $this->extend("updateProductImage", $image);
138
139
        return $image;
140
    }
141
142
    /**
143
     * Return the title, description, keywords and language metatags.
144
     * NOTE: Shamelessley taken from SiteTree
145
     *
146
     * @param bool $includeTitle Show default <title>-tag, set to false for custom templating
147
     *
148
     * @return string The XHTML metatags
149
     */
150
    public function MetaTags($includeTitle = true)
151
    {
152
        $tags = [];
153
154
        if ($includeTitle && strtolower($includeTitle) != 'false') {
0 ignored issues
show
Bug introduced by
$includeTitle of type true is incompatible with the type string expected by parameter $string of strtolower(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

154
        if ($includeTitle && strtolower(/** @scrutinizer ignore-type */ $includeTitle) != 'false') {
Loading history...
155
            $tags[] = HTML::createTag(
156
                'title',
157
                [],
158
                $this->obj('Title')->forTemplate()
159
            );
160
        }
161
162
        $generator = trim(Config::inst()->get(self::class, 'meta_generator'));
163
        if (!empty($generator)) {
164
            $tags[] = HTML::createTag(
165
                'meta',
166
                [
167
                    'name' => 'generator',
168
                    'content' => $generator,
169
                ]
170
            );
171
        }
172
173
        $charset = ContentNegotiator::config()->uninherited('encoding');
174
        $tags[] = HTML::createTag(
175
            'meta',
176
            [
177
                'http-equiv' => 'Content-Type',
178
                'content' => 'text/html; charset=' . $charset,
179
            ]
180
        );
181
        if ($this->MetaDescription) {
0 ignored issues
show
Bug Best Practice introduced by
The property MetaDescription does not exist on SilverCommerce\Catalogue...rol\CatalogueController. Since you implemented __get, consider adding a @property annotation.
Loading history...
182
            $tags[] = HTML::createTag(
183
                'meta',
184
                [
185
                    'name' => 'description',
186
                    'content' => $this->MetaDescription,
187
                ]
188
            );
189
        }
190
191
        if (Permission::check('CMS_ACCESS_CMSMain') && $this->exists()) {
192
            $tags[] = HTML::createTag(
193
                'meta',
194
                [
195
                    'name' => 'x-page-id',
196
                    'content' => $this->obj('ID')->forTemplate()
197
                ]
198
            );
199
            $tags[] = HTML::createTag(
200
                'meta',
201
                [
202
                    'name' => 'x-cms-edit-link',
203
                    'content' => $this->obj('CMSEditLink')->forTemplate()
204
                ]
205
            );
206
        }
207
208
        $tags = implode("\n", $tags);
209
        if ($this->ExtraMeta) {
0 ignored issues
show
Bug Best Practice introduced by
The property ExtraMeta does not exist on SilverCommerce\Catalogue...rol\CatalogueController. Since you implemented __get, consider adding a @property annotation.
Loading history...
210
            $tags .= $this->obj('ExtraMeta')->forTemplate();
211
        }
212
213
        $this->dataRecord->extend('MetaTags', $tags);
214
215
        return $tags;
216
    }
217
218
    /**
219
     * This acts the same as {@link Controller::handleRequest()}, but if an action cannot be found this will attempt to
220
     * fall over to a child controller in order to provide functionality for nested URLs.
221
     *
222
     * @param  HTTPRequest $request
223
     * @return HTTPResponse
224
     * @throws HTTPResponse_Exception
225
     */
226
    public function handleRequest(HTTPRequest $request)
227
    {
228
        /**
229
         * @var SiteTree $child
230
        */
231
        $child  = null;
232
        $action = $request->param('Action');
233
234
        // If nested URLs are enabled, and there is no action handler for the current request then attempt to pass
235
        // control to a child controller. This allows for the creation of chains of controllers which correspond to a
236
        // nested URL.
237
        if ($action && !$this->hasAction($action)) {
238
            // look for a child category with this URLSegment
239
            $child = CatalogueCategory::get()->filter(
240
                [
241
                'ParentID' => $this->ID,
242
                'URLSegment' => rawurlencode($action),
243
                'Disabled' => 0
244
                ]
245
            )->first();
246
247
            // Next check to see if the child os a product
248
            if (!$child) {
249
                $child = CatalogueProduct::get()->filter(
250
                    [
251
                    "Categories.ID" => $this->ID,
252
                    "URLSegment" => rawurldecode($action),
253
                    'Disabled' => 0
254
                    ]
255
                )->first();
256
            }
257
        }
258
259
        // we found a page with this URLSegment.
260
        if ($child) {
261
            $request->shiftAllParams();
262
            $request->shift();
263
264
            $response = ModelAsController::controller_for_object($child)->handleRequest($request);
265
        } else {
266
            // If a specific locale is requested, and it doesn't match the page found by URLSegment,
267
            // look for a translation and redirect (see #5001). Only happens on the last child in
268
            // a potentially nested URL chain.
269
            if (class_exists('Translatable')) {
270
                $locale = $request->getVar('locale');
271
                if ($locale
272
                    && i18n::getData()->validate($locale)
273
                    && $this->dataRecord
274
                    && $this->dataRecord->Locale != $locale
275
                ) {
276
                    $translation = $this->dataRecord->getTranslation($locale);
277
                    if ($translation) {
278
                        $response = new HTTPResponse();
279
                        $response->redirect($translation->Link(), 301);
280
                        throw new HTTPResponse_Exception($response);
281
                    }
282
                }
283
            }
284
285
            Director::set_current_page($this->data());
286
287
            try {
288
                $response = parent::handleRequest($request);
289
290
                Director::set_current_page(null);
291
            } catch (HTTPResponse_Exception $e) {
292
                $this->popCurrent();
293
294
                Director::set_current_page(null);
295
296
                throw $e;
297
            }
298
        }
299
300
        return $response;
301
    }
302
303
    /**
304
     * Overwrite default SSViewer call to get a custom
305
     * template list
306
     *
307
     * @param  $action string
308
     * @return SSViewer
309
     */
310
    public function getViewer($action)
311
    {
312
        // Manually set templates should be dealt with by Controller::getViewer()
313
        if (isset($this->templates[$action]) && $this->templates[$action]
314
            || (isset($this->templates['index']) && $this->templates['index'])
315
            || $this->template
0 ignored issues
show
Bug Best Practice introduced by
The property template does not exist on SilverCommerce\Catalogue...rol\CatalogueController. Since you implemented __get, consider adding a @property annotation.
Loading history...
316
        ) {
317
            return parent::getViewer($action);
318
        }
319
320
        // Prepare action for template search
321
        if ($action == "index") {
322
            $action = "";
323
        } else {
324
            $action = '_' . $action;
325
        }
326
327
        $templates = array_merge(
328
            // Find templates by dataRecord
329
            SSViewer::get_templates_by_class(get_class($this->dataRecord), $action, "SilverStripe\\CMS\\Model\\SiteTree"),
330
            // Now get templates for sitetree
331
            SSViewer::get_templates_by_class(Page::singleton(), $action, "SilverStripe\\CMS\\Model\\SiteTree"),
332
            // Next, we need to add templates for all controllers
333
            SSViewer::get_templates_by_class(static::class, $action, "SilverStripe\\Control\\Controller"),
334
            // Fail-over to the same for the "index" action
335
            SSViewer::get_templates_by_class(get_class($this->dataRecord), "", "SilverStripe\\CMS\\Model\\SiteTree"),
336
            SSViewer::get_templates_by_class(static::class, "", "SilverStripe\\Control\\Controller")
337
        );
338
339
        return SSViewer::create($templates);
340
    }
341
    
342
    /**
343
     * Returns a fixed navigation menu of the given level.
344
     *
345
     * @return SS_List
0 ignored issues
show
Bug introduced by
The type SilverCommerce\CatalogueFrontend\Control\SS_List was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
346
     */
347
    public function CategoryMenu($level = 1)
348
    {
349
        if ($level == 1) {
350
            $result = CatalogueCategory::get()->filter(
351
                array(
352
                "ParentID" => 0
353
                )
354
            );
355
        } else {
356
            $parent = $this->data();
357
            $stack = array($parent);
358
359
            if ($parent) {
0 ignored issues
show
introduced by
$parent is of type SilverStripe\CMS\Model\SiteTree, thus it always evaluated to true.
Loading history...
360
                while ($parent = $parent->Parent) {
361
                    array_unshift($stack, $parent);
362
                }
363
            }
364
365
            if (isset($stack[$level-2])) {
366
                $result = $stack[$level-2]->Children();
367
            }
368
        }
369
370
        $visible = array();
371
372
        if (isset($result)) {
373
            foreach ($result as $item) {
374
                if ($item->canView()) {
375
                    $visible[] = $item;
376
                }
377
            }
378
        }
379
380
        return new ArrayList($visible);
0 ignored issues
show
Bug introduced by
The type SilverCommerce\CatalogueFrontend\Control\ArrayList was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
381
    }
382
}
383