Passed
Push — master ( 866c3b...50a671 )
by y
08:13
created

Project::selectSections()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 2
rs 10
1
<?php
2
3
namespace Helix\Asana;
4
5
use Helix\Asana\Base\AbstractEntity;
6
use Helix\Asana\Base\AbstractEntity\CrudTrait;
7
use Helix\Asana\Base\AbstractEntity\WorkspaceTrait;
8
use Helix\Asana\Event\ProjectEvent;
9
use Helix\Asana\Event\StoryEvent;
10
use Helix\Asana\Event\TaskEvent;
11
use Helix\Asana\Project\Section;
12
use Helix\Asana\Project\Status;
13
use Helix\Asana\Webhook\ProjectWebhook;
14
15
/**
16
 * A project.
17
 *
18
 * @see https://developers.asana.com/docs/asana-projects
19
 * @see https://developers.asana.com/docs/project
20
 *
21
 * @method bool         isArchived          ()
22
 * @method $this        setArchived         (bool $archived)
23
 * @method string       getColor            ()
24
 * @method $this        setColor            (null|string $color)
25
 * @method string       getCreatedAt        ()
26
 * @method null|Status  getCurrentStatus    ()
27
 * @method CustomField[] getCustomFields    ()
28
 * @method CustomField[] selectCustomFields ()
29
 * @method string       getDueOn            ()
30
 * @method $this        setDueOn            (string $date)
31
 * @method User[]       getFollowers        ()
32
 * @method User[]       selectFollowers     ()
33
 * @method string       getHtmlNotes        ()
34
 * @method $this        setHtmlNotes        (string $notes)
35
 * @method string       getLayout           ()
36
 * @method $this        setLayout           (string $layout)
37
 * @method User[]       getMembers          ()
38
 * @method User[]       selectMembers       ()
39
 * @method string       getModifiedAt       ()
40
 * @method string       getName             ()
41
 * @method $this        setName             (string $name)
42
 * @method string       getNotes            ()
43
 * @method $this        setNotes            (string $notes)
44
 * @method null|User    getOwner            ()
45
 * @method $this        setOwner            (User $owner)
46
 * @method bool         isPublic            ()
47
 * @method $this        setPublic           (bool $public)
48
 * @method string       getStartOn          ()
49
 * @method $this        setStartOn          (string $date)
50
 * @method null|Team    getTeam             ()
51
 * @method bool         hasTeam             ()
52
 */
