Completed
Pull Request — master (#13)
by Robbie
02:33
created

DatedUpdateHolderController::parseParams()   F

Complexity

Conditions 20
Paths 18432

Size

Total Lines 83
Code Lines 44

Duplication

Lines 12
Ratio 14.46 %

Importance

Changes 0
Metric Value
cc 20
eloc 44
nc 18432
nop 1
dl 12
loc 83
rs 2.0926
c 0
b 0
f 0

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
namespace CWP\CWP\PageTypes;
4
5
use CWP\Core\Feed\CwpAtomFeed;
6
use PageController;
0 ignored issues
show
Bug introduced by
The type PageController 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...
7
use SilverStripe\Control\Director;
8
use SilverStripe\Control\HTTP;
9
use SilverStripe\Control\RSS\RSSFeed;
10
use SilverStripe\Core\Config\Config;
11
use SilverStripe\Forms\DateField;
12
use SilverStripe\Forms\FieldList;
13
use SilverStripe\Forms\Form;
14
use SilverStripe\Forms\FormAction;
15
use SilverStripe\Forms\HiddenField;
16
use SilverStripe\ORM\FieldType\DBDatetime;
17
use SilverStripe\ORM\FieldType\DBField;
18
use SilverStripe\ORM\PaginatedList;
19
use SilverStripe\Taxonomy\TaxonomyTerm;
20
21
/**
22
 * The parameters apply in the following preference order:
23
 *  - Highest priority: Tag & date (or date range)
24
 *  - Month (and Year)
25
 *  - Pagination
26
 *
27
 * So, when the user click on a tag link, the pagination, and month will be reset, but not the date filter. Also,
28
 * changing the date will not affect the tag, but will reset the month and pagination.
29
 *
30
 * When the user clicks on a month, pagination will be reset, but tags retained. Pagination retains all other
31
 * parameters.
32
 */
33
class DatedUpdateHolderController extends PageController
34
{
35
    private static $allowed_actions = [
0 ignored issues
show
introduced by
The private property $allowed_actions is not used, and could be removed.
Loading history...
36
        'rss',
37
        'atom',
38
        'DateRangeForm',
39
    ];
40
41
    private static $casting = [
0 ignored issues
show
introduced by
The private property $casting is not used, and could be removed.
Loading history...
42
        'MetaTitle' => 'Text',
43
        'FilterDescription' => 'Text',
44
    ];
45
46
    /**
47
     * Get the meta title for the current action
48
     *
49
     * @return string
50
     */
51
    public function getMetaTitle()
52
    {
53
        $title = $this->data()->getTitle();
54
        $filter = $this->FilterDescription();
55
        if ($filter) {
56
            $title = "{$title} - {$filter}";
57
        }
58
59
        $this->extend('updateMetaTitle', $title);
60
        return $title;
61
    }
62
63
    /**
64
     * Returns a description of the current filter
65
     *
66
     * @return string
67
     */
68
    public function FilterDescription()
69
    {
70
        $params = $this->parseParams();
71
72
        $filters = array();
73
        if ($params['tag']) {
74
            $term = TaxonomyTerm::get_by_id(TaxonomyTerm::class, $params['tag']);
75
            if ($term) {
76
                $filters[] = _t('DatedUpdateHolder.FILTER_WITHIN', 'within') . ' "' . $term->Name . '"';
77
            }
78
        }
79
80
        if ($params['from'] || $params['to']) {
81
            if ($params['from']) {
82
                $from = strtotime($params['from']);
83
                if ($params['to']) {
84
                    $to = strtotime($params['to']);
85
                    $filters[] = _t('DatedUpdateHolder.FILTER_BETWEEN', 'between') . ' '
86
                        . date('j/m/Y', $from) . ' and ' . date('j/m/Y', $to);
87
                } else {
88
                    $filters[] = _t('DatedUpdateHolder.FILTER_ON', 'on') . ' ' . date('j/m/Y', $from);
89
                }
90
            } else {
91
                $to = strtotime($params['to']);
92
                $filters[] = _t('DatedUpdateHolder.FILTER_ON', 'on') . ' ' . date('j/m/Y', $to);
93
            }
94
        }
95
96
        if ($params['year'] && $params['month']) {
97
            $timestamp = mktime(1, 1, 1, $params['month'], 1, $params['year']);
98
            $filters[] = _t('DatedUpdateHolder.FILTER_IN', 'in') . ' ' . date('F', $timestamp) . ' ' . $params['year'];
99
        }
100
101
        if ($filters) {
102
            return $this->getUpdateName() . ' ' . implode(' ', $filters);
103
        }
104
    }
105
106
    public function getUpdateName()
107
    {
108
        return Config::inst()->get($this->data()->ClassName, 'update_name');
109
    }
110
111
    protected function init()
112
    {
113
        parent::init();
114
        RSSFeed::linkToFeed($this->Link() . 'rss', $this->getSubscriptionTitle());
115
    }
116
117
    /**
118
     * Parse URL parameters.
119
     *
120
     * @param bool $produceErrorMessages Set to false to omit session messages.
121
     */
122
    public function parseParams($produceErrorMessages = true)
123
    {
124
        $tag = $this->request->getVar('tag');
125
        $from = $this->request->getVar('from');
126
        $to = $this->request->getVar('to');
127
        $year = $this->request->getVar('year');
128
        $month = $this->request->getVar('month');
129
130
        if ($tag == '') {
131
            $tag = null;
132
        }
133
        if ($from == '') {
134
            $from = null;
135
        }
136
        if ($to == '') {
137
            $to = null;
138
        }
139
        if ($year == '') {
140
            $year = null;
141
        }
142
        if ($month == '') {
143
            $month = null;
144
        }
145
146
        if (isset($tag)) {
147
            $tag = (int)$tag;
148
        }
149 View Code Duplication
        if (isset($from)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
150
            $from = urldecode($from);
151
            $parser = DBDatetime::create();
152
            $parser->setValue($from);
153
            $from = $parser->Format('y-MM-dd');
154
        }
155 View Code Duplication
        if (isset($to)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
156
            $to = urldecode($to);
157
            $parser = DBDatetime::create();
158
            $parser->setValue($to);
159
            $to = $parser->Format('y-MM-dd');
160
        }
161
        if (isset($year)) {
162
            $year = (int)$year;
163
        }
164
        if (isset($month)) {
165
            $month = (int)$month;
166
        }
167
168
        // If only "To" has been provided filter by single date. Normalise by swapping with "From".
169
        if (isset($to) && !isset($from)) {
170
            list($to, $from) = array($from, $to);
171
        }
172
173
        // Flip the dates if the order is wrong.
174
        if (isset($to) && isset($from) && strtotime($from)>strtotime($to)) {
175
            list($to, $from) = array($from, $to);
176
177
            if ($produceErrorMessages) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
178
                // @todo replace
0 ignored issues
show
Unused Code Comprehensibility introduced by
42% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
179
//                Session::setFormMessage(
180
//                    'Form_DateRangeForm',
181
//                    _t('DateUpdateHolder.FilterAppliedMessage', 'Filter has been applied with the dates reversed.'),
182
//                    'warning'
183
//                );
184
            }
185
        }
186
187
        // Notify the user that filtering by single date is taking place.
188
        if (isset($from) && !isset($to)) {
189
            if ($produceErrorMessages) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
190
                // @todo replace
0 ignored issues
show
Unused Code Comprehensibility introduced by
42% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
191
//                Session::setFormMessage(
192
//                    'Form_DateRangeForm',
193
//                    _t('DateUpdateHolder.DateRangeFilterMessage', 'Filtered by a single date.'),
194
//                    'warning'
195
//                );
196
            }
197
        }
198
199
        return [
200
            'tag' => $tag,
201
            'from' => $from,
202
            'to' => $to,
203
            'year' => $year,
204
            'month' => $month,
205
        ];
206
    }
