Completed
Push — master ( 2af2d7...ce9658 )
by Kirill
02:09
created

Controller::diff()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 0
cts 9
cp 0
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 7
nc 2
nop 1
crap 6
1
<?php
2
/**
3
 * This file is part of Railt package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
declare(strict_types=1);
9
10
namespace Railt\CarbonExtension;
11
12
use Carbon\Carbon;
13
use Railt\CarbonExtension\Exception\InvalidDateTimeFormat;
14
use Railt\Http\InputInterface;
15
16
/**
17
 * Class Controller
18
 */
19
class Controller
20
{
21
    /**
22
     * Simple Date format.
23
     * Example: `2005-08-15`
24
     */
25
    private const DATE = 'DATE';
26
27
    /**
28
     * Simple Time format.
29
     * Example: `15:52:01`
30
     */
31
    private const TIME = 'TIME';
32
33
    /**
34
     * Simple DateTime format.
35
     * Example: `2005-08-15 15:52:01`
36
     */
37
    private const DATE_TIME = 'DATE_TIME';
38
39
    /**
40
     * RFC 7231 date format.
41
     * Example: `Mon, 15 Aug 2005 15:52:01 GMT`
42
     */
43
    private const RFC7231 = 'RFC7231';
44
45
    /**
46
     * ISO-8601 date format.
47
     * Example: `2005-08-15T15:52:01+00:00`
48
     *
49
     * Note: This format is an alias of the RFC 3339 specification:
50
     * @see https://www.iso.org/iso-8601-date-and-time-format.html
51
     * @see https://www.ietf.org/rfc/rfc3339.txt
52
     */
53
    private const ISO8601 = 'ISO8601';
54
55
    /**
56
     * Human readable string.
57
     * Example: `2 days ago`
58
     */
59
    private const HUMAN_READABLE = 'HUMAN_READABLE';
60
61
    /**
62
     * @param InputInterface $input
63
     * @return string
64
     * @throws \InvalidArgumentException
65
     */
66
    public function getDateTime(InputInterface $input): string
67
    {
68
        return $this->format($this->extract($input), $input->get('format'));
69
    }
70
71
    /**
72
     * @param \DateTimeInterface|\DateInterval $date
73
     * @param string $format
74
     * @return string
75
     * @throws \InvalidArgumentException
76
     * @throws \Symfony\Component\Translation\Exception\InvalidArgumentException
77
     */
78
    private function format($date, string $format): string
79
    {
80
        switch ($format) {
81
            /**
82
             * Compatibility bugfix.
83
             * @see http://php.net/manual/en/class.datetime.php
84
             */
85
            case self::ISO8601:
86
                return $date->format(Carbon::RFC3339);
87
88
            case self::RFC7231:
89
                return $date->format(Carbon::RFC7231_FORMAT);
90
91
            case self::DATE_TIME:
92
                return $date->format('Y-m-d H:i:s');
93
94
            case self::DATE:
95
                return $date->format('Y-m-d');
96
97
            case self::TIME:
98
                return $date->format('H:i:s');
99
100
            case self::HUMAN_READABLE && $date instanceof \DateTimeInterface:
101
                return Carbon::instance($date)->diffForHumans();
0 ignored issues
show
Bug introduced by
It seems like $date defined by parameter $date on line 78 can also be of type object<DateInterval>; however, Carbon\Carbon::instance() does only seem to accept object<DateTimeInterface>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
102
        }
103
104
        return $date->format(\constant(Carbon::class . '::' . $format));
105
    }
106
107
    /**
108
     * @param InputInterface $input
109
     * @return Carbon
110
     * @throws \InvalidArgumentException
111
     */
112
    private function extract(InputInterface $input): Carbon
113
    {
114
        $date = $input->getParent();
115
116
        if ($date instanceof \DateTimeInterface) {
117
            return Carbon::instance($date);
118
        }
119
120
        $error = 'Return type of GraphQL DateTime must be an instance of DateTime, but %s given';
121
        $type  = \is_object($date) ? \get_class($date) : \strtolower(\gettype($date));
122
123
        throw new \InvalidArgumentException(\sprintf($error, $type));
124
    }
125
126
    /**
127
     * @param InputInterface $input
128
     * @return string
129
     * @throws \InvalidArgumentException
130
     */
131
    public function diff(InputInterface $input): string
132
    {
133
        /** @var Carbon $value */
134
        $value = $this->extract($input);
135
136
        /** @var Carbon $diff */
137
        $diff = $this->extractDiff($input);
138
139
        /** @var string $format */
140
        $format = $input->get('format');
141
142
        return $format === self::HUMAN_READABLE
143
            ? $value->diffForHumans($diff)
144
            : $this->format($value->diff($diff), $format);
145
    }
146
147
    /**
148
     * @param InputInterface $input
149
     * @return Carbon
150
     * @throws InvalidDateTimeFormat
151
     * @throws \InvalidArgumentException
152
     */
153
    private function extractDiff(InputInterface $input): Carbon
154
    {
155
        if ($input->has('with')) {
156
            try {
157
                return Carbon::parse($input->get('with'));
158
            } catch (\Throwable $e) {
159
                throw new InvalidDateTimeFormat('Invalid DateTime format passed in "with" argument');
160
            }
161
        }
162
163
        return Carbon::now($this->extract($input)->getTimezone());
164
    }
165
}
166