Completed
Push — master ( 693596...23a82f )
by Michał
06:07
created

Message   B

Complexity

Total Complexity 40

Size/Duplication

Total Lines 408
Duplicated Lines 5.39 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
wmc 40
lcom 1
cbo 2
dl 22
loc 408
rs 8.2608
c 0
b 0
f 0

24 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 2
D setAttributes() 0 32 8
A getEndpoint() 0 4 1
A setEndpoint() 0 6 1
A getText() 0 4 1
A setText() 0 6 1
A getChannel() 0 4 1
A setChannel() 0 6 1
A getUsername() 0 4 1
A setUsername() 0 6 1
A getIcon() 0 4 1
A setIcon() 0 6 1
A attach() 11 11 2
A hasAttachment() 0 4 1
A getAttachment() 0 8 2
A setAttachment() 11 11 2
A getAttachments() 0 4 1
A setAttachments() 0 10 2
A countAttachments() 0 4 1
A getParseMode() 0 4 1
A setParseMode() 0 10 2
A unserialize() 0 4 1
A toArray() 0 19 2
A resolveAttachment() 0 17 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Message often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Message, and based on these observations, apply Extract Interface, too.

1
<?php namespace nyx\notify\transports\slack;
2
3
// External dependencies
4
use nyx\core;
5
use nyx\diagnostics;
6
7
/**
8
 * Slack Message
9
 *
10
 * @package     Nyx\Notify
11
 * @version     0.1.0
12
 * @author      Michal Chojnacki <[email protected]>
13
 * @copyright   2012-2017 Nyx Dev Team
14
 * @link        https://github.com/unyx/nyx
15
 * @todo        PHP7.1 pass for nullable return types (missing ?string on most methods).
16
 */