207
208
    /**
209
     * Build the link - keep the date range, reset the rest.
210
     */
211
    public function AllTagsLink()
212
    {
213
        $link = HTTP::setGetVar('tag', null, null, '&');
214
        $link = HTTP::setGetVar('month', null, $link, '&');
215
        $link = HTTP::setGetVar('year', null, $link, '&');
216
        $link = HTTP::setGetVar('start', null, $link, '&');
217
218
        return $link;
219
    }
220
221
    /**
222
     * List tags and attach links.
223
     */
224
    public function UpdateTagsWithLinks()
225
    {
226
        $tags = $this->UpdateTags();
227
228
        $processed = ArrayList::create();
0 ignored issues
show
Bug introduced by
The type CWP\CWP\PageTypes\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...
229
230
        foreach ($tags as $tag) {
231
            // Build the link - keep the tag, and date range, but reset month, year and pagination.
232
            $link = HTTP::setGetVar('tag', $tag->ID, null, '&');
233
            $link = HTTP::setGetVar('month', null, $link, '&');
234
            $link = HTTP::setGetVar('year', null, $link, '&');
235
            $link = HTTP::setGetVar('start', null, $link, '&');
236
237
            $tag->Link = $link;
238
            $processed->push($tag);
239
        }
240
241
        return $processed;
242
    }
243
244
    /**
245
     * Get the TaxonomyTerm related to the current tag GET parameter.
246
     */
247
    public function CurrentTag()
248
    {
249
        $tagID = $this->request->getVar('tag');
250
251
        if (isset($tagID)) {
252
            return TaxonomyTerm::get_by_id(TaxonomyTerm::class, (int)$tagID);
253
        }
254
    }
255
256
    /**
257
     * Extract the available months based on the current query.
258
     * Only tag is respected. Pagination and months are ignored.
259
     */
260
    public function AvailableMonths()
