Passed
Push — main ( b7649a...398f47 )
by Michiel
06:32
created

GrowlNotifyTask   B

Complexity

Total Complexity 48

Size/Duplication

Total Lines 454
Duplicated Lines 0 %

Test Coverage

Coverage 76.16%

Importance

Changes 0
Metric Value
wmc 48
eloc 178
dl 0
loc 454
ccs 131
cts 172
cp 0.7616
rs 8.5599
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A setAppicon() 0 17 4
A init() 0 25 2
A __construct() 0 4 1
A setMessage() 0 10 2
A setIcon() 0 17 4
A setName() 0 14 3
C main() 0 83 10
B setPriority() 0 29 7
A setHost() 0 10 2
A setProtocol() 0 18 4
A setNotification() 0 14 3
A setPassword() 0 10 2
A setTitle() 0 14 3
A setSticky() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like GrowlNotifyTask 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.

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 GrowlNotifyTask, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Copyright (c) 2012-2013, Laurent Laville <[email protected]>
4
 *
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 *
11
 *     * Redistributions of source code must retain the above copyright
12
 *       notice, this list of conditions and the following disclaimer.
13
 *     * Redistributions in binary form must reproduce the above copyright
14
 *       notice, this list of conditions and the following disclaimer in the
15
 *       documentation and/or other materials provided with the distribution.
16
 *     * Neither the name of the authors nor the names of its contributors
17
 *       may be used to endorse or promote products derived from this software
18
 *       without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
24
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
 * POSSIBILITY OF SUCH DAMAGE.
31
 *
32
 * PHP version 5
33
 *
34
 * @category Tasks
35
 * @package  phing.tasks.ext
36
 * @author   Laurent Laville <[email protected]>
37
 * @license  http://www.opensource.org/licenses/bsd-license.php  BSD License
38
 * @link     https://github.com/llaville/phing-GrowlNotifyTask
39
 */
40
41
namespace Phing\Task\Optional;
42
43
use Net_Growl;
44
use Net_Growl_Exception;
45
use Phing\Exception\BuildException;
46
use Phing\Project;
47
use Phing\Task;
48
49
50
/**
51
 * Growl notification task for Phing, the PHP build tool.
52
 *
53
 * PHP version 5
54
 *
55
 * @category Tasks
56
 * @package  phing.tasks.ext
57
 * @author   Laurent Laville <[email protected]>
58
 * @license  http://www.opensource.org/licenses/bsd-license.php  BSD License
59
 * @link     https://github.com/llaville/phing-GrowlNotifyTask
60
 */