53
class Project extends AbstractEntity {
54
55
    use CrudTrait;
56
    use WorkspaceTrait;
57
58
    const TYPE = 'project';
59
60
    const LAYOUT_BOARD = 'board';
61
    const LAYOUT_LIST = 'list';
62
63
    protected static $map = [
64
        'current_status' => Status::class,
65
        'custom_fields' => [CustomField::class],
66
        'followers' => [User::class],
67
        'members' => [User::class],
68
        'owner' => User::class,
69
        'team' => Team::class,
70
        'workspace' => Workspace::class
71
    ];
72
73
    final public function __toString (): string {
74
        return "projects/{$this->getGid()}";
75
    }
76
77
    final protected function _getDir (): string {
78
        return 'projects';
79
    }
80
81
    /**
82
     * @depends after-create
83
     * @param User $user
84
     * @return $this
85
     */
86
    public function addMember (User $user) {
87
        return $this->addMembers([$user]);
88
    }
89
90
    /**
91
     * @depends after-create
92
     * @param User[] $users
93
     * @return $this
94
     */
95
    public function addMembers (array $users) {
96
        return $this->_addWithPost("{$this}/addMembers", [
97
            'members' => array_column($users, 'gid')
98
        ], 'members', $users);
99
    }
100
101
    /**
102
     * @depends after-create
103
     * @param string $target
104
     * @return ProjectWebhook
105
     */
106
    public function addWebhook (string $target) {
107
        /** @var ProjectWebhook $webhook */
108
        $webhook = $this->factory(ProjectWebhook::class);
109
        return $webhook->create($this, $target);
110
    }
111
112
    /**
113
     * Duplicates the project.
114
     *
115
     * @see https://developers.asana.com/docs/duplicate-a-project
116
     *
117
     * If `$team` is `null`, the duplicate will inherit the existing team.
118
     *
119
     * If `$schedule` is given:
120
     * - It must have either `due_on` or `start_on`
121
     * - `task_dates` is automatically added to `$include`
122
     * - `should_skip_weekends` defaults to `true` if not given.
123
     *
124
     * @depends after-create
125
     * @param string $name
126
     * @param string[] $include
127
     * @param Team|null $team
128
     * @param array $schedule
129
     * @return Job
130
     */
131
    public function duplicate (string $name, array $include, Team $team = null, array $schedule = []) {
132
        $data = ['name' => $name];
133
        if ($team) {
134
            $data['team'] = $team->getGid();
135
        }
136
        if ($schedule) {
1 ignored issue
show
Bug Best Practice introduced by
The expression $schedule of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
137
            $include[] = 'task_dates';
138
            $schedule += ['should_skip_weekends' => true];
139
            $data['schedule_dates'] = $schedule;
140
        }
141
        $data['include'] = array_values($include);
142
        $remote = $this->api->post("{$this}/duplicate", $data);
143
        return $this->factory(Job::class, $remote);
1 ignored issue
show
Bug introduced by
It seems like $remote can also be of type null; however, parameter $data of Helix\Asana\Base\Data::factory() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

143
        return $this->factory(Job::class, /** @scrutinizer ignore-type */ $remote);
Loading history...
144
    }
145
146
    /**
147
     * @depends after-create
148
     * @return Section
149
     */
150
    public function getDefaultSection () {
151
        return $this->loadAll(Section::class, "{$this}/sections", ['limit' => 1])[0];
152
    }
153
154
    /**
155
     * Returns events since the last sync.
156
     *
157
     * @depends after-create
158
     * @param null|string $token
159
     * @return ProjectEvent[]|TaskEvent[]|StoryEvent[]
160
     */
161
    public function getEvents (&$token) {
162
        return $this->api->sync($this, $token);
163
    }
164
165
    /**
166
     * @depends after-create
167
     * @return Section[]
168
     */
169
    public function getSections () {
170
        return $this->loadAll(Section::class, "{$this}/sections");
171
    }
172
173
    /**
174
     * @depends after-create
175
     * @return Status[]
176
     */
177
    public function getStatuses () {
178
        return $this->loadAll(Status::class, "{$this}/project_statuses");
179
    }
180
181
    /**
182
     * The project's tasks.
183
     *
184
     * @see https://developers.asana.com/docs/get-multiple-tasks
185
     *
186
     * @depends after-create
187
     * @param array $filter
188
     * @return Task[]
189
     */
190
    public function getTasks (array $filter = []) {
191
        $filter['project'] = $this->getGid();
192
        return $this->loadAll(Task::class, "tasks", $filter);
193
    }
194
195
    /**
196
     * @depends after-create
197
     * @return string
198
     */
199
    public function getUrl (): string {
200
        return "https://app.asana.com/0/{$this->getGid()}";
201
    }
202
203
    /**
204
     * @return ProjectWebhook[]
205
     */
206
    public function getWebhooks () {
207
        return $this->loadAll(ProjectWebhook::class, 'webhooks', [
208
            'workspace' => $this->getWorkspace()->getGid(),
209
            'resource' => $this->getGid()
210
        ]);
211
    }
212
213
    public function isBoard (): bool {
214
        return $this->getLayout() === self::LAYOUT_BOARD;
215
    }
216
217
    public function isList (): bool {
218
        return $this->getLayout() === self::LAYOUT_LIST;
219
    }
220
221
    /**
222
     * @depends after-create
223
     * @return Section
224
     */
225
    public function newSection () {
226
        return $this->factory(Section::class, ['project' => $this]);
227
    }
228
229
    /**
230
     * @depends after-create
231
     * @return Status
232
     */
233
    public function newStatus () {
234
        return $this->factory(Status::class);
235
    }
236
237
    /**
238
     * Instantiates and returns a new task in the default section of the project.
239
     *
240
     * @depends after-create
241
     * @return Task
242
     */
243
    public function newTask () {
244
        return $this->getDefaultSection()->newTask();
245
    }
246
247
    /**
248
     * @depends after-create
249
     * @param User $user
250
     * @return $this
251
     */
252
    public function removeMember (User $user) {
253
        return $this->removeMembers([$user]);
254
    }
255
256
    /**
257
     * @depends after-create
258
     * @param User[] $users
259
     * @return $this
260
     */
261
    public function removeMembers (array $users) {
262
        return $this->_removeWithPost("{$this}/removeMembers", [
263
            'members' => array_column($users, 'gid')
264
        ], 'members', $users);
265
    }
266
267
    /**
268
     * @param callable $filter `fn( Section $section ): bool`
269
     * @return Section[]
270
     */
271
    public function selectSections (callable $filter) {
272
        return $this->_select($this->getSections(), $filter);
273
    }
274
275
    /**
276
     * @param callable $filter `fn( Status $status ): bool`
277
     * @return Status[]
278
     */
279
    public function selectStatuses (callable $filter) {
280
        return $this->_select($this->getStatuses(), $filter);
281
    }
282
283
    /**
284
     * @param callable $filter `fn( Task $task ): bool`
285
     * @param array $apiFilter Pre-filter given to the API to reduce network load.
286
     * @return Task[]
287
     */
288
    public function selectTasks (callable $filter, array $apiFilter = []) {
289
        return $this->_select($this->getTasks($apiFilter), $filter);
290
    }
291
292
    /**
293
     * @depends create-only
294
     * @param null|Team $team
295
     * @return $this
296
     */
297
    public function setTeam (?Team $team) {
298
        if ($team and !$this->hasWorkspace()) {
299
            $this->setWorkspace($team->getOrganization());
300
        }
301
        return $this->_set('team', $team);
302
    }
303
}