Completed
Push — master ( 4a1992...3a4f99 )
by Vladimir
06:33
created

Pulse::createUpdate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 3
crap 1
1
<?php
2
3
/**
4
 * @copyright 2017 Vladimir Jimenez
5
 * @license   https://github.com/allejo/PhpPulse/blob/master/LICENSE.md MIT
6
 */
7
8
namespace allejo\DaPulse;
9
10
use allejo\DaPulse\Exceptions\ColumnNotFoundException;
11
use allejo\DaPulse\Exceptions\InvalidColumnException;
12
use allejo\DaPulse\Exceptions\InvalidObjectException;
13
use allejo\DaPulse\Objects\PulseColumnDateValue;
14
use allejo\DaPulse\Objects\PulseColumnNumericValue;
15
use allejo\DaPulse\Objects\PulseColumnPersonValue;
16
use allejo\DaPulse\Objects\PulseColumnStatusValue;
17
use allejo\DaPulse\Objects\PulseColumnTextValue;
18
use allejo\DaPulse\Objects\PulseColumnTimelineValue;
19
use allejo\DaPulse\Objects\PulseColumnValue;
20
use allejo\DaPulse\Objects\SubscribableObject;
21
use allejo\DaPulse\Utilities\ArrayUtilities;
22
23
/**
24
 * A class representing a single pulse in a board
25
 *
26
 * @api
27
 * @package allejo\DaPulse
28
 * @since   0.1.0
29
 */
30
class Pulse extends SubscribableObject
31
{
32
    /**
33
     * @ignore
34
     */
35
    const API_PREFIX = "pulses";
36
37
    // ================================================================================================================
38
    //   Instance Variables
39
    // ================================================================================================================
40
41
    /**
42
     * The resource's URL.
43
     *
44
     * @var string
45
     */
46
    protected $url;
47
48
    /**
49
     * The pulse's name.
50
     *
51
     * @var string
52
     */
53
    protected $name;
54
55
    /**
56
     * The amount of updates a pulse has.
57
     *
58
     * @var int
59
     */
60
    protected $updates_count;
61
62
    /**
63
     * The ID of the parent board.
64
     *
65
     * @var int
66
     */
67
    protected $board_id;
68
69
    /**
70
     * Creation time.
71
     *
72
     * @var \DateTime
73
     */
74
    protected $created_at;
75
76
    /**
77
     * Last update time.
78
     *
79
     * @var \DateTime
80
     */
81
    protected $updated_at;
82
83
    /**
84
     * The ID of the group this pulse belongs to
85
     *
86
     * @var string
87
     */
88
    protected $group_id;
89
90
    /**
91
     * @var PulseColumn[]
92
     */
93
    protected $column_structure;
94
95
    /**
96
     * An array containing all of the values a pulse has for each column
97
     *
98
     * @var mixed
99
     */
100
    protected $raw_column_values;
101
102
    /**
103
     * An array containing objects extended from PulseColumnValue storing all of the values for each column
104
     *
105
     * @var array
106
     */
107
    protected $column_values;
108
109
    /**
110
     * The common URL path for retrieving objects relating a pulse such as subscribers, notes, or updates
111
     *
112
     * @var string
113
     */
114
    private $urlSyntax = "%s/%s/%s.json";
115
116
    // ================================================================================================================
117
    //   Overloaded functions
118
    // ================================================================================================================
119
120 104
    protected function initializeValues ()
121
    {
122 104
        $this->column_values     = [];
123 104
        $this->column_structure  = [];
124 104
        $this->raw_column_values = [];
125 104
    }
126
127
    // ================================================================================================================
128
    //   Getter functions
129
    // ================================================================================================================
130
131
    /**
132
     * The resource's URL.
133
     *
134
     * @api
135
     *
136
     * @since  0.1.0
137
     *
138
     * @return string
139
     */
140 1
    public function getUrl ()
141
    {
142 1
        $this->lazyLoad();
143
144 1
        return $this->url;
145
    }
146
147
    /**
148
     * The pulse's name.
149
     *
150
     * @api
151
     *
152
     * @since  0.1.0
153
     *
154
     * @return string
155
     */
156 4
    public function getName ()
157
    {
158 4
        $this->lazyLoad();
159
160 4
        return $this->name;
161
    }
162
163
    /**
164
     * The amount of updates a pulse has.
165
     *
166
     * @api
167
     *
168
     * @since  0.1.0
169
     *
170
     * @return int
171
     */
172 1
    public function getUpdatesCount ()
173
    {
174 1
        $this->lazyLoad();
175
176 1
        return $this->updates_count;
177
    }
178
179
    /**
180
     * The ID of the parent board.
181
     *
182
     * @api
183
     *
184
     * @since  0.1.0
185
     *
186
     * @return int
187
     */
188 41
    public function getBoardId ()
189
    {
190 41
        $this->lazyLoad();
191
192 41
        return $this->board_id;
193
    }
194
195
    /**
196
     * Creation time.
197
     *
198
     * @api
199
     *
200
     * @since  0.1.0
201
     *
202
     * @return \DateTime
203
     */
204 1
    public function getCreatedAt ()
205
    {
206 1
        $this->lazyLoad();
207 1
        self::lazyCast($this->created_at, '\DateTime');
208
209 1
        return $this->created_at;
210
    }
211
212
    /**
213
     * Last update time.
214
     *
215
     * @api
216
     *
217
     * @since  0.1.0
218
     *
219
     * @return \DateTime
220
     */
221 3
    public function getUpdatedAt ()
222
    {
223 3
        $this->lazyLoad();
224 3
        self::lazyCast($this->updated_at, '\DateTime');
225
226 3
        return $this->updated_at;
227
    }
228
229
    /**
230
     * Get the ID of the group this Pulse is a part of. If this value is not available, an API call will be made to
231
     * find the group ID via brute force.
232
     *
233
     * **Note** The group ID is cached if it is not available. To update the cached value, use $forceFetch to force an
234
     * API call to get a new value.
235
     *
236
     * **Warning** An API call is always slower than using the cached value.
237
     *
238
     * @api
239
     *
240
     * @param bool $forceFetch Force an API call to get an updated group ID if it has been changed
241
     *
242
     * @since 0.1.0
243
     *
244
     * @return string
245
     */
246 3
    public function getGroupId ($forceFetch = false)
247
    {
248 3
        $this->lazyLoad();
249
250 3
        if (empty($this->group_id) || $forceFetch)
251 3
        {
252 2
            $parentBoard = new PulseBoard($this->board_id, true);
253 2
            $pulses      = $parentBoard->getPulses();
254
255 2
            foreach ($pulses as $pulse)
256
            {
257 2
                if ($this->getId() === $pulse->getId())
258 2
                {
259 2
                    $this->group_id = $pulse->getGroupId();
260 2
                    break;
261
                }
262 2
            }
263 2
        }
264
265 3
        return $this->group_id;
266
    }
267
268
    // ================================================================================================================
269
    //   Pulse functions
270
    // ================================================================================================================
271
272
    /**
273
     * Edit the name of the pulse
274
     *
275
     * @api
276
     *
277
     * @param string $title
278
     *
279
     * @since 0.1.0
280
     */
281 1
    public function editName ($title)
282
    {
283 1
        $editUrl    = sprintf("%s/%d.json", self::apiEndpoint(), $this->getId());
284
        $postParams = [
285
            'name' => $title
286 1
        ];
287
288 1
        $this->jsonResponse = self::sendPut($editUrl, $postParams);
0 ignored issues
show
Documentation Bug introduced by
It seems like self::sendPut($editUrl, $postParams) of type * is incompatible with the declared type array of property $jsonResponse.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
289 1
        $this->assignResults();
290 1
    }
291
292
    /**
293
     * Archive the current pulse
294
     *
295
     * This is the equivalent of a soft delete and can be restored from the DaPulse website.
296
     *
297
     * @api
298
     *
299
     * @since 0.1.0
300
     */
301 1
    public function archivePulse ()
302
    {
303 1
        $archiveURL = sprintf("%s/%d.json", self::apiEndpoint(), $this->getId());
304
        $getParams  = [
305
            'archive' => true
306 1
        ];
307
308 1
        $this->jsonResponse = self::sendDelete($archiveURL, $getParams);
0 ignored issues
show
Documentation Bug introduced by
It seems like self::sendDelete($archiveURL, $getParams) of type * is incompatible with the declared type array of property $jsonResponse.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
309 1
        $this->assignResults();
310 1
    }
311
312
    /**
313
     * Delete the current Pulse
314
     *
315
     * @api
316
     *
317
     * @since 0.1.0
318
     *
319
     * @throws InvalidObjectException
320
     */
321 1 View Code Duplication
    public function deletePulse ()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
322
    {
323 1
        $this->checkInvalid();
324
325 1
        $deleteURL          = sprintf("%s/%d.json", self::apiEndpoint(), $this->getId());
326 1
        $this->jsonResponse = self::sendDelete($deleteURL);
0 ignored issues
show
Documentation Bug introduced by
It seems like self::sendDelete($deleteURL) of type * is incompatible with the declared type array of property $jsonResponse.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
327 1
        $this->assignResults();
328
329 1
        $this->deletedObject = true;
330 1
    }
331
332
    public function duplicatePulse ($groupId = null, $ownerId = null)
333
    {
334
        $url        = sprintf("%s/%s/pulses/%s/duplicate.json", self::apiEndpoint("boards"), $this->getBoardId(), $this->getId());
335
        $postParams = [];
336
337
        if ($ownerId instanceof PulseUser)
338
        {
339
            $ownerId = $ownerId->getId();
340
        }
341
342
        self::setIfNotNullOrEmpty($postParams, "group_id", $groupId);
343
        self::setIfNotNullOrEmpty($postParams, "owner_id", $ownerId);
344
345
        $result = self::sendPost($url, $postParams);
346
        $this->pulseInjection($result);
347
348
        return (new Pulse($result['pulse']));
349
    }
350
351 View Code Duplication
    private function pulseInjection (&$result)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
352
    {
353
        $parentBoard = new PulseBoard($this->getBoardId());
354
355
        // Inject some information so a Pulse object can survive on its own
356
        $result["pulse"]["group_id"]          = $result["board_meta"]["group_id"];
357
        $result["pulse"]["column_structure"]  = $parentBoard->getColumns();
358
        $result["pulse"]["raw_column_values"] = $result["column_values"];
359
    }
360
361
    // ================================================================================================================
362
    //   Column data functions
363
    // ================================================================================================================
364
365
    /**
366
     * Access a color type column value belonging to this pulse in order to read it or modify.
367
     *
368
     * This function should only be used to access color type values; an exception will be thrown otherwise.
369
     *
370
     * @api
371
     *
372
     * @param  string $columnId The ID of the column to access. This is typically a slugified version of the column name
373
     *
374
     * @since  0.4.0  ColumnNotFoundException will no longer thrown, instead it'll be thrown when getValue() is called
375
     * @since  0.1.0
376
     *
377
     * @throws InvalidColumnException  The specified column is not a "color" type column
378
     * @throws InvalidObjectException  The specified column exists but modification of its value is unsupported either
379
     *                                 by this library or the DaPulse API.
380
     *
381
     * @return PulseColumnStatusValue A column object with access to its contents
382
     */
383 6
    public function getStatusColumn ($columnId)
384
    {
385 6
        return $this->getColumn($columnId, PulseColumn::Status);
386
    }
387
388
    /**
389
     * Access a date type column value belonging to this pulse in order to read it or modify.
390
     *
391
     * This function should only be used to access date type values; an exception will be thrown otherwise.
392
     *
393
     * @api
394
     *
395
     * @param  string $columnId The ID of the column to access. This is typically a slugified version of the column name
396
     *
397
     * @since  0.4.0  ColumnNotFoundException will no longer thrown, instead it'll be thrown when getValue() is called
398
     * @since  0.1.0
399
     *
400
     * @throws InvalidColumnException  The specified column is not a "date" type column
401
     * @throws InvalidObjectException  The specified column exists but modification of its value is unsupported either
402
     *                                 by this library or the DaPulse API.
403
     *
404
     * @return PulseColumnDateValue A column object with access to its contents
405
     */
406 9
    public function getDateColumn ($columnId)
407
    {
408 9
        return $this->getColumn($columnId, PulseColumn::Date);
409
    }
410
411
    /**
412
     * Access a numeric type column value belonging to this pulse in order to read it or modify.
413
     *
414
     * This function should only be used to access number type values; an exception will be thrown otherwise.
415
     *
416
     * @api
417
     *
418
     * @param  string $columnId The ID of the column to access. This is typically a slugified version of the column name
419
     *
420
     * @since  0.4.0  ColumnNotFoundException will no longer thrown, instead it'll be thrown when getValue() is called
421
     * @since  0.2.0
422
     *
423
     * @throws InvalidColumnException  The specified column is not a "numeric" type column
424
     * @throws InvalidObjectException  The specified column exists but modification of its value is unsupported either
425
     *                                 by this library or the DaPulse API.
426
     *
427
     * @return PulseColumnNumericValue A column object with access to its contents
428
     */
429 7
    public function getNumericColumn ($columnId)
430
    {
431 7
        return $this->getColumn($columnId, PulseColumn::Numeric);
432
    }
433
434
    /**
435
     * Access a person type column value belonging to this pulse in order to read it or modify.
436
     *
437
     * This function should only be used to access person type values; an exception will be thrown otherwise.
438
     *
439
     * @api
440
     *
441
     * @param  string $columnId The ID of the column to access. This is typically a slugified version of the column name
442
     *
443
     * @since  0.4.0  ColumnNotFoundException will no longer thrown, instead it'll be thrown when getValue() is called
444
     * @since  0.1.0
445
     *
446
     * @throws InvalidColumnException  The specified column is not a "person" type column
447
     * @throws InvalidObjectException  The specified column exists but modification of its value is unsupported either
448
     *                                 by this library or the DaPulse API.
449
     *
450
     * @return PulseColumnPersonValue A column object with access to its contents
451
     */
452 9
    public function getPersonColumn ($columnId)
453
    {
454 9
        return $this->getColumn($columnId, PulseColumn::Person);
455
    }
456
457
    /**
458
     * Access a text type column value belonging to this pulse in order to read it or modify.
459
     *
460
     * This function should only be used to access text type values; an exception will be thrown otherwise.
461
     *
462
     * @api
463
     *
464
     * @param  string $columnId The ID of the column to access. This is typically a slugified version of the column name
465
     *
466
     * @since  0.4.0  ColumnNotFoundException will no longer thrown, instead it'll be thrown when getValue() is called
467
     * @since  0.1.0
468
     *
469
     * @throws InvalidColumnException  The specified column is not a "text" type column
470
     * @throws InvalidObjectException  The specified column exists but modification of its value is unsupported either
471
     *                                 by this library or the DaPulse API.
472
     *
473
     * @return PulseColumnTextValue A column object with access to its contents
474
     */
475 4
    public function getTextColumn ($columnId)
476
    {
477 4
        return $this->getColumn($columnId, PulseColumn::Text);
478
    }
479
480
    /**
481
     * Access a timeline type column value belonging to this pulse in order to read it or modify.
482
     *
483
     * This function should only be used to access timeline type values; an exception will be thrown otherwise.
484
     *
485
     * @api
486
     *
487
     * @param  string $columnId The ID of the column to access. This is typically a slugified version of the column name
488
     *
489
     * @since  0.2.1
490
     *
491
     * @throws ColumnNotFoundException The specified column ID does not exist for this Pulse
492
     * @throws InvalidColumnException  The specified column is not a "numeric" type column
493
     * @throws InvalidObjectException  The specified column exists but modification of its value is unsupported either
494
     *                                 by this library or the DaPulse API.
495
     *
496
     * @return PulseColumnTimelineValue A column object with access to its contents
497
     */
498 5
    public function getTimelineColumn ($columnId)
499
    {
500 5
        return $this->getColumn($columnId, PulseColumn::Timeline);
501
    }
502
503
    /**
504
     * Access a column belonging to this pulse in order to read it or modify it.
505
     *
506
     * @api
507
     *
508
     * @param  string $columnId   The ID of the column to access. This is typically a slugified version of the column
509
     *                            title
510
     * @param  string $columnType The type of column being accessed. **Only** use available constants or PulseColumn::getType()
511
     *
512
     * @see    PulseColumn::Date
513
     * @see    PulseColumn::Numeric
514
     * @see    PulseColumn::Person
515
     * @see    PulseColumn::Status
516
     * @see    PulseColumn::Text
517
     * @see    PulseColumn::Timeline
518
     * @see    PulseColumnDateValue
519
     * @see    PulseColumnNumericValue
520
     * @see    PulseColumnPersonValue
521
     * @see    PulseColumnStatusValue
522
     * @see    PulseColumnTextValue
523
     * @see    PulseColumnTimelineValue
524
     *
525
     * @since  0.3.1
526
     *
527
     * @throws InvalidColumnException  The specified column is not the same type as specified in `$columnType`
528
     * @throws InvalidObjectException  The specified column exists but modification of its value is unsupported either
529
     *                                 by this library or the DaPulse API.
530
     *
531
     * @return mixed Returns an instance of an object extending the PulseColumnValue class
532
     */
533 40
    public function getColumn ($columnId, $columnType)
534
    {
535 40
        if (!isset($this->column_values) || !array_key_exists($columnId, $this->column_values))
536 40
        {
537 40
            $key  = ArrayUtilities::array_search_column($this->raw_column_values, 'cid', $columnId);
538 40
            $data = [];
539
540
            // We can't find the key, this means that we got our information from accessing a Pulse directly instead of
541
            // getting it through a PulseBoard. This isn't as robust as accessing a PulseBoard but it's more efficient.
542
            // We make a separate API call to get the value of a column.
543 40
            if ($key !== false)
544 40
            {
545 11
                $data = $this->raw_column_values[$key];
546 11
                $type = $this->column_structure[$key]->getType();
547
548 11
                if ($type !== $columnType)
549 11
                {
550 1
                    throw new InvalidColumnException("The '$columnId' column was expected to be '$columnType' but was '$type' instead.");
551
                }
552 10
            }
553
554 39
            $data['column_id'] = $columnId;
555 39
            $data['board_id']  = $this->getBoardId();
556 39
            $data['pulse_id']  = $this->getId();
557
558 39
            $this->column_values[$columnId] = PulseColumnValue::_createColumnType($columnType, $data);
559 39
        }
560
561 39
        return $this->column_values[$columnId];
562
    }
563
564
    // ================================================================================================================
565
    //   Notes functions
566
    // ================================================================================================================
567
568
    /**
569
     * Create a new note in this project
570
     *
571
     * @api
572
     *
573
     * @param  string   $title         The title of the note
574
     * @param  string   $content       The body of the note
575
     * @param  bool     $ownersOnly    Set to true if only pulse owners can edit this note.
576
     * @param  int|null $user          The id of the user to be marked as the note's last updater
577
     * @param  bool     $createUpdate  Indicates whether to create an update on the pulse notifying subscribers on the
578
     *                                 changes (required user_id to be set).
579
     *
580
     * @throws \InvalidArgumentException if $createUpdate is true and $user is null or $user is not a valid user ID or
581
     *                                   PulseUser object
582
     *
583
     * @since  0.1.0
584
     *
585
     * @return PulseNote
586
     */
587 2
    public function addNote ($title, $content, $ownersOnly = false, $user = null, $createUpdate = false)
588
    {
589 2
        $url        = sprintf($this->urlSyntax, self::apiEndpoint(), $this->id, "notes");
590
        $postParams = [
591 2
            "id"            => $this->id,
592 2
            "title"         => $title,
593 2
            "content"       => $content,
594 2
            "owners_only"   => $ownersOnly,
595
            "create_update" => $createUpdate
596 2
        ];
597
598 2
        if (!is_null($user))
599 2
        {
600
            $user = PulseUser::_castToInt($user);
601
        }
602
603 2
        self::setIfNotNullOrEmpty($postParams, 'user_id', $user);
604
605 2
        if ($createUpdate && is_null($user))
606 2
        {
607 1
            throw new \InvalidArgumentException("The user_id value must be set if an update is to be created");
608
        }
609
610 1
        $noteResult = self::sendPost($url, $postParams);
611
612 1
        return (new PulseNote($noteResult));
613
    }
614
615
    /**
616
     * Return all of the notes belonging to this project
617
     *
618
     * @api
619
     *
620
     * @since  0.1.0
621
     *
622
     * @return PulseNote[]
623
     */
624
    public function getNotes ()
625
    {
626
        $url = sprintf($this->urlSyntax, self::apiEndpoint(), $this->id, "notes");
627
628
        return self::fetchAndCastToObjectArray($url, "PulseNote");
629
    }
630
631
    // ================================================================================================================
632
    //   Updates functions
633
    // ================================================================================================================
634
635
    /**
636
     * Get all of the updates that belong to this Pulse in reverse chronological order
637
     *
638
     * @api
639
     *
640
     * @since 0.1.0
641
     *
642
     * @return PulseUpdate[]
643
     */
644 22
    public function getUpdates ()
645
    {
646 22
        $url = sprintf($this->urlSyntax, self::apiEndpoint(), $this->id, "updates");
647
648 22
        return self::fetchAndCastToObjectArray($url, "PulseUpdate");
649
    }
650
651
    /**
652
     * Create an update for the current Pulse
653
     *
654
     * @api
655
     *
656
     * @param  int|PulseUser $user
657
     * @param  string        $text
658
     * @param  null|bool     $announceToAll
659
     *
660
     * @since  0.3.0 A PulseUpdate object is returned containing the information of the newly created Update
661
     * @since  0.1.0
662
     *
663
     * @return PulseUpdate
664
     */
665 2
    public function createUpdate ($user, $text, $announceToAll = null)
666
    {
667 2
        return PulseUpdate::createUpdate($user, $this->getId(), $text, $announceToAll);
668
    }
669
670
    // ================================================================================================================
671
    //   Static functions
672
    // ================================================================================================================
673
674
    /**
675
     * Get all of the pulses that belong to the organization across all boards.
676
     *
677
     * To modify the amount of data returned with pagination, use the following values in the array to configure your
678
     * pagination or offsets.
679
     *
680
     * ```php
681
     * $params = array(
682
     *     "page"     => 1,          // (int) Page offset to fetch
683
     *     "per_page" => 10,         // (int) Number of results per page
684
     *     "offset"   => 5,          // (int) Instead of starting at result 0, start counting from result 5
685
     *     "order_by_latest" => true // (bool) Order the pulses with the most recent first
686
     * );
687
     * ```
688
     *
689
     * @api
690
     *
691
     * @param array $params GET parameters passed to with the query to modify the data returned.
692
     *
693
     * @since 0.1.0
694
     *
695
     * @return Pulse[]
696
     */
697
    public static function getPulses ($params = [])
698
    {
699
        $url = sprintf("%s.json", self::apiEndpoint());
700
701
        return self::fetchAndCastToObjectArray($url, "Pulse", $params);
702
    }
703
}
704