Growl   A
last analyzed

Complexity

Total Complexity 29

Size/Duplication

Total Lines 230
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 100%

Importance

Changes 28
Bugs 2 Features 8
Metric Value
wmc 29
c 28
b 2
f 8
lcom 1
cbo 5
dl 0
loc 230
ccs 50
cts 50
cp 1
rs 10

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __toString() 0 4 1
A setSafe() 0 18 4
A __construct() 0 15 3
A execute() 0 10 3
A buildCommand() 0 11 3
A setOption() 0 6 1
A setOptions() 0 8 2
A setEscape() 0 6 1
A escape() 0 13 3
B selectBuilder() 0 21 8
1
<?php
2
3
namespace BryanCrowe\Growl;
4
5
use BryanCrowe\Growl\Builder\BuilderAbstract;
6
use BryanCrowe\Growl\Builder\GrowlNotifyBuilder;
7
use BryanCrowe\Growl\Builder\GrowlNotifyWindowsBuilder;
8
use BryanCrowe\Growl\Builder\NotifySendBuilder;
9
use BryanCrowe\Growl\Builder\TerminalNotifierBuilder;
10
use InvalidArgumentException;
11
12
/**
13
 * This class optionally accepts a Builder in its constructor to be used for
14
 * building the growl/notification command. It contains various methods to set
15
 * command options, toggling escaping, whitelisting fields, and finally
16
 * building and/or executing the command.
17
 */
18
class Growl
19
{
20
    /**
21
     * The Builder to use for building the command.
22
     *
23
     * @var \BryanCrowe\Growl\Builder\BuilderAbstract
24
     */
25
    protected $builder = null;
26
27
    /**
28
     * Stores the built command when treating this object like a string.
29
     *
30
     * @var string
31
     */
32
    protected $command = '';
33
34
    /**
35
     * An array of options to use for building commands.
36
     *
37
     * @var array
38
     */
39
    protected $options = [];
40
41
    /**
42
     * Whether or not to escape the command arguments.
43
     *
44
     * @var boolean
45
     */
46
    protected $escape = true;
47
48
    /**
49
     * An array of options that are considered safe and should not be escaped
50
     * while escaping is turned on.
51
     *
52
     * @var array
53
     */
54
    protected $safe = [];
55
56
    /**
57
     * Constructor.
58
     *
59
     * Accepts a Builder object to be used in building the command.
60
     *
61
     * @param \BryanCrowe\Growl\Builder\BuilderAbstract $builder
62
     * @throws \InvalidArgumentException If not null or a BuilderAbstract
63
     * instance.
64
     */
65 24
    public function __construct($builder = null)
66
    {
67 24
        if ($builder === null) {
68 3
            $this->builder = $this->selectBuilder();
69 3
            return;
70
        }
71 24
        if ($builder instanceof BuilderAbstract) {
72 24
            $this->builder = $builder;
73 24
            return;
74
        }
75
76 3
        throw new InvalidArgumentException(
77
            'This constructor expects null or a BuilderAbstract instance.'
78 3
        );
79
    }
80
81
    /**
82
     * Allow this object to be treated as a string in the case of using the
83
     * buildCommand() method instead of executing the command.
84
     *
85
     * @return string
86
     */
87 3
    public function __toString()
88
    {
89 3
        return $this->command;
90
    }
91
92
    /**
93
     * Executes the command on your machine.
94
     *
95
     * @codeCoverageIgnore
96
     * @return void
97
     */
98
    public function execute()
99
    {
100
        if ($this->escape !== false) {
101
            $this->options = $this->escape($this->options);
102
        }
103
        if ($this->builder !== null) {
104
            $command = $this->builder->build($this->options);
105
            exec($command);
106
        }
107
    }
108
109
    /**
110
     * Builds the command.
111
     *
112
     * @return string
113
     */
114 3
    public function buildCommand()
115
    {
116 3
        if ($this->escape !== false) {
117 3
            $this->options = $this->escape($this->options);
118 3
        }
119 3
        if ($this->builder !== null) {
120 3
            $this->command = $this->builder->build($this->options);
121 3
        }
122
123 3
        return $this;
124
    }
125
126
    /**
127
     * Set options for Builders with a key/value.
128
     *
129
     * @param string $key The key.
130
     * @param array $value The value of the key.
131
     * @return $this
132
     */
133 3
    public function setOption($key, $value)
134
    {
135 3
        $this->options[$key] = $value;
136
137 3
        return $this;
138
    }
139
140
    /**
141
     * Set an entire set of options for a Builder. This is available so a user
142
     * bulk-set options rather than chaining set() calls.
143
     *
144
     * @param array $options The entire set of options.
145
     * @return $this
146
     */
147 6
    public function setOptions(array $options)
148
    {
149 6
        foreach ($options as $key => $value) {
150 6
            $this->options[$key] = $value;
151 6
        }
152
153 6
        return $this;
154
    }
155
156
    /**
157
     * Set the escape properties value. Set it to false to disable command
158
     * argument escaping.
159
     *
160
     * @param boolean $value Pass false to disable escaping.
161
     * @return $this
162
     */
163 3
    public function setEscape($value)
164
    {
165 3
        $this->escape = $value;
166
167 3
        return $this;
168
    }
169
170
    /**
171
     * Sets option names that are considered safe, in order to bypass escaping.
172
     *
173
     * @param mixed A string or array of option names assumed to be safe from
174
     * escaping.
175
     * @throws \InvalidArgumentException If the method argument isn't a string or
176
     * array.
177
     * @return $this
178
     */
179 12
    public function setSafe($options)
180
    {
181 12
        if (is_string($options)) {
182 9
            $this->safe[] = $options;
183 9
            return $this;
184
        }
185
186 6
        if (is_array($options)) {
187 3
            foreach ($options as $key => $value) {
188 3
                $this->safe[] = $value;
189 3
            }
190 3
            return $this;
191
        }
192
193 3
        throw new InvalidArgumentException(
194
            'This method expects a string or an array argument.'
195 3
        );
196
    }
197
198
    /**
199
     * Escapes the set of option values.
200
     *
201
     * @param array A set of key/value options.
202
     * @return array The sanitized set of key/value options.
203
     */
204 6
    protected function escape(array $options)
205
    {
206 6
        $results = [];
207 6
        foreach ($options as $key => $value) {
208 6
            if (!in_array($key, $this->safe)) {
209 6
                $results[$key] = escapeshellarg($value);
210 6
            } else {
211 6
                $results[$key] = $value;
212
            }
213 6
        }
214
215 6
        return $results;
216
    }
217
218
    /**
219
     * Chooses a Builder to use depending on the operating system and which
220
     * program is installed.
221
     *
222
     * @codeCoverageIgnore
223
     * @return \BryanCrowe\Growl\Builder\BuilderAbstract A suitable Builder for
224
     * a notification program that was found on the system.
225
     */
226
    protected function selectBuilder()
227
    {
228
        if (PHP_OS === 'Darwin') {
229
            if (exec('which growlnotify')) {
230
                return new GrowlNotifyBuilder;
231
            }
232
            if (exec('which terminal-notifier')) {
233
                return new TerminalNotifierBuilder;
234
            }
235
        }
236
        if (PHP_OS === 'Linux') {
237
            if (exec('which notify-send')) {
238
                return new NotifySendBuilder;
239
            }
240
        }
241
        if (PHP_OS === 'WINNT') {
242
            if (exec('where growlnotify')) {
243
                return new GrowlNotifyWindowsBuilder;
244
            }
245
        }
246
    }
247
}
248