261
    {
262
        $params = $this->parseParams();
263
264
        return DatedUpdateHolder::ExtractMonths(
265
            $this->Updates($params['tag'], $params['from'], $params['to']),
266
            Director::makeRelative($_SERVER['REQUEST_URI']),
267
            $params['year'],
268
            $params['month']
269
        );
270
    }
271
272
    /**
273
     * Get the updates based on the current query.
274
     */
275
    public function FilteredUpdates($pageSize = 20)
276
    {
277
        $params = $this->parseParams();
278
279
        $items = $this->Updates(
280
            $params['tag'],
281
            $params['from'],
282
            $params['to'],
283
            $params['year'],
284
            $params['month']
285
        );
286
287
        // Apply pagination
288
        $list = PaginatedList::create($items, $this->getRequest());
289
        $list->setPageLength($pageSize);
290
        return $list;
291
    }
292
293
    /**
294
     * @return Form
295
     */
296
    public function DateRangeForm()
297
    {
298
        $dateFromTitle = DBField::create_field('HTMLText', sprintf(
299
            '%s <span class="field-note">%s</span>',
300
            _t('DatedUpdateHolder.FROM_DATE', 'From date'),
301
            _t('DatedUpdateHolder.DATE_EXAMPLE', '(example: 2017/12/30)')
302
        ));
303
        $dateToTitle = DBField::create_field('HTMLText', sprintf(
304
            '%s <span class="field-note">%s</span>',
305
            _t('DatedUpdateHolder.TO_DATE', 'To date'),
306
            _t('DatedUpdateHolder.DATE_EXAMPLE', '(example: 2017/12/30)')
307
        ));
308
309
        $fields = FieldList::create(
310
            DateField::create('from', $dateFromTitle),
0 ignored issues
show
Bug introduced by
$dateFromTitle of type SilverStripe\ORM\FieldType\DBField is incompatible with the type array expected by parameter $args of SilverStripe\View\ViewableData::create(). ( Ignorable by Annotation )

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

310
            DateField::create('from', /** @scrutinizer ignore-type */ $dateFromTitle),
Loading history...
Bug introduced by
'from' of type string is incompatible with the type array expected by parameter $args of SilverStripe\View\ViewableData::create(). ( Ignorable by Annotation )

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

310
            DateField::create(/** @scrutinizer ignore-type */ 'from', $dateFromTitle),
Loading history...
311
            DateField::create('to', $dateToTitle),
312
            HiddenField::create('tag')
313
        );
314
315
        $actions = FieldList::create(
316
            FormAction::create("doDateFilter")->setTitle("Filter")->addExtraClass('btn btn-primary primary'),
317
            FormAction::create("doDateReset")->setTitle("Clear")->addExtraClass('btn')
318
        );
319
320
        $form = Form::create($this, 'DateRangeForm', $fields, $actions);
0 ignored issues
show
Bug introduced by
$this of type CWP\CWP\PageTypes\DatedUpdateHolderController is incompatible with the type array expected by parameter $args of SilverStripe\View\ViewableData::create(). ( Ignorable by Annotation )

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

320
        $form = Form::create(/** @scrutinizer ignore-type */ $this, 'DateRangeForm', $fields, $actions);
Loading history...
321
        $form->loadDataFrom($this->request->getVars());
322
        $form->setFormMethod('get');
323
324
        // Manually extract the message so we can clear it.
325
        $form->ErrorMessage = $form->getMessage();
326
        $form->ErrorMessageType = $form->getMessageType();
327
        $form->clearMessage();
328
329
        return $form;
330
    }
331
332
    public function doDateFilter()
333
    {
334
        $params = $this->parseParams();
335
336
        // Build the link - keep the tag, but reset month, year and pagination.
337
        $link = HTTP::setGetVar('from', $params['from'], $this->AbsoluteLink(), '&');
338
        $link = HTTP::setGetVar('to', $params['to'], $link, '&');
339
        if (isset($params['tag'])) {
340
            $link = HTTP::setGetVar('tag', $params['tag'], $link, '&');
341
        }
342
343
        $this->redirect($link);
344
    }
345
346
    public function doDateReset()
347
    {
348
        $params = $this->parseParams(false);
349
350
        // Reset the link - only include the tag.
351
        $link = $this->AbsoluteLink();
352
        if (isset($params['tag'])) {
353
            $link = HTTP::setGetVar('tag', $params['tag'], $link, '&');
354
        }
355
356
        $this->redirect($link);
357
    }
358
359
    public function rss()
360
    {
361
        $rss = RSSFeed::create(
362
            $this->Updates()->sort('Created DESC')->limit(20),
363
            $this->Link('rss'),
364
            $this->getSubscriptionTitle()
365
        );
366
        return $rss->outputToBrowser();
367
    }
368
369 View Code Duplication
    public function atom()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
370
    {
371
        $atom = CwpAtomFeed::create(
372
            $this->Updates()->sort('Created DESC')->limit(20),
373
            $this->Link('atom'),
374
            $this->getSubscriptionTitle()
375
        );
376
        return $atom->outputToBrowser();
377
    }
378
}
379