Passed
Pull Request — master (#30)
by Guillaume
38:15 queued 36:45
created

Toggl::projects()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
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 14
    public function tags()
28
    {
29 14
        return $this->extractFromData('tags');
30
    }
31
32 11
    public function pastTimers()
33
    {
34
        try {
35 11
            $togglTimers = $this->client->getTimeEntriesInRange(Carbon::today(), Carbon::today()->subDays(30));
36
37 11
            return $this->convertToPastTimers($togglTimers);
38
        } catch (Exception $e) {
39
            return [];
40
        }
41
    }
42
43 121
    public function startTimer()
44
    {
45
        try {
46 121
            $timer = $this->client->startTimeEntry([
47 121
                'description' => getenv('timer_description'),
48 121
                'pid' => getenv('timer_project_id'),
49 121
                'tags' => getenv('timer_tag') ? [getenv('timer_tag')] : '',
50 121
                'created_with' => 'Alfred Time'
51
            ]);
52
53 121
            if (! isset($timer->id)) {
54 121
                return false;
55
            }
56
        } catch (Exception $e) {
57
            return false;
58
        }
59
60 121
        return $timer->id;
61
    }
62
63 98
    public function stopCurrentTimer()
64
    {
65 98
        if ($timerId = $this->runningTimer()) {
66 98
            $response = $this->client->stopTimeEntry($timerId);
67
68 98
            if (! isset($response->id)) {
69
                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 98
            return true;
75
        }
76
77 11
        return false;
78
    }
79
80 162
    public function runningTimer()
81
    {
82 162
        $timer = $this->client->getRunningTimeEntry();
83
84 162
        return $timer->id ?? false;
85
    }
86
87 22
    public function continueTimer($timerId)
88
    {
89
        /**
90
         * Timer attributes are stored in env variables
91
         * gathered in startTimer.
92
         */
93 22
        return $this->startTimer();
94
    }
95
96 120
    public function deleteTimer($timerId)
97
    {
98
        try {
99 120
            $this->client->deleteTimeEntry($timerId);
100
        } catch (Exception $e) {
101
            return false;
102
        }
103
104 120
        return true;
105
    }
106
107 50
    private function extractFromData($needle)
108
    {
109 50
        $data = $this->getData();
110
111 50
        if (! isset($data->$needle)) {
112 6
            return [];
113
        }
114
115 44
        $nonDeletedData = $this->filterOutServerwiseDeletedItemsFromData($data->$needle);
116
117 44
        return array_column($nonDeletedData, 'name', 'id');
118
    }
119
120 50
    private function getData()
121
    {
122 50
        if (is_null($this->data)) {
123 50
            return $this->client->getMe(true);
124
        }
125
126
        return $this->data;
127
    }
128
129 44
    private function filterOutServerwiseDeletedItemsFromData($items = [])
130
    {
131
        return array_filter($items, function ($item) {
132 44
            return ! isset($item->server_deleted_at);
133 44
        });
134
    }
135
136 11
    protected function convertToPastTimers($togglTimers)
137
    {
138 11
        $projects = $this->projects();
139
140 11
        return array_reverse(
141
            array_map(function ($togglTimer) use ($projects) {
142 11
                return $this->buildPastTimerObject($togglTimer, $projects);
143 11
            }, $togglTimers)
144
        );
145
    }
146
147 11
    protected function buildPastTimerObject($togglTimer, $projects)
148
    {
149 11
        $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 11
        $pastTimer['description'] = $togglTimer->description ?? '';
151 11
        $pastTimer['duration'] = CarbonInterval::seconds($togglTimer->duration)->cascade()->format('%H:%I:%S');
152
153 11
        if (isset($togglTimer->pid)) {
154 11
            $pastTimer['project_id'] = $togglTimer->pid;
155 11
            $pastTimer['project_name'] = $projects[$togglTimer->pid];
156
        }
157
158 11
        if (isset($togglTimer->tags)) {
159 11
            $pastTimer['tags'] = implode(', ', (array) $togglTimer->tags);
160
        }
161
162 11
        return (object) $pastTimer;
163
    }
164
}
165