Passed
Push — master ( b86afc...725f43 )
by Sebastian
03:04
created

Date::prepareDatePartsInVariable()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 18
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 18
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 6
nc 3
nop 2
1
<?php
2
/*
3
 * citeproc-php
4
 *
5
 * @link        http://github.com/seboettg/citeproc-php for the source repository
6
 * @copyright   Copyright (c) 2016 Sebastian Böttger.
7
 * @license     https://opensource.org/licenses/MIT
8
 */
9
10
namespace Seboettg\CiteProc\Rendering\Date;
11
12
use Seboettg\CiteProc\CiteProc;
13
use Seboettg\CiteProc\Exception\CiteProcException;
14
use Seboettg\CiteProc\Styles\AffixesTrait;
15
use Seboettg\CiteProc\Styles\DisplayTrait;
16
use Seboettg\CiteProc\Styles\FormattingTrait;
17
use Seboettg\CiteProc\Styles\TextCaseTrait;
18
use Seboettg\CiteProc\Util;
19
use Seboettg\Collection\ArrayList;
20
21
22
/**
23
 * Class Date
24
 * @package Seboettg\CiteProc\Rendering
25
 *
26
 * @author Sebastian Böttger <[email protected]>
27
 */
28
class Date
29
{
30
31
    use AffixesTrait,
32
        DisplayTrait,
33
        FormattingTrait,
34
        TextCaseTrait;
35
36
    // ymd
37
    const DATE_RANGE_STATE_NONE         = 0; // 000
38
    const DATE_RANGE_STATE_DAY          = 1; // 001
39
    const DATE_RANGE_STATE_MONTH        = 2; // 010
40
    const DATE_RANGE_STATE_MONTHDAY     = 3; // 011
41
    const DATE_RANGE_STATE_YEAR         = 4; // 100
42
    const DATE_RANGE_STATE_YEARDAY      = 5; // 101
43
    const DATE_RANGE_STATE_YEARMONTH    = 6; // 110
44
    const DATE_RANGE_STATE_YEARMONTHDAY = 7; // 111
45
46
    private static $localizedDateFormats = [
47
        'numeric',
48
        'text'
49
    ];
50
51
    /**
52
     * @var ArrayList
53
     */
54
    private $dateParts;
55
56
    /**
57
     * @var string
58
     */
59
    private $form = "";
60
61
    /**
62
     * @var string
63
     */
64
    private $variable = "";
65
66
    /**
67
     * @var string
68
     */
69
    private $datePartsAttribute = "";
70
71
    public function __construct(\SimpleXMLElement $node)
72
    {
73
        $this->dateParts = new ArrayList();
74
75
        /** @var \SimpleXMLElement $attribute */
76 View Code Duplication
        foreach ($node->attributes() as $attribute) {
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...
77
            switch ($attribute->getName()) {
78
                case 'form':
79
                    $this->form = (string) $attribute;
80
                    break;
81
                case 'variable':
82
                    $this->variable = (string) $attribute;
83
                    break;
84
                case 'date-parts':
85
                    $this->datePartsAttribute = (string) $attribute;
86
            }
87
        }
88
        /** @var \SimpleXMLElement $child */
89
        foreach ($node->children() as $child) {
90
            if ($child->getName() === "date-part") {
91
                $datePartName = (string) $child->attributes()["name"];
92
                $this->dateParts->set($this->form . "-" . $datePartName, Util\Factory::create($child));
93
            }
94
        }
95
96
        $this->initAffixesAttributes($node);
97
        $this->initDisplayAttributes($node);
98
        $this->initFormattingAttributes($node);
99
        $this->initTextCaseAttributes($node);
100
    }
101
102
    /**
103
     * @param $data
104
     * @return string
105
     */
106
    public function render($data)
107
    {
108
        $ret = "";
109
        $var = null;
0 ignored issues
show
Unused Code introduced by
$var 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...
110
        if (isset($data->{$this->variable})) {
111
            $var = $data->{$this->variable};
112
        } else {
113
            return "";
114
        }
115
116
        try {
117
            $this->prepareDatePartsInVariable($data, $var);
118
        } catch (CiteProcException $e) {
119
            if (!preg_match("/(\p{L}+)\s?([\-\-\&,])\s?(\p{L}+)/u", $data->{$this->variable}->raw)) {
120
                return $this->addAffixes($this->format($this->applyTextCase($data->{$this->variable}->raw)));
121
            }
122
        }
123
124
        $form = $this->form;
125
        $dateParts = explode("-", $this->datePartsAttribute);
126
        $this->prepareDatePartsChildren($dateParts, $form);
127
128
129
        // No date-parts in date-part attribute defined, take into account that the defined date-part children will be used.
130
        if (empty($this->datePartsAttribute) && $this->dateParts->count() > 0) {
131
            /** @var DatePart $part */
132
            foreach ($this->dateParts as $part) {
133
                $dateParts[] = $part->getName();
134
            }
135
        }
136
137
        /* cs:date may have one or more cs:date-part child elements (see Date-part). The attributes set on
138
        these elements override those specified for the localized date formats (e.g. to get abbreviated months for all
139
        locales, the form attribute on the month-cs:date-part element can be set to “short”). These cs:date-part
140
        elements do not affect which, or in what order, date parts are rendered. Affixes, which are very
141
        locale-specific, are not allowed on these cs:date-part elements. */
142
143
        if ($this->dateParts->count() > 0) {
144
145
            /* if (isset($var->raw) && !preg_match("/(\p{L}+)\s?([\-\-\&,])\s?(\p{L}+)/u", $var->raw) && $this->dateParts->count() > 0) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
61% 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...
146
                //$var->{"date-parts"} = [];
147
            } else*/
148
            if (!isset($var->{'date-parts'})) { // ignore empty date-parts
149
                return "";
150
            }
151
152
            if (count($data->{$this->variable}->{'date-parts'}) === 1) {
153
                $data_ = $this->createDateTime($data->{$this->variable}->{'date-parts'});
154
                /** @var DatePart $datePart */
155
                foreach ($this->dateParts as $key => $datePart) {
156
                    list($f, $p) = explode("-", $key);
0 ignored issues
show
Unused Code introduced by
The assignment to $f is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
157
                    if (in_array($p, $dateParts)) {
158
                        $ret .= $datePart->render($data_[0], $this);
159
                    }
160
                }
161
            } else if (count($var->{'date-parts'}) === 2) { //date range
162
                $data_ = $this->createDateTime($var->{'date-parts'});
163
                $from = $data_[0];
164
                $to = $data_[1];
165
                $interval = $to->diff($from);
166
                $delim = "";
167
                $toRender = 0;
168
                if ($interval->y > 0) {
169
                    $toRender |= self::DATE_RANGE_STATE_YEAR;
170
                    $delim = $this->dateParts->get($this->form . "-year")->getRangeDelimiter();
171
                }
172
                if ($interval->m > 0 && $from->getMonth() - $to->getMonth() !== 0) {
173
                    $toRender |= self::DATE_RANGE_STATE_MONTH;
174
                    $delim = $this->dateParts->get($this->form . "-month")->getRangeDelimiter();
175
                }
176
                if ($interval->d > 0 && $from->getDay() - $to->getDay() !== 0) {
177
                    $toRender |= self::DATE_RANGE_STATE_DAY;
178
                    $delim = $this->dateParts->get($this->form . "-day")->getRangeDelimiter();
179
                }
180
181
                $ret = $this->renderDateRange($toRender, $from, $to, $delim);
182
            }
183
184
            if (isset($var->raw) && preg_match("/(\p{L}+)\s?([\-\-\&,])\s?(\p{L}+)/u", $var->raw, $matches)) {
185
                return $matches[1] . $matches[2] . $matches[3];
186
            }
187
        }
188
        // fallback:
189
        // When there are no dateParts children, but date-parts attribute in date
190
        // render numeric
191
        else if (!empty($this->datePartsAttribute)) {
192
            $data = $this->createDateTime($var->{'date-parts'});
193
            $ret = $this->renderNumeric($data[0]);
194
        }
195
196
        return !empty($ret) ? $this->addAffixes($this->format($this->applyTextCase($ret))) : "";
197
    }
198
199
    private function renderNumeric(DateTime $date)
200
    {
201
        return $date->renderNumeric();
202
    }
203
204
    public function getForm()
205
    {
206
        return $this->form;
207
    }
208
209
    private function createDateTime($dates)
210
    {
211
        $data = [];
212
        foreach ($dates as $date) {
213
            if ($date[0] < 1000) {
214
                $dateTime = new DateTime(0, 0, 0);
0 ignored issues
show
Documentation introduced by
0 is of type integer, but the function expects a object<DateTimeZone>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
215
                $dateTime->setDay(0)->setMonth(0)->setYear(0);
216
                $data[] = $dateTime;
217
            }
218
            $dateTime = new DateTime($date[0], array_key_exists(1, $date) ? $date[1] : 1, array_key_exists(2, $date) ? $date[2] : 1);
219
            if (!array_key_exists(1, $date)) {
220
                $dateTime->setMonth(0);
221
            }
222
            if (!array_key_exists(2, $date)) {
223
                $dateTime->setDay(0);
224
            }
225
            $data[] = $dateTime;
226
        }
227
228
        return $data;
229
    }
230
231
    /**
232
     * @param $differentParts
233
     * @param DateTime $from
234
     * @param DateTime $to
235
     * @param $delim
236
     * @return string
237
     */
238
    private function renderDateRange($differentParts, DateTime $from, DateTime $to, $delim)
239
    {
240
        $ret = "";
241
        switch ($differentParts) {
242
            case Date::DATE_RANGE_STATE_YEAR:
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
243
                foreach ($this->dateParts as $key => $datePart) {
244
                    if (strpos($key, "year") !== false) {
245
                        $ret .= $this->renderOneRangePart($datePart, $from, $to, $delim);
246
                    }
247
                    if (strpos($key, "month") !== false) {
248
                        $day = !empty($d = $from->getMonth()) ? $d : "";
249
                        $ret .= $day;
250
                    }
251 View Code Duplication
                    if (strpos($key, "day") !== false) {
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...
252
                        $day = !empty($d = $from->getDay()) ? $datePart->render($from, $this) : "";
253
                        $ret .= $day;
254
                    }
255
                }
256
                break;
257
            case Date::DATE_RANGE_STATE_MONTH:
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
258
                /**
259
                 * @var string $key
260
                 * @var DatePart $datePart
261
                 */
262
                foreach ($this->dateParts as $key => $datePart) {
263
                    if (strpos($key, "year") !== false) {
264
                        $ret .= $datePart->render($from, $this);
265
                    }
266
                    if (strpos($key, "month")) {
267
                        $ret .= $this->renderOneRangePart($datePart, $from, $to, $delim);
268
                    }
269 View Code Duplication
                    if (strpos($key, "day") !== false) {
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...
270
                        $day = !empty($d = $from->getDay()) ? $datePart->render($from, $this) : "";
271
                        $ret .= $day;
272
                    }
273
                }
274
                break;
275
            case Date::DATE_RANGE_STATE_DAY:
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
276
                /**
277
                 * @var string $key
278
                 * @var DatePart $datePart
279
                 */
280
                foreach ($this->dateParts as $key => $datePart) {
281
                    if (strpos($key, "year") !== false) {
282
                        $ret .= $datePart->render($from, $this);
283
                    }
284
                    if (strpos($key, "month") !== false) {
285
                        $ret .= $datePart->render($from, $this);
286
                    }
287
                    if (strpos($key, "day")) {
288
                        $ret .= $this->renderOneRangePart($datePart, $from, $to, $delim);
289
                    }
290
                }
291
                break;
292
            case Date::DATE_RANGE_STATE_YEARMONTHDAY:
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
293
                $i = 0;
294 View Code Duplication
                foreach ($this->dateParts as $datePart) {
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...
295
                    if ($i === $this->dateParts->count() - 1) {
296
                        $ret .= $datePart->renderPrefix();
297
                        $ret .= $datePart->renderWithoutAffixes($from, $this);
298
                    } else {
299
                        $ret .= $datePart->render($from, $this);
300
                    }
301
                    ++$i;
302
                }
303
                $ret .= $delim;
304
                $i = 0;
305 View Code Duplication
                foreach ($this->dateParts as $datePart) {
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...
306
                    if ($i == 0) {
307
                        $ret .= $datePart->renderWithoutAffixes($to, $this);
308
                        $ret .= $datePart->renderSuffix();
309
                    } else {
310
                        $ret .= $datePart->render($to, $this);
311
                    }
312
                    ++$i;
313
                }
314
                break;
315 View Code Duplication
            case Date::DATE_RANGE_STATE_YEARMONTH:
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...
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
316
                $dp = $this->dateParts->toArray();
317
                $i = 0;
318
                $dateParts_ = [];
319
                array_walk($dp, function($datePart, $key) use (&$i, &$dateParts_, $differentParts) {
320
                    if (strpos($key, "year") !== false || strpos($key, "month") !== false) {
321
                        $dateParts_["yearmonth"][] = $datePart;
322
                    }
323
                    if (strpos($key, "day") !== false) {
324
                        $dateParts_["day"] = $datePart;
325
                    }
326
                });
327
                break;
328 View Code Duplication
            case Date::DATE_RANGE_STATE_YEARDAY:
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...
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
329
                $dp = $this->dateParts->toArray();
330
                $i = 0;
331
                $dateParts_ = [];
332
                array_walk($dp, function($datePart, $key) use (&$i, &$dateParts_, $differentParts) {
333
                    if (strpos($key, "year") !== false || strpos($key, "day") !== false) {
334
                        $dateParts_["yearday"][] = $datePart;
335
                    }
336
                    if (strpos($key, "month") !== false) {
337
                        $dateParts_["month"] = $datePart;
338
                    }
339
                });
340
                break;
341 View Code Duplication
            case Date::DATE_RANGE_STATE_MONTHDAY:
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...
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
342
                $dp = $this->dateParts->toArray();
343
                $i = 0;
344
                $dateParts_ = [];
345
                array_walk($dp, function($datePart, $key) use (&$i, &$dateParts_, $differentParts) {
346
                    //$bit = sprintf("%03d", decbin($differentParts));
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% 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...
347
                    if (strpos($key, "month") !== false || strpos($key, "day") !== false) {
348
                        $dateParts_["monthday"][] = $datePart;
349
                    }
350
                    if (strpos($key, "year") !== false) {
351
                        $dateParts_["year"] = $datePart;
352
                    }
353
                });
354
                break;
355
        }
356
        switch ($differentParts) {
357
            case Date::DATE_RANGE_STATE_YEARMONTH:
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
358
            case Date::DATE_RANGE_STATE_YEARDAY:
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
359
            case Date::DATE_RANGE_STATE_MONTHDAY:
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
360
                /**
361
                 * @var $key
362
                 * @var DatePart $datePart */
363
                foreach ($dateParts_ as $key => $datePart) {
0 ignored issues
show
Bug introduced by
The variable $dateParts_ does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
364
                    if (is_array($datePart)) {
365
366
                        $f  = $datePart[0]->render($from, $this);
367
                        $f .= $datePart[1]->renderPrefix();
368
                        $f .= $datePart[1]->renderWithoutAffixes($from, $this);
369
                        $t  = $datePart[0]->renderWithoutAffixes($to, $this);
370
                        $t .= $datePart[0]->renderSuffix();
371
                        $t .= $datePart[1]->render($to, $this);
372
                        $ret .= $f . $delim . $t;
373
                    } else {
374
                        $ret .= $datePart->render($from, $this);
375
                    }
376
                }
377
                break;
378
        }
379
        return $ret;
380
    }
381
382
    /**
383
     * @param $datePart
384
     * @param DateTime $from
385
     * @param DateTime $to
386
     * @param $delim
387
     * @return string
388
     */
389
    protected function renderOneRangePart(DatePart $datePart, $from, $to, $delim)
390
    {
391
        $prefix = $datePart->renderPrefix();
392
        $from = $datePart->renderWithoutAffixes($from, $this);
393
        $to = $datePart->renderWithoutAffixes($to, $this);
394
        $suffix = !empty($to) ? $datePart->renderSuffix() : "";
395
        return $prefix . $from . $delim . $to . $suffix;
396
    }
397
398
    /**
399
     * @param string $format
400
     * @return bool
401
     */
402
    private function hasDatePartsFromLocales($format)
403
    {
404
        $dateXml = CiteProc::getContext()->getLocale()->getDateXml();
405
        return !empty($dateXml[$format]);
406
    }
407
408
    /**
409
     * @param string $format
410
     * @return array
411
     */
412
    private function getDatePartsFromLocales($format)
413
    {
414
        $ret = [];
415
        // date parts from locales
416
        $dateFromLocale_ = CiteProc::getContext()->getLocale()->getDateXml();
417
        $dateFromLocale = $dateFromLocale_[$format];
418
419
        // no custom date parts within the date element (this)?
420
        if (!empty($dateFromLocale)) {
421
422
            $dateForm = array_filter(is_array($dateFromLocale) ? $dateFromLocale : [$dateFromLocale], function($element) use ($format) {
423
                /** @var \SimpleXMLElement $element */
424
                $dateForm = (string) $element->attributes()["form"];
425
                return $dateForm === $format;
426
            });
427
428
            //has dateForm from locale children (date-part elements)?
429
            $localeDate = array_pop($dateForm);
430
431
            if ($localeDate instanceof \SimpleXMLElement && $localeDate->count() > 0) {
432
                foreach ($localeDate as $child) {
433
                    $ret[] = $child;
434
                }
435
            }
436
        }
437
        return $ret;
438
    }
439
440
    /**
441
     * @return string
442
     */
443
    public function getVariable()
444
    {
445
        return $this->variable;
446
    }
447
448
    /**
449
     * @param $data
450
     * @param $var
451
     * @throws CiteProcException
452
     */
453
    private function prepareDatePartsInVariable($data, $var)
454
    {
455
        if (!isset($data->{$this->variable}->{'date-parts'}) || empty($data->{$this->variable}->{'date-parts'})) {
456
            if (isset($data->{$this->variable}->raw) && !empty($data->{$this->variable}->raw)) {
457
                //try {
458
                // try to parse date parts from "raw" attribute
459
                $var->{'date-parts'} = Util\Date::parseDateParts($data->{$this->variable});
460
                //} catch (CiteProcException $e) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% 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...
461
                //    if (!preg_match("/(\p{L}+)\s?([\-\-\&,])\s?(\p{L}+)/u", $data->{$this->variable}->raw)) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% 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...
462
                //        return $this->addAffixes($this->format($this->applyTextCase($data->{$this->variable}->raw)));
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% 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...
463
                //    }
464
                //}
465
            } else {
466
                throw new CiteProcException("No valid date format");
467
                //return "";
468
            }
469
        }
470
    }
471
472
    private function prepareDatePartsChildren($dateParts, $form)
473
    {
474
        /* Localized date formats are selected with the optional form attribute, which must set to either “numeric”
475
        (for fully numeric formats, e.g. “12-15-2005”), or “text” (for formats with a non-numeric month, e.g.
476
        “December 15, 2005”). Localized date formats can be customized in two ways. First, the date-parts attribute may
477
        be used to show fewer date parts. The possible values are:
478
            - “year-month-day” - (default), renders the year, month and day
479
            - “year-month” - renders the year and month
480
            - “year” - renders the year */
481
482
        if ($this->dateParts->count() < 1 && in_array($form, self::$localizedDateFormats)) {
483
            if ($this->hasDatePartsFromLocales($form)) {
484
                $datePartsFromLocales = $this->getDatePartsFromLocales($form);
485
                array_filter($datePartsFromLocales, function(\SimpleXMLElement $item) use ($dateParts) {
486
                    return in_array($item["name"], $dateParts);
487
                });
488
489
                foreach ($datePartsFromLocales as $datePartNode) {
490
                    $datePart = $datePartNode["name"];
491
                    $this->dateParts->set("$form-$datePart", Util\Factory::create($datePartNode));
492
                }
493
            } else { //otherwise create default date parts
494
                foreach ($dateParts as $datePart) {
495
                    $this->dateParts->add("$form-$datePart", new DatePart(new \SimpleXMLElement('<date-part name="' . $datePart . '" form="' . $form . '" />')));
496
                }
497
            }
498
        }
499
    }
500
}