Passed
Push — 1.0 ( 9ae6a9...0c6842 )
by Morven
08:45 queued 10s
created

CatalogueController   C

Complexity

Total Complexity 53

Size/Duplication

Total Lines 361
Duplicated Lines 0 %

Importance

Changes 6
Bugs 0 Features 2
Metric Value
eloc 151
c 6
b 0
f 2
dl 0
loc 361
rs 6.96
wmc 53

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 83 14
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\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...
15
use SilverStripe\Control\ContentNegotiator;
16
use SilverStripe\CMS\Controllers\ContentController;
17
use SilverCommerce\CatalogueAdmin\Model\CatalogueProduct;
18
use SilverCommerce\CatalogueAdmin\Model\CatalogueCategory;
19
20
/**
21
 * Controller used to render pages in the catalogue (either categories or pages)
22
 *
23
 * @author  i-lateral (http://www.i-lateral.com)
24
 * @package catalogue
25
 */
26
class CatalogueController extends ContentController
27
{
28
29
    /**
30
     * Find a filter from the URL that we can apply to the products list
31
     *
32
     * @return array
33
     */
34
    public function getFilter()
35
    {
36
        $filter = ['Disabled' => 0];
37
        $tag = $this->getRequest()->getVar("t");
38
39
        if ($tag) {
40
            $filter["Tags.URLSegment"] = $tag;
41
        }
42
43
        $this->extend("updateFilter", $filter);
44
45
        return $filter;
46
    }
47
    
48
    /**
49
     * Get a paginated list of products contained in this category
50
     *
51
     * @return PaginatedList
52
     */
53
    public function PaginatedProducts($limit = 10)
54
    {
55
        $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

55
        /** @scrutinizer ignore-call */ 
56
        $products = $this->SortedProducts();
Loading history...
56
        $filter = $this->getFilter();
57
58
        if (count($filter)) {
59
            $products = $products->filter($filter);
60
        }
61
62
        return PaginatedList::create(
63
            $products,
64
            $this->getRequest()
65
        )->setPageLength($limit);
66
    }
67
68
69
    /**
70
     * Get a paginated list of all products at this level and below
71
     *
72
     * @return PaginatedList
73
     */
74
    public function PaginatedAllProducts($limit = 10)
75
    {
76
        $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

76
        /** @scrutinizer ignore-call */ 
77
        $products = $this->AllProducts();
Loading history...
77
        $filter = $this->getFilter();
78
79
        if (count($filter)) {
80
            $products = $products->filter($filter);
81
        }
82
83
        return PaginatedList::create(
84
            $products,
85
            $this->getRequest()
86
        )->setPageLength($limit);
87
    }
88
89
    /**
90
     * The Controller will take the URLSegment parameter from the URL
91
     * and use that to look up a record.
92
     */
93
    public function __construct($dataRecord = null)
94
    {
95
        if (!$dataRecord) {
96
            $dataRecord = new CatalogueCategory();
97
            if ($this->hasMethod("Title")) {
98
                $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

98
                /** @scrutinizer ignore-call */ 
99
                $dataRecord->Title = $this->Title();
Loading history...
99
            }
100
            $dataRecord->URLSegment = get_class($this);
101
            $dataRecord->ID = -1;
102
        }
103
        
104
        parent::__construct($dataRecord);
105
    }
106
107
    protected function init()
108
    {
109
        parent::init();
110
111
        // Check for subsites and add support
112
        if (class_exists(Subsite::class)) {
113
            $subsite = Subsite::currentSubsite();
114
115
            if ($subsite && $subsite->Theme) {
116
                SSViewer::add_themes([$subsite->Theme]);
117
            }
118
119
            if ($subsite && i18n::getData()->validate($subsite->Language)) {
120
                i18n::set_locale($subsite->Language);
121
            }
122
        }
123
    }
124
125
    /**
126
     * The productimage action is used to determine the default image that will
127
     * appear related to a product
128
     *
129
     * @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...
130
     */
131
    public function ProductImage()
132
    {
133
        $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

133
        $image = $this->/** @scrutinizer ignore-call */ SortedImages()->first();
Loading history...
134
            
135
        $this->extend("updateProductImage", $image);
136
137
        return $image;
138
    }
139
140
    /**
141
     * Return the title, description, keywords and language metatags.
142
     * NOTE: Shamelessley taken from SiteTree
143
     *
144
     * @param bool $includeTitle Show default <title>-tag, set to false for custom templating
145
     *
146
     * @return string The XHTML metatags
147
     */
148
    public function MetaTags($includeTitle = true)
149
    {
150
        $tags = [];
151
152
        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 $str 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

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