61
class GrowlNotifyTask extends Task
62
{
63
    protected $growl;
64
65
    protected $name;
66
    protected $sticky;
67
    protected $message;
68
    protected $title;
69
    protected $notification;
70
    protected $appicon;
71
    protected $host;
72
    protected $password;
73
    protected $priority;
74
    protected $protocol;
75
    protected $icon;
76
77
    /**
78
     * Initializes task with default options
79
     *
80
     * @param Net_Growl $growl (optional) mock instance
81
     */
82 14
    public function __construct(Net_Growl $growl = null)
83
    {
84 14
        parent::__construct();
85 14
        $this->growl = $growl;
86 14
    }
87
88
    /**
89
     * The init method check if Net_Growl is available
90
     * (exists and can be loaded)
91
     *
92
     * @return void
93
     * @throws BuildException
94
     */
95 6
    public function init()
96
    {
97 6
        $autoloader = 'Net/Growl/Autoload.php';
98
99 6
        if (!$handle = @fopen($autoloader, 'r', true)) {
100
            throw new BuildException(
101
                'The Growl Notify task requires the pear/net_growl package.'
102
            );
103
        }
104
105 6
        fclose($handle);
106 6
        include_once $autoloader;
107
108 6
        $this->setTaskName('GrowlNotify');
109 6
        $this->setName();
110 6
        $this->setSticky(false);
111 6
        $this->setMessage();
112 6
        $this->setTitle();
113 6
        $this->setNotification();
114 6
        $this->setAppicon();
115 6
        $this->setHost();
116 6
        $this->setPassword();
117 6
        $this->setPriority();
118 6
        $this->setProtocol();
119 6
        $this->setIcon();
120 6
    }
121
122
    /**
123
     * Defines the name of the application sending the notification
124
     *
125
     * @param string $name (optional) Name of the application
126
     *                     that appears in your Growl preferences
127
     *                     Default: "Growl for Phing"
128
     *
129
     * @return void
130
     * @throws BuildException
131
     */
132 6
    public function setName($name = '')
133
    {
134 6
        if ('' == $name) {
135 6
            $name = 'Growl for Phing';
136
        }
137
138 6
        if (!is_string($name)) {
0 ignored issues
show
introduced by
The condition is_string($name) is always true.
Loading history...
139
            throw new BuildException(
140
                '"name" attribute is invalid.' .
141
                ' Expect to be a string, actual is ' . gettype($name)
142
            );
143
        }
144
145 6
        $this->name = $name;
146 6
    }
147
148
    /**
149
     * Indicates if the notification should be sticky
150
     *
151
     * @param bool $sticky (optional) Notification should be sticky
152
     *
153
     * @return void
154
     */
155 7
    public function setSticky(bool $sticky = true)
156
    {
157 7
        $this->sticky = $sticky;
158 7
    }
159
160
    /**
161
     * The notification's text is required.
162
     * Use \n to specify a line break.
163
     *
164
     * @param string $message Notification's text
165
     *
166
     * @return void
167
     * @throws BuildException
168
     */
169 14
    public function setMessage($message = '')
170
    {
171 14
        if (!is_string($message)) {
0 ignored issues
show
introduced by
The condition is_string($message) is always true.
Loading history...
172
            throw new BuildException(
173
                '"message" attribute is invalid.' .
174
                ' Expect to be a string, actual is ' . gettype($message)
175
            );
176
        }
177
178 14
        $this->message = $message;
179 14
    }
180
181
    /**
182
     * The notification's title.
183
     * Use \n to specify a line break.
184
     *
185
     * @param string $title (optional) Notification's title
186
     *                      Default: GrowlNotify
187
     *
188
     * @return void
189
     * @throws BuildException
190
     */
191 7
    public function setTitle($title = '')
192
    {
193 7
        if ('' == $title) {
194 6
            $title = 'GrowlNotify';
195
        }
196
197 7
        if (!is_string($title)) {
0 ignored issues
show
introduced by
The condition is_string($title) is always true.
Loading history...
198
            throw new BuildException(
199
                '"title" attribute is invalid.' .
200
                ' Expect to be a string, actual is ' . gettype($title)
201
            );
202
        }
203
204 7
        $this->title = $title;
205 7
    }
206
207
    /**
208
     * The notification name/type
209
     *
210
     * @param string $notification Name/type
211
     *                             Default: "General Notification"
212
     *
213
     * @return void
214
     * @throws BuildException
215
     */
216 7
    public function setNotification($notification = '')
217
    {
218 7
        if ('' == $notification) {
219 6
            $notification = 'General Notification';
220
        }
221
222 7
        if (!is_string($notification)) {
0 ignored issues
show
introduced by
The condition is_string($notification) is always true.
Loading history...
223
            throw new BuildException(
224
                '"notification" attribute is invalid.' .
225
                ' Expect to be a string, actual is ' . gettype($notification)
226
            );
227
        }
228
229 7
        $this->notification = $notification;
230 7
    }
231
232
    /**
233
     * The icon of the application being registered.
234
     *
235
     * Must be a valid file type (png, jpg, gif, ico).
236
     * Can be any of the following:
237
     *  - absolute url (http://domain/image.png)
238
     *  - absolute file path (c:\temp\image.png)
239
     *  - relative file path (.\folder\image.png) (relative file paths must start
240
     *    with a dot and are relative to GrowlNotify's phing task location
241
     *
242
     * @param string $icon Icon of the application
243
     *
244
     * @return void
245
     * @throws BuildException
246
     */
247 8
    public function setAppicon($icon = '')
248
    {
249 8
        if (!is_string($icon)) {
0 ignored issues
show
introduced by
The condition is_string($icon) is always true.
Loading history...
250
            throw new BuildException(
251
                '"appicon" attribute is invalid.' .
252
                ' Expect to be a string, actual is ' . gettype($icon)
253
            );
254
        }
255
256
        // relative location
257 8
        if (strpos($icon, '..') === 0) {
258 2
            $icon = realpath(__DIR__ . DIRECTORY_SEPARATOR . $icon);
259 6
        } elseif (strpos($icon, '.') === 0) {
260
            $icon = __DIR__ . substr($icon, 1);
261
        }
262
263 8
        $this->appicon = $icon;
264 8
    }
265
266
    /**
267
     * The host address to send the notification to.
268
     *
269
     * If any value other than 'localhost' or '127.0.0.1' is provided, the host
270
     * is considered a remote host and the "pass" attribute must also be provided.
271
     * Default: 127.0.0.1
272
     *
273
     * @param string $host Remote host name/ip
274
     *                     Default: 127.0.0.1
275
     *
276
     * @return void
277
     * @throws BuildException
278
     */
279 7
    public function setHost($host = '127.0.0.1')
280
    {
281 7
        if (!is_string($host)) {
0 ignored issues
show
introduced by
The condition is_string($host) is always true.
Loading history...
282
            throw new BuildException(
283
                '"host" attribute is invalid.' .
284
                ' Expect to be a string, actual is ' . gettype($host)
285
            );
286
        }
287
288 7
        $this->host = $host;
289 7
    }
290
291
    /**
292
     * The password required to send notifications.
293
     *
294
     * A password is required to send a request to a remote host. If host attribute
295
     * is specified and is any value other than 'localhost' or '127.0.0.1',
296
     * then "pass" attribute is also required.
297
     * Default: no password
298
     *
299
     * @param string $password Password to send request to a remote host
300
     *
301
     * @return void
302
     * @throws BuildException
303
     */
304 6
    public function setPassword($password = '')
305
    {
306 6
        if (!is_string($password)) {
0 ignored issues
show
introduced by
The condition is_string($password) is always true.
Loading history...
307
            throw new BuildException(
308
                '"password" attribute is invalid.' .
309
                ' Expect to be a string, actual is ' . gettype($password)
310
            );
311
        }
312
313 6
        $this->password = $password;
314 6
    }
315
316
    /**
317
     * The notification priority.
318
     *
319
     * Valid values are : low, moderate, normal, high, emergency
320
     * Default: normal
321
     *
322
     * @param string $priority Notification priority
323
     *                         Default: normal
324
     *
325
     * @return void
326
     * @throws BuildException
327
     */
328 7
    public function setPriority($priority = '')
329
    {
330 7
        if ('' == $priority) {
331 6
            $priority = 'normal';
332
        }
333
334 7
        switch ($priority) {
335 7
            case 'low':
336
                $priority = Net_Growl::PRIORITY_LOW;
337
                break;
338 7
            case 'moderate':
339
                $priority = Net_Growl::PRIORITY_MODERATE;
340
                break;
341 7
            case 'normal':
342 6
                $priority = Net_Growl::PRIORITY_NORMAL;
343 6
                break;
344 1
            case 'high':
345 1
                $priority = Net_Growl::PRIORITY_HIGH;
346 1
                break;
347
            case 'emergency':
348
                $priority = Net_Growl::PRIORITY_EMERGENCY;
349
                break;
350
            default:
351
                throw new BuildException(
352
                    '"priority" attribute is invalid.'
353
                );
354
        }
355
356 7
        $this->priority = $priority;
357 7
    }
358
359
    /**
360
     * The protocol (and port) to send the notification to.
361
     *
362
     * With TCP (GNTP) protocol, port is always 23053
363
     * With UDP protocol, port is always 9887
364
     * Default: 23053
365
     *
366
     * @param string $protocol Protocol to use to send request to remote host
367
     *                         Default: gntp
368
     *
369
     * @return void
370
     * @throws BuildException
371
     */
372 6
    public function setProtocol($protocol = '')
373
    {
374 6
        if ('' == $protocol) {
375 6
            $protocol = 'gntp';
376
        }
377
378 6
        switch ($protocol) {
379 6
            case 'udp':
380 6
            case 'gntp':
381 6
                break;
382
            default:
383
                throw new BuildException(
384
                    '"protocol" attribute is invalid.' .
385
                    ' Expect to be either udp or gntp.'
386
                );
387
        }
388
389 6
        $this->protocol = $protocol;
390 6
    }
391
392
    /**
393
     * The icon to show for the notification.
394
     *
395
     * Must be a valid file type (png, jpg, gif, ico).
396
     * Can be any of the following:
397
     *  - absolute url (http://domain/image.png)
398
     *  - absolute file path (c:\temp\image.png)
399
     *  - relative file path (.\folder\image.png) (relative file paths must start
400
     *    with a dot and are relative to GrowlNotify's phing task location
401
     *
402
     * @param string $icon Icon of the message
403
     *
404
     * @return void
405
     * @throws BuildException
406
     */
407 7
    public function setIcon($icon = '')
408
    {
409 7
        if (!is_string($icon)) {
0 ignored issues
show
introduced by
The condition is_string($icon) is always true.
Loading history...
410
            throw new BuildException(
411
                '"icon" attribute is invalid.' .
412
                ' Expect to be a string, actual is ' . gettype($icon)
413
            );
414
        }
415
416
        // relative location
417 7
        if (strpos($icon, '..') === 0) {
418 1
            $icon = realpath(__DIR__ . DIRECTORY_SEPARATOR . $icon);
419 6
        } elseif (strpos($icon, '.') === 0) {
420
            $icon = __DIR__ . substr($icon, 1);
421
        }
422
423 7
        $this->icon = $icon;
424 7
    }
425
426
    /**
427
     * The main entry point method
428
     *
429
     * @return void
430
     * @throws BuildException
431
     */
432 14
    public function main()
433
    {
434 14
        if (empty($this->message)) {
435 1
            throw new BuildException(
436 1
                '"message" attribute cannot be empty'
437
            );
438
        }
439
440
        $notifications = [
441 13
            $this->notification
442
        ];
443
        $options = [
444 13
            'host' => $this->host,
445 13
            'protocol' => $this->protocol,
446
        ];
447 13
        if (!empty($this->appicon)) {
448
            $options['AppIcon'] = $this->appicon;
449
        }
450
451
        try {
452 13
            if ($this->growl instanceof Net_Growl) {
453 8
                $growl = $this->growl;
454
            } else {
455 5
                $growl = Net_Growl::singleton(
456 5
                    $this->name,
457
                    $notifications,
458 5
                    $this->password,
459
                    $options
460
                );
461
            }
462 13
            $response = $growl->register();
463
464 13
            if ($this->protocol == 'gntp') {
465 5
                if ($response->getStatus() != 'OK') {
466
                    throw new BuildException(
467
                        'Growl Error ' . $response->getErrorCode() .
468
                        ' - ' . $response->getErrorDescription()
469
                    );
470
                }
471
            }
472 13
            $this->log(
473 13
                'Application ' . $this->name . ' registered',
474 13
                Project::MSG_VERBOSE
475
            );
476
477
            $logRequest = [
478 13
                'Application-Name' => $this->name,
479 13
                'Application-Icon' => $this->appicon,
480 13
                'Notification-Name' => $this->notification,
481 13
                'Notification-Title' => $this->title,
482 13
                'Notification-Text' => $this->message,
483 13
                'Notification-Priority' => $this->priority,
484 13
                'Notification-Icon' => $this->icon,
485 13
                'Notification-Sticky' => $this->sticky,
486
            ];
487 13
            foreach ($logRequest as $key => $value) {
488 13
                $this->log($key . ': ' . $value, Project::MSG_DEBUG);
489
            }
490
491
            $options = [
492 13
                'sticky' => $this->sticky,
493 13
                'priority' => $this->priority,
494 13
                'icon' => $this->icon,
495
            ];
496 13
            $response = $growl->publish(
497 13
                $this->notification,
498 13
                $this->title,
499 13
                $this->message,
500
                $options
0 ignored issues
show
Bug introduced by
$options of type array is incompatible with the type string expected by parameter $options of Net_Growl::publish(). ( Ignorable by Annotation )

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

500
                /** @scrutinizer ignore-type */ $options
Loading history...
501
            );
502
503 13
            if ($this->protocol == 'gntp') {
504 5
                if ($response->getStatus() != 'OK') {
505
                    throw new BuildException(
506
                        'Growl Error ' . $response->getErrorCode() .
507
                        ' - ' . $response->getErrorDescription()
508
                    );
509
                }
510
            }
511 13
            $this->log('Notification was sent to remote host ' . $this->host);
512
        } catch (Net_Growl_Exception $e) {
513
            throw new BuildException(
514
                'Growl Exception : ' . $e->getMessage()
515
            );
516
        }
517 13
    }
518
}
519