Test Setup Failed
Push — master ( 015ad6...183045 )
by Michael
02:22
created

Notif   A

Complexity

Total Complexity 42

Size/Duplication

Total Lines 306
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 100
dl 0
loc 306
rs 9.0399
c 0
b 0
f 0
wmc 42

28 Methods

Rating   Name   Duplication   Size   Complexity  
A makeTag() 0 3 1
A addFart() 0 3 1
A setTemplate() 0 2 1
A setFromAddress() 0 11 2
A matchFind() 0 7 1
A setBody() 0 2 1
A getTemplate() 0 2 1
A setSubjectTemplate() 0 3 1
A getTags() 0 14 2
A setFromName() 0 3 1
A __construct() 0 4 1
A getTemplateTags() 0 6 2
A loadTemplate() 0 14 3
A getHooks() 0 5 1
A getBodyTags() 0 3 1
A getBody() 0 2 1
A setTemplateDirectory() 0 8 2
A getCurrentYear() 0 3 1
A render() 0 4 1
A renderAllHooks() 0 18 2
A hash() 0 7 2
A addHook() 0 3 1
A getArgs() 0 4 1
A getCurrentDay() 0 3 1
A renderHook() 0 21 4
A doFart() 0 23 4
A getDate() 0 4 1
A getCurrentMonth() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like Notif 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 Notif, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * {CLASS SUMMARY}
4
 *
5
 * Date: 7/26/18
6
 * Time: 6:54 PM
7
 * @author Michael Munger <[email protected]>
8
 */
9
10
namespace HPHIO\Farret;
11
12
use \Exception;
13
14
class Notif
15
{
16
    private $tagPattern       = '/\{{2} {0,2}([A-Z]+) {0,2}\}{2}/';
17
    private $hookPattern      = '/(?:{\%\s{0,})([A-Z]+)\s{0,}((\|(?:{{){0,1}[A-Za-z0-9-]+(?:}}){0,1}\s{0,}){0,})(?:\%})/';
18
19
    public $templateDirectory = null;
20
    public $template          = null;
21
    public $fromName          = null;
22
    public $fromAddress       = null;
23
    public $subjectTemplate   = null;
24
    public $body              = null;
25
26
    public $to                = [];
27
    public $cc                = [];
28
    public $bcc               = [];
29
    public $fartDictionary    = [];
30
31
    public $hooks             = [];
32
33
    public function __construct()
34
    {
35
        $this->addHook('DATE', 'getDate');
36
        $this->addHook('HASH', 'hash');
37
38
    }
39
40
    public function setBody($body) {
41
        $this->body = $body;
42
    }
43
44
    public function getBody() {
45
        return $this->body;
46
    }
47
48
    public function setTemplate($template) {
49
        $this->template = $template;
50
    }
51
52
    public function getTemplate() {
53
        return $this->template;
54
    }
55
56
    public function setTemplateDirectory($directory)
57
    {
58
        if (file_exists($directory) === false) {
59
            return false;
60
        }
61
62
        $this->templateDirectory = $directory;
63
        return file_exists($this->templateDirectory);
64
    }
65
66
    /**
67
     * Loads a template from the template directory.
68
     * @param $template
69
     * @throws Exception
70
     */
71
72
    public function loadTemplate($template)
73
    {
74
        $targetTemplate = $this->templateDirectory . "$template.html";
75
76
        if (file_exists($this->templateDirectory) === false) {
77
            throw new Exception("Template directory not set!");
78
        }
79
        if (file_exists($targetTemplate)          === false) {
80
            throw new Exception("Requested template does not exist in $targetTemplate");
81
        }
82
83
        $this->template = file_get_contents($targetTemplate);
84
85
        return strlen($this->template) > 0;
86
    }
87
88
    public function setFromName($name)
89
    {
90
        $this->fromName = $name;
91
    }
92
93
    /**
94
     * Validates an email passed to it, and if valid, sets the from address for the email notification.
95
     * @param $email
96
     * @return bool
97
     * @throws Exception
98
     */
99
100
    public function setFromAddress($email)
101
    {
102
        $email = filter_var($email, FILTER_VALIDATE_EMAIL);
103
104
        if ($email === false) {
105
            throw new Exception("$email is not a valid email address!");
106
        }
107
108
        $this->fromAddress = $email;
109
110
        return true;
111
    }
112
113
    public function setSubjectTemplate($subject)
114
    {
115
        $this->subjectTemplate = $subject;
116
    }
117
118
    /**
119
     * Adds a Find And Replace Template pair. These will be used to find {{ TEMPLATETAGS }} and perform a substitution.
120
     * @param $find
121
     * @param $replace
122
     */
123
124
    public function addFart($find, $replace)
125
    {
126
        $this->fartDictionary[$find] = $replace;
127
    }
128
129
    /**
130
     * Returns unmatched, unreplaced tags from the template.
131
     * @return mixed
132
     * @throws Exception
133
     */
134
135
    public function getTemplateTags()
136
    {
137
        if (strlen($this->template) == 0) {
138
            throw new Exception("Template not set!");
139
        }
140
        return $this->getTags($this->template);
141
    }
142
143
    public function getBodyTags()
144
    {
145
        return $this->getTags($this->body);
146
    }
147
148
    public function getTags($body)
149
    {
150
        $matches = [];
151
        preg_match_all($this->tagPattern, $body, $matches, PREG_PATTERN_ORDER);
152
153
        $TagFactory = new TagFactory();
154
        $buffer = [];
155
156
        foreach($matches[0] as $match) {
157
            $tag = $TagFactory->getTag($match);
158
            $buffer[] = $tag;
159
        }
160
161
        return $buffer;
162
    }
163
164
    public function getHooks($body)
165
    {
166
        $matches = [];
167
        preg_match_all($this->hookPattern, $body, $matches, PREG_PATTERN_ORDER);
168
        return $matches[0];
169
    }
170
171
    public function makeTag($find)
172
    {
173
        return sprintf("{{%s}}", strtoupper($find));
174
    }
175
176
    public function matchFind($tag, $find)
177
    {
178
        //Remove spaces
179
        $tag = str_replace(" ", '', $tag);
180
        //Decorate the find
181
        $find = $this->makeTag($find);
182
        return (strcmp($tag, $find) === 0);
183
    }
184
185
    /**
186
     * @param $body
187
     * @throws Exception
188
     */
189
190
    private function doFart($body, $tags)
191
    {
192
193
        foreach ($tags as $tag) {
194
195
            $tag->fart($this->fartDictionary);
196
197
            if(strpos($body, $tag->getTag()) === false) {
198
                // @codeCoverageIgnoreStart
199
                continue;
200
                // @codeCoverageIgnoreEnd
201
            }
202
203
            $body = str_replace($tag->getTag(), $tag->getReplacement(), $body);
204
        }
205
206
        $tags = $this->getTags($body);
207
208
        if (count($tags) > 0) {
209
            $body = $this->doFart($body, $tags);
210
        }
211
212
        return $body;
213
    }
214
215
    /**
216
     * @throws Exception
217
     */
218
219
    public function render()
220
    {
221
        $this->body = $this->doFart($this->template, $this->getTemplateTags());
222
        $this->body = $this->renderAllHooks($this->body);
223
    }
224
225
    /**
226
     * @param $body
227
     * @return mixed
228
     * @throws Exception
229
     *
230
     */
231
232
    public function renderAllHooks($body) {
233
        $hooks = $this->getHooks($body);
234
        $TagFactory = new TagFactory();
235
        $tags = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $tags is dead and can be removed.
Loading history...
236
237
        foreach($hooks as $hook) {
238
            $Tag = $TagFactory->getTag($hook);
239
            $Tag->setReplacement($this->renderHook($hook));
240
            $body = str_replace($hook, $Tag->getReplacement(), $body);
241
        }
242
243
        // Hooks are not recursive now. But they could be if we uncomment this.
244
        // $hooks = $this->getHooks($body);
245
        // if(count($hooks) > 0) {
246
        //     $this->renderAllHooks($body);
247
        // }
248
249
        return $body;
250
    }
251
252
    public function addHook($hook, $callback)
253
    {
254
        $this->hooks[$hook] = $callback;
255
    }
256
257
    /**
258
     * @param $hook
259
     * @return mixed
260
     * @throws Exception
261
     */
262
263
    public function renderHook($hook)
264
    {
265
266
        $TagFactory = new TagFactory();
267
        $Tag = $TagFactory->getTag($hook);
268
        $Tag->fart($this->fartDictionary);
269
        $action = $Tag->getLabel();
270
271
        //2. Lookup the callback in the hooks dictionary.
272
273
        if(isset($this->hooks[$action]) === false) {
274
            throw new Exception('The callback you requested is not registered in the notification hooks.');
275
        }
276
277
        $callback = $this->hooks[$action];
278
279
        if (method_exists($this, $callback) === false) {
280
            throw new Exception("Hook method does not exist! Cannot execute $callback.");
281
        }
282
283
        return (count($Tag->getArgs()) == 0 ? $this->$callback() : $this->$callback($Tag->getArgs()));
284
    }
285
286
    public function getDate($formatArray)
287
    {
288
        $now = new \DateTime();
289
        return $now->format($formatArray[0]);
290
    }
291
292
    public function getCurrentMonth()
293
    {
294
        return $this->getDate(["m"]);
295
    }
296
297
    public function getCurrentDay()
298
    {
299
        return $this->getDate(["d"]);
300
    }
301
302
    public function getCurrentYear()
303
    {
304
        return $this->getDate(["Y"]);
305
    }
306
307
    public function getArgs($hook) {
308
        $Factory = new TagFactory();
309
        $Tag = $Factory->getTag($hook);
310
        return $Tag->getArgs();
311
    }
312
313
    public function hash($args) {
314
        $buffer = '';
315
        for($x = 0; $x < count($args); $x++ ) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
316
            $buffer = md5($buffer.$args[$x]);
317
        }
318
319
        return $buffer;
320
    }
321
322
}
323