Passed
Pull Request — master (#30)
by Guillaume
39:08 queued 37:29
created

Toggl::convertToPastTimers()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 1
dl 0
loc 8
ccs 5
cts 5
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Godbout\Alfred\Time\Services;
4
5
use Carbon\Carbon;
6
use Carbon\CarbonInterval;
7
use Exception;
8
use MorningTrain\TogglApi\TogglApi;
9
10
class Toggl extends TimerService
11
{
12
    private $client;
13
14
    private $data = null;
15
16
17 168
    public function __construct($apiToken)
18
    {
19 168
        $this->client = new TogglApi($apiToken);
20 168
    }
21
22 36
    public function projects()
23
    {
24 36
        return $this->extractFromData('projects');
25
    }
26
27 22
    public function tags()
28
    {
29 22
        return $this->extractFromData('tags');
30
    }
31
32 7
    public function pastTimers()
33
    {
34
        try {
35 7
            $togglTimers = $this->client->getTimeEntriesInRange(Carbon::today(), Carbon::today()->subDays(30));
36
37 7
            return $this->convertToPastTimers($togglTimers);
38
        } catch (Exception $e) {
39
            return [];
40
        }
41
    }
42
43 77
    public function startTimer()
44
    {
45
        try {
46 77
            $timer = $this->client->startTimeEntry([
47 77
                'description' => getenv('timer_description'),
48 77
                'pid' => getenv('timer_project_id'),
49 77
                'tags' => getenv('timer_tag') ? [getenv('timer_tag')] : '',
50 77
                'created_with' => 'Alfred Time'
51
            ]);
52
53 77
            if (! isset($timer->id)) {
54 77
                return false;
55
            }
56
        } catch (Exception $e) {
57
            return false;
58
        }
59
60 77
        return $timer->id;
61
    }
62
63 67
    public function stopCurrentTimer()
64
    {
65 67
        if ($timerId = $this->runningTimer()) {
66 63
            $response = $this->client->stopTimeEntry($timerId);
67
68 63
            if (! isset($response->id)) {
69 1
                throw new Exception("Can't stop current running timer.", 1);
70
71
                return false;
0 ignored issues
show
Unused Code introduced by
return false is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
72
            }
73
74 62
            return true;
75
        }
76
77 11
        return false;
78
    }
79
80 138
    public function runningTimer()
81
    {
82 138
        $timer = $this->client->getRunningTimeEntry();
83
84 138
        return $timer->id ?? false;
85
    }
86
87 14
    public function continueTimer($timerId)
88
    {
89
        /**
90
         * Timer attributes are stored in env variables
91
         * gathered in startTimer.
92
         */
93 14
        return $this->startTimer();
94
    }
95
96 78
    public function deleteTimer($timerId)
97
    {
98
        try {
99 78
            $this->client->deleteTimeEntry($timerId);
100
        } catch (Exception $e) {
101
            return false;
102
        }
103
104 78
        return true;
105
    }
106
107 58
    private function extractFromData($needle)
108
    {
109 58
        $data = $this->getData();
110
111 58
        if (! isset($data->$needle)) {
112 30
            return [];
113
        }
114
115 28
        $nonDeletedData = $this->filterOutServerwiseDeletedItemsFromData($data->$needle);
116
117 28
        return array_column($nonDeletedData, 'name', 'id');
118
    }
119
120 58
    private function getData()
121
    {
122 58
        if (is_null($this->data)) {
123 58
            return $this->client->getMe(true);
124
        }
125
126
        return $this->data;
127
    }
128
129 28
    private function filterOutServerwiseDeletedItemsFromData($items = [])
130
    {
131
        return array_filter($items, function ($item) {
132 28
            return ! isset($item->server_deleted_at);
133 28
        });
134
    }
135
136 7
    protected function convertToPastTimers($togglTimers)
137
    {
138 7
        $projects = $this->projects();
139
140 7
        return array_reverse(
141
            array_map(function ($togglTimer) use ($projects) {
142 7
                return $this->buildPastTimerObject($togglTimer, $projects);
143 7
            }, $togglTimers)
144
        );
145
    }
146
147 7
    protected function buildPastTimerObject($togglTimer, $projects)
148
    {
149 7
        $pastTimer['id'] = $togglTimer->id;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$pastTimer was never initialized. Although not strictly required by PHP, it is generally a good practice to add $pastTimer = array(); before regardless.
Loading history...
150 7
        $pastTimer['description'] = $togglTimer->description ?? '';
151 7
        $pastTimer['duration'] = CarbonInterval::seconds($togglTimer->duration)->cascade()->format('%H:%I:%S');
152
153 7
        if (isset($togglTimer->pid)) {
154 7
            $pastTimer['project_id'] = $togglTimer->pid;
155 7
            $pastTimer['project_name'] = $projects[$togglTimer->pid];
156
        }
157
158 7
        if (isset($togglTimer->tags)) {
159 7
            $pastTimer['tags'] = implode(', ', (array) $togglTimer->tags);
160
        }
161
162 7
        return (object) $pastTimer;
163
    }
164
}
165