17
class Message implements core\interfaces\Serializable
18
{
19
    /**
20
     * The parse modes that can be requested for a Message.
21
     */
22
    const PARSE_DEFAULT = null;
23
    const PARSE_FULL    = 'full';
24
    const PARSE_NONE    = 'none';
25
26
    /**
27
     * The traits of a Slack Message.
28
     */
29
    use core\traits\Serializable;
30
31
    /**
32
     * @var string  The endpoint for this Message. Note: Only has effect when using the Slack Webhook Transport, not
33
     *              the Web API.
34
     */
35
    protected $endpoint;
36
37
    /**
38
     * @var string  The text content of the Message.
39
     */
40
    protected $text;
41
42
    /**
43
     * @var string  The channel this Message shall be sent to.
44
     */
45
    protected $channel;
46
47
    /**
48
     * @var string  The name this Message shall be sent as.
49
     */
50
    protected $username;
51
52
    /**
53
     * @var string  The icon of the Message.
54
     */
55
    protected $icon;
56
57
    /**
58
     * @var message\Attachment[]    The Attachments of the Message.
59
     */
60
    protected $attachments = [];
61
62
    /**
63
     * @var string  The parse mode of this Message. One of the PARSE_* class constants.
64
     */
65
    protected $parse;
66
67
    /**
68
     * Creates a new Slack Message instance.
69
     *
70
     * @param   array   $attributes
71
     */
72
    public function __construct(array $attributes = null)
73
    {
74
        if (!empty($attributes)) {
75
            $this->setAttributes($attributes);
76
        }
77
    }
78
79
    /**
80
     * Sets the attributes of this Message.
81
     *
82
     * @param   array   $attributes
83
     * @return  $this
84
     */
85
    public function setAttributes(array $attributes) : Message
86
    {
87
        if (isset($attributes['endpoint'])) {
88
            $this->setEndpoint($attributes['endpoint']);
89
        }
90
91
        if (isset($attributes['text'])) {
92
            $this->setText($attributes['text']);
93
        }
94
95
        if (isset($attributes['channel'])) {
96
            $this->setChannel($attributes['channel']);
97
        }
98
99
        if (isset($attributes['username'])) {
100
            $this->setUsername($attributes['username']);
101
        }
102
103
        if (isset($attributes['icon'])) {
104
            $this->setIcon($attributes['icon']);
105
        }
106
107
        foreach($attributes['attachments'] as $attachment) {
108
            $this->attach($attachment);
109
        }
110
111
        if (isset($attributes['parse'])) {
112
            $this->setParseMode($attributes['parse']);
113
        }
114
115
        return $this;
116
    }
117
118
    /**
119
     * Returns the endpoint for this Message.
120
     *
121
     * Note: Only has effect when using the Slack Webhook Transport, not the Web API.
122
     *
123
     * @return  string
124
     */
125
    public function getEndpoint()
126
    {
127
        return $this->endpoint;
128
    }
129
130
    /**
131
     * Sets the endpoint for this Message.
132
     *
133
     * Note: Only has effect when using the Slack Webhook Transport, not the Web API.
134
     *
135
     * @param   string  $url
136
     * @return  $this
137
     */
138
    public function setEndpoint(string $url) : Message
139
    {
140
        $this->endpoint = $url;
141
142
        return $this;
143
    }
144
145
    /**
146
     * Returns the text content of the Message.
147
     *
148
     * @return  string
149
     */
150
    public function getText()
151
    {
152
        return $this->text;
153
    }
154
155
    /**
156
     * Sets the text content of the Message.
157
     *
158
     * @param   string  $text
159
     * @return  $this
160
     */
161
    public function setText(string $text) : Message
162
    {
163
        $this->text = $text;
164
165
        return $this;
166
    }
167
168
    /**
169
     * Returns the channel this Message shall be sent to.
170
     *
171
     * @return  string
172
     */
173
    public function getChannel()
174
    {
175
        return $this->channel;
176
    }
177
178
    /**
179
     * Sets the channel this Message shall be sent to.
180
     *
181
     * @param   string  $channel
182
     * @return  $this
183
     */
184
    public function setChannel(string $channel = null) : Message
185
    {
186
        $this->channel = $channel;
187
188
        return $this;
189
    }
190
191
    /**
192
     * Returns the name this Message shall be sent as.
193
     *
194
     * @return  string
195
     */
196
    public function getUsername()
197
    {
198
        return $this->username;
199
    }
200
201
    /**
202
     * Sets the name this Message shall be sent as.
203
     *
204
     * @param   string  $name
205
     * @return  $this
206
     */
207
    public function setUsername(string $name = null) : Message
208
    {
209
        $this->username = $name;
210
211
        return $this;
212
    }
213
214
    /**
215
     * Returns the icon of the Message.
216
     *
217
     * @return  string
218
     */
219
    public function getIcon()
220
    {
221
        return $this->icon;
222
    }
223
224
    /**
225
     * Sets the icon of the Message.
226
     *
227
     * @param   string  $icon
228
     * @return  $this
229
     */
230
    public function setIcon(string $icon = null) : Message
231
    {
232
        $this->icon = $icon;
233
234
        return $this;
235
    }
236
237
    /**
238
     * Adds an Attachment to the Message.
239
     *
240
     * @param   callable|array|message\Attachment   $attachment When a callable is given, an Attachment will be created
241
     *                                                          and passed to the callable. With an array, an Attachment
242
     *                                                          will be constructed based on the array. Otherwise
243
     *                                                          an existing instance of an Attachment can be passed in.
244
     * @return  $this
245
     * @throws  \InvalidArgumentException                       When $attachment is neither of the supported types.
246
     */
247 View Code Duplication
    public function attach($attachment) : Message
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...
248
    {
249
        // Let's try to resolve the input into something usable.
250
        if (!($attachment = $this->resolveAttachment($attachment)) instanceof message\Attachment) {
251
            throw new \InvalidArgumentException("Expected a callable, an array or an instance of ".message\Attachment::class.", got [".diagnostics\Debug::getTypeName($attachment)."] instead.");
252
        }
253
254
        $this->attachments[] = $attachment;
255
256
        return $this;
257
    }
258
259
    /**
260
     * Checks whether an Attachment with the specified $index is set.
261
     *
262
     * @return  bool
263
     */
264
    public function hasAttachment(int $index) : bool
265
    {
266
        return isset($this->attachments[$index]);
267
    }
268
269
    /**
270
     * Returns the Attachment at the given $index.
271
     *
272
     * @return  message\Attachment
273
     * @throws  \OutOfBoundsException
274
     */
275
    public function getAttachment(int $index) : message\Attachment
276
    {
277
        if (!isset($this->attachments[$index])) {
278
            throw new \OutOfBoundsException("No Attachment at the specified index [$index].");
279
        }
280
281
        return $this->attachments[$index];
282
    }
283
284
    /**
285
     * Sets the Attachment at the given $index. Overwrites, if applicable.
286
     *
287
     * @see     attach()
288
     *
289
     * @param   callable|array|message\Attachment   $attachment
290
     * @return  $this
291
     * @throws  \InvalidArgumentException
292
     */
293 View Code Duplication
    public function setAttachment(int $index, $attachment) : Message
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...
294
    {
295
        // Let's try to resolve the input into something usable.
296
        if (!($attachment = $this->resolveAttachment($attachment)) instanceof message\Attachment) {
297
            throw new \InvalidArgumentException("Expected a callable, an array or an instance of ".message\Attachment::class.", got [".diagnostics\Debug::getTypeName($attachment)."] instead.");
298
        }
299
300
        $this->attachments[$index] = $attachment;
301
302
        return $this;
303
    }
304
305
    /**
306
     * Returns the Attachments of the Message.
307
     *
308
     * @return  message\Attachment[]
309
     */
310
    public function getAttachments() : array
311
    {
312
        return $this->attachments;
313
    }
314
315
    /**
316
     * Sets the Attachments of the Message.
317
     *
318
     * @param   message\Attachment[]    $attachments
319
     * @return  $this
320
     */
321
    public function setAttachments(array $attachments) : Message
322
    {
323
        $this->attachments = [];
324
325
        foreach ($attachments as $attachment) {
326
            $this->attach($attachment);
0 ignored issues
show
Documentation introduced by
$attachment is of type object<nyx\notify\transp...ack\message\Attachment>, but the function expects a callable.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
327
        }
328
329
        return $this;
330
    }
331
332
    /**
333
     * Returns the number of Attachments in this Message.
334
     *
335
     * @return  int
336
     */
337
    public function countAttachments() : int
338
    {
339
        return count($this->attachments);
340
    }
341
342
    /**
343
     * Returns the parse mode of this Message.
344
     *
345
     * @return  string
346
     */
347
    public function getParseMode()
348
    {
349
        return $this->parse;
350
    }
351
352
    /**
353
     * Sets the parse mode of this Message.
354
     *
355
     * @param   string  $mode               One of the PARSE_* class constants.
356
     * @return  $this
357
     * @throws  \InvalidArgumentException   When passing a $mode which is not one of the PARSE_* class constants.
358
     */
359
    public function setParseMode(string $mode = self::PARSE_DEFAULT) : Message
360
    {
361
        if (!in_array($mode, [self::PARSE_DEFAULT, self::PARSE_FULL, self::PARSE_NONE])) {
362
            throw new \InvalidArgumentException("Unknown parse mode requested [$mode].");
363
        }
364
365
        $this->parse = $mode;
366
367
        return $this;
368
    }
369
370
    /**
371
     * {@inheritDoc}
372
     */
373
    public function unserialize($data)
374
    {
375
        $this->setAttributes(unserialize($data));
376
    }
377
378
    /**
379
     * {@inheritDoc}
380
     */
381
    public function toArray() : array
382
    {
383
        $data = [
384
            'endpoint'    => $this->getEndpoint(),
385
            'text'        => $this->getText(),
386
            'channel'     => $this->getChannel(),
387
            'username'    => $this->getUsername(),
388
            'icon'        => $this->getIcon(),
389
            'parse'       => $this->getParseMode(),
390
            'attachments' => [],
391
            'link_names'  => 1
392
        ];
393
394
        foreach ($this->getAttachments() as $attachment) {
395
            $data['attachments'][] = $attachment->toArray();
396
        }
397
398
        return $data;
399
    }
400
401
    /**
402
     * Attempts to create a slack\Attachment instance based on the $attachment data given.
403
     *
404
     * @param   mixed   $attachment
405
     * @return  mixed                   Either an instantiated slack\Attachment, or a passthrough of the input data.
406
     */
407
    protected function resolveAttachment($attachment)
408
    {
409
        if (is_callable($attachment)) {
410
            $callable   = $attachment;
411
            $attachment = new message\Attachment;
412
413
            call_user_func($callable, $attachment);
414
415
            return $attachment;
416
        }
417
418
        if (is_array($attachment)) {
419
            return new message\Attachment($attachment);
420
        }
421
422
        return $attachment;
423
    }
424
}
425