Notif   A
last analyzed

Complexity

Total Complexity 42

Size/Duplication

Total Lines 306
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 100
dl 0
loc 306
ccs 121
cts 121
cp 1
rs 9.0399
c 0
b 0
f 0
wmc 42

28 Methods

Rating   Name   Duplication   Size   Complexity  
A makeTag() 0 3 1
A getCurrentYear() 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 render() 0 4 1
A renderAllHooks() 0 18 2
A getTemplate() 0 2 1
A hash() 0 7 2
A setSubjectTemplate() 0 3 1
A addHook() 0 3 1
A getTags() 0 14 2
A setFromName() 0 3 1
A __construct() 0 4 1
A getArgs() 0 4 1
A getTemplateTags() 0 6 2
A loadTemplate() 0 14 3
A getCurrentDay() 0 3 1
A getHooks() 0 5 1
A getBodyTags() 0 3 1
A getBody() 0 2 1
A renderHook() 0 21 4
A doFart() 0 23 4
A setTemplateDirectory() 0 8 2
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 31
    public function __construct()
34
    {
35 31
        $this->addHook('DATE', 'getDate');
36 31
        $this->addHook('HASH', 'hash');
37
38 31
    }
39
40 3
    public function setBody($body) {
41 3
        $this->body = $body;
42 3
    }
43
44 2
    public function getBody() {
45 2
        return $this->body;
46
    }
47
48 1
    public function setTemplate($template) {
49 1
        $this->template = $template;
50 1
    }
51
52 3
    public function getTemplate() {
53 3
        return $this->template;
54
    }
55
56 8
    public function setTemplateDirectory($directory)
57
    {
58 8
        if (file_exists($directory) === false) {
59 1
            return false;
60
        }
61
62 7
        $this->templateDirectory = $directory;
63 7
        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 8
    public function loadTemplate($template)
73
    {
74 8
        $targetTemplate = $this->templateDirectory . "$template.html";
75
76 8
        if (file_exists($this->templateDirectory) === false) {
77 1
            throw new Exception("Template directory not set!");
78
        }
79 7
        if (file_exists($targetTemplate)          === false) {
80 2
            throw new Exception("Requested template does not exist in $targetTemplate");
81
        }
82
83 5
        $this->template = file_get_contents($targetTemplate);
84
85 5
        return strlen($this->template) > 0;
86
    }
87
88 1
    public function setFromName($name)
89
    {
90 1
        $this->fromName = $name;
91 1
    }
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 2
    public function setFromAddress($email)
101
    {
102 2
        $email = filter_var($email, FILTER_VALIDATE_EMAIL);
103
104 2
        if ($email === false) {
105 1
            throw new Exception("$email is not a valid email address!");
106
        }
107
108 1
        $this->fromAddress = $email;
109
110 1
        return true;
111
    }
112
113 1
    public function setSubjectTemplate($subject)
114
    {
115 1
        $this->subjectTemplate = $subject;
116 1
    }
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 6
    public function addFart($find, $replace)
125
    {
126 6
        $this->fartDictionary[$find] = $replace;
127 6
    }
128
129
    /**
130
     * Returns unmatched, unreplaced tags from the template.
131
     * @return mixed
132
     * @throws Exception
133
     */
134
135 1
    public function getTemplateTags()
136
    {
137 1
        if (strlen($this->template) == 0) {
138 1
            throw new Exception("Template not set!");
139
        }
140 1
        return $this->getTags($this->template);
141
    }
142
143 1
    public function getBodyTags()
144
    {
145 1
        return $this->getTags($this->body);
146
    }
147
148 2
    public function getTags($body)
149
    {
150 2
        $matches = [];
151 2
        preg_match_all($this->tagPattern, $body, $matches, PREG_PATTERN_ORDER);
152
153 2
        $TagFactory = new TagFactory();
154 2
        $buffer = [];
155
156 2
        foreach($matches[0] as $match) {
157 2
            $tag = $TagFactory->getTag($match);
158 2
            $buffer[] = $tag;
159
        }
160
161 2
        return $buffer;
162
    }
163
164 2
    public function getHooks($body)
165
    {
166 2
        $matches = [];
167 2
        preg_match_all($this->hookPattern, $body, $matches, PREG_PATTERN_ORDER);
168 2
        return $matches[0];
169
    }
170
171 11
    public function makeTag($find)
172
    {
173 11
        return sprintf("{{%s}}", strtoupper($find));
174
    }
175
176 11
    public function matchFind($tag, $find)
177
    {
178
        //Remove spaces
179 11
        $tag = str_replace(" ", '', $tag);
180
        //Decorate the find
181 11
        $find = $this->makeTag($find);
182 11
        return (strcmp($tag, $find) === 0);
183
    }
184
185
    /**
186
     * @param $body
187
     * @throws Exception
188
     */
189
190 1
    private function doFart($body, $tags)
191
    {
192
193 1
        foreach ($tags as $tag) {
194
195 1
            $tag->fart($this->fartDictionary);
196
197 1
            if(strpos($body, $tag->getTag()) === false) {
198
                // @codeCoverageIgnoreStart
199
                continue;
200
                // @codeCoverageIgnoreEnd
201
            }
202
203 1
            $body = str_replace($tag->getTag(), $tag->getReplacement(), $body);
204
        }
205
206 1
        $tags = $this->getTags($body);
207
208 1
        if (count($tags) > 0) {
209 1
            $body = $this->doFart($body, $tags);
210
        }
211
212 1
        return $body;
213
    }
214
215
    /**
216
     * @throws Exception
217
     */
218
219 1
    public function render()
220
    {
221 1
        $this->body = $this->doFart($this->template, $this->getTemplateTags());
222 1
        $this->body = $this->renderAllHooks($this->body);
223 1
    }
224
225
    /**
226
     * @param $body
227
     * @return mixed
228
     * @throws Exception
229
     *
230
     */
231
232 1
    public function renderAllHooks($body) {
233 1
        $hooks = $this->getHooks($body);
234 1
        $TagFactory = new TagFactory();
235 1
        $tags = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $tags is dead and can be removed.
Loading history...
236
237 1
        foreach($hooks as $hook) {
238 1
            $Tag = $TagFactory->getTag($hook);
239 1
            $Tag->setReplacement($this->renderHook($hook));
240 1
            $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 1
        return $body;
250
    }
251
252 31
    public function addHook($hook, $callback)
253
    {
254 31
        $this->hooks[$hook] = $callback;
255 31
    }
256
257
    /**
258
     * @param $hook
259
     * @return mixed
260
     * @throws Exception
261
     */
262
263 7
    public function renderHook($hook)
264
    {
265
266 7
        $TagFactory = new TagFactory();
267 7
        $Tag = $TagFactory->getTag($hook);
268 7
        $Tag->fart($this->fartDictionary);
269 7
        $action = $Tag->getLabel();
270
271
        //2. Lookup the callback in the hooks dictionary.
272
273 7
        if(isset($this->hooks[$action]) === false) {
274 1
            throw new Exception('The callback you requested is not registered in the notification hooks.');
275
        }
276
277 7
        $callback = $this->hooks[$action];
278
279 7
        if (method_exists($this, $callback) === false) {
280 1
            throw new Exception("Hook method does not exist! Cannot execute $callback.");
281
        }
282
283 6
        return (count($Tag->getArgs()) == 0 ? $this->$callback() : $this->$callback($Tag->getArgs()));
284
    }
285
286 2
    public function getDate($formatArray)
287
    {
288 2
        $now = new \DateTime();
289 2
        return $now->format($formatArray[0]);
290
    }
291
292 2
    public function getCurrentMonth()
293
    {
294 2
        return $this->getDate(["m"]);
295
    }
296
297 2
    public function getCurrentDay()
298
    {
299 2
        return $this->getDate(["d"]);
300
    }
301
302 2
    public function getCurrentYear()
303
    {
304 2
        return $this->getDate(["Y"]);
305
    }
306
307 3
    public function getArgs($hook) {
308 3
        $Factory = new TagFactory();
309 3
        $Tag = $Factory->getTag($hook);
310 3
        return $Tag->getArgs();
311
    }
312
313 4
    public function hash($args) {
314 4
        $buffer = '';
315 4
        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 4
            $buffer = md5($buffer.$args[$x]);
317
        }
318
319 4
        return $buffer;
320
    }
321
322
}
323