Metagen   B
last analyzed

Complexity

Total Complexity 43

Size/Duplication

Total Lines 416
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 200
c 3
b 0
f 0
dl 0
loc 416
rs 8.96
wmc 43

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 2
A html2text() 0 54 2
A createMetaKeywords() 0 11 2
A autoBuildMetaKeywords() 0 2 1
A emptyString() 0 3 1
C setTitle() 0 27 12
A findMetaKeywords() 0 18 5
B generateSeoTitle() 0 72 4
A setKeywords() 0 3 1
A purifyText() 0 32 2
A setDescription() 0 5 1
A createMetaTags() 0 11 4
A setCategoryPath() 0 4 1
A createMetaDescription() 0 17 3
A buildAutoMetaTags() 0 4 1
A createTitleTag() 0 2 1

How to fix   Complexity   

Complex Class

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

1
<?php declare(strict_types=1);
2
3
namespace XoopsModules\Publisher;
4
5
/*
6
 You may not change or alter any portion of this comment or credits
7
 of supporting developers from this source code or any supporting source code
8
 which is considered copyrighted (c) material of the original comment or credit authors.
9
10
 This program is distributed in the hope that it will be useful,
11
 but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
 */
14
15
/**
16
 * @copyright       XOOPS Project (https://xoops.org)
17
 * @license         https://www.fsf.org/copyleft/gpl.html GNU public license
18
 * @since           1.0
19
 * @author          trabis <[email protected]>
20
 * @author          The SmartFactory <www.smartfactory.ca>
21
 */
22
require_once \dirname(__DIR__) . '/include/common.php';
23
24
/**
25
 * Class Metagen
26
 */
27
class Metagen
28
{
29
    /**
30
     * @var Helper
31
     */
32
    public $helper;
33
    /**
34
     * @var \MyTextSanitizer
35
     */
36
    public $myts;
37
    /**
38
     * @var string
39
     */
40
    public $title;
41
    /**
42
     * @var string
43
     */
44
    public $originalTitle;
45
    /**
46
     * @var string
47
     */
48
    public $keywords;
49
    /**
50
     * @var string
51
     */
52
    public $categoryPath;
53
    /**
54
     * @var string
55
     */
56
    public $description;
57
    /**
58
     * @var int
59
     */
60
    public $minChar = 4;
61
62
    /**
63
     * @param string $title
64
     * @param string $keywords
65
     * @param string $description
66
     * @param string $categoryPath
67
     */
68
    public function __construct($title, $keywords = '', $description = '', $categoryPath = '')
69
    {
70
        /** @var Helper $this- >helper */
71
        $this->helper = Helper::getInstance();
72
        $this->myts   = \MyTextSanitizer::getInstance();
73
        $this->setCategoryPath($categoryPath);
74
        $this->setTitle($title);
75
        $this->setDescription($description);
76
        if ('' == $keywords) {
77
            $keywords = $this->createMetaKeywords();
78
        }
79
        $this->setKeywords($keywords);
80
    }
81
82
    /**
83
     * @param string $title
84
     */
85
    public function setTitle($title): void
86
    {
87
        $this->title         = $this->html2text($title);
88
        $this->originalTitle = $this->title;
89
        $titleTag            = [];
90
        $titleTag['module']  = $this->helper->getModule()
91
                                            ->getVar('name');
92
        if (isset($this->title) && ('' != $this->title) && (\mb_strtoupper($this->title) != \mb_strtoupper($titleTag['module']))) {
93
            $titleTag['title'] = $this->title;
94
        }
95
        if (isset($this->categoryPath) && ('' != $this->categoryPath)) {
96
            $titleTag['category'] = $this->categoryPath;
97
        }
98
        $ret = $titleTag['title'] ?? '';
99
        if (isset($titleTag['category']) && '' != $titleTag['category']) {
100
            if ('' != $ret) {
101
                $ret .= ' - ';
102
            }
103
            $ret .= $titleTag['category'];
104
        }
105
        if (isset($titleTag['module']) && '' != $titleTag['module']) {
106
            if ('' != $ret) {
107
                $ret .= ' - ';
108
            }
109
            $ret .= $titleTag['module'];
110
        }
111
        $this->title = $ret;
112
    }
113
114
    /**
115
     * @param string $keywords
116
     */
117
    public function setKeywords($keywords): void
118
    {
119
        $this->keywords = $keywords;
120
    }
121
122
    /**
123
     * @param string $categoryPath
124
     */
125
    public function setCategoryPath($categoryPath): void
126
    {
127
        $categoryPath       = $this->html2text($categoryPath);
128
        $this->categoryPath = $categoryPath;
129
    }
130
131
    /**
132
     * @param string $description
133
     */
134
    public function setDescription($description): void
135
    {
136
        $description       = $this->html2text($description);
137
        $description       = $this->purifyText($description);
138
        $this->description = $description;
139
    }
140
141
    /**
142
     * Does nothing
143
     */
144
    public function createTitleTag(): void
145
    {
146
    }
147
148
    /**
149
     * @param int $maxWords
150
     *
151
     * @return string
152
     */
153
    public function createMetaDescription($maxWords = 30)
0 ignored issues
show
Unused Code introduced by
The parameter $maxWords is not used and could be removed. ( Ignorable by Annotation )

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

153
    public function createMetaDescription(/** @scrutinizer ignore-unused */ $maxWords = 30)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
154
    {
155
        $description = $this->purifyText($this->description);
156
        $description = $this->html2text($description);
157
        $words       = \explode(' ', $description);
158
        $ret         = '';
159
        $i           = 1;
160
        $wordCount   = \count($words);
161
        foreach ($words as $word) {
162
            $ret .= $word;
163
            if ($i < $wordCount) {
164
                $ret .= ' ';
165
            }
166
            ++$i;
167
        }
168
169
        return $ret;
170
    }
171
172
    /**
173
     * @param string $text
174
     * @param int    $minChar
175
     *
176
     * @return array
177
     */
178
    public function findMetaKeywords($text, $minChar)
179
    {
180
        $keywords         = [];
181
        $text             = $this->purifyText($text);
182
        $text             = $this->html2text($text);
183
        $originalKeywords = \explode(' ', $text);
184
        foreach ($originalKeywords as $originalKeyword) {
185
            $secondRoundKeywords = \explode("'", $originalKeyword);
186
            foreach ($secondRoundKeywords as $secondRoundKeyword) {
187
                if (\mb_strlen($secondRoundKeyword) >= $minChar) {
188
                    if (!\in_array($secondRoundKeyword, $keywords, true)) {
189
                        $keywords[] = \trim($secondRoundKeyword);
190
                    }
191
                }
192
            }
193
        }
194
195
        return $keywords;
196
    }
197
198
    /**
199
     * @return string
200
     */
201
    public function createMetaKeywords()
202
    {
203
        $keywords       = $this->findMetaKeywords($this->originalTitle . ' ' . $this->description, $this->minChar);
204
        $moduleKeywords = $this->helper->getConfig('seo_meta_keywords');
205
        if ('' != $moduleKeywords) {
206
            $moduleKeywords = \explode(',', $moduleKeywords);
0 ignored issues
show
Bug introduced by
It seems like $moduleKeywords can also be of type null; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

206
            $moduleKeywords = \explode(',', /** @scrutinizer ignore-type */ $moduleKeywords);
Loading history...
207
            $keywords       = \array_merge($keywords, \array_map('\trim', $moduleKeywords));
208
        }
209
        $ret = \implode(',', $keywords);
210
211
        return $ret;
212
    }
213
214
    /**
215
     * Does nothing
216
     */
217
    public function autoBuildMetaKeywords(): void
218
    {
219
    }
220
221
    /**
222
     * Build Metatags
223
     */
224
    public function buildAutoMetaTags(): void
225
    {
226
        $this->keywords    = $this->createMetaKeywords();
227
        $this->description = $this->createMetaDescription();
228
        //$this->title = $this->createTitleTag();
229
    }
230
231
    /**
232
     * Creates meta tags
233
     */
234
    public function createMetaTags(): void
235
    {
236
        global $xoopsTpl, $xoTheme;
237
        if ('' != $this->keywords) {
238
            $xoTheme->addMeta('meta', 'keywords', $this->keywords);
239
        }
240
        if ('' != $this->description) {
241
            $xoTheme->addMeta('meta', 'description', $this->description);
242
        }
243
        if ('' != $this->title) {
244
            $xoopsTpl->assign('xoops_pagetitle', $this->title);
245
        }
246
    }
247
248
    /**
249
     * Return true if the string is length > 0
250
     *
251
     * @credit psylove
252
     * @param mixed $var
253
     * @return bool
254
     */
255
    public static function emptyString($var)
256
    {
257
        return ('' !== $var);
258
    }
259
260
    /**
261
     * Create a title for the short_url field of an article
262
     *
263
     * @credit psylove
264
     *
265
     * @param string|array $title   title of the article
266
     * @param bool         $withExt do we add an html extension or not
267
     *
268
     * @return string short url for article
269
     */
270
    public static function generateSeoTitle($title = '', $withExt = true)
271
    {
272
        // Transformation de la chaine en minuscule
273
        // Codage de la chaine afin d'éviter les erreurs 500 en cas de caractères imprévus
274
        $title = \rawurlencode(\mb_strtolower($title));
0 ignored issues
show
Bug introduced by
It seems like $title can also be of type array; however, parameter $string of mb_strtolower() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

274
        $title = \rawurlencode(\mb_strtolower(/** @scrutinizer ignore-type */ $title));
Loading history...
275
        // Transformation des ponctuations
276
277
        $pattern = [
278
            '/%09/', // Tab
279
            '/%20/', // Space
280
            '/%21/', // !
281
            '/%22/', // "
282
            '/%23/', // #
283
            '/%25/', // %
284
            '/%26/', // &
285
            '/%27/', // '
286
            '/%28/', // (
287
            '/%29/', // )
288
            '/%2C/', // ,
289
            '/%2F/', // /
290
            '/%3A/', // :
291
            '/%3B/', // ;
292
            '/%3C/', // <
293
            '/%3D/', // =
294
            '/%3E/', // >
295
            '/%3F/', // ?
296
            '/%40/', // @
297
            '/%5B/', // [
298
            '/%5C/', // \
299
            '/%5D/', // ]
300
            '/%5E/', // ^
301
            '/%7B/', // {
302
            '/%7C/', // |
303
            '/%7D/', // }
304
            '/%7E/', // ~
305
            '/\./', // .
306
        ];
307
        $repPat  = ['-', '-', '-', '-', '-', '-100', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-at-', '-', '-', '-', '-', '-', '-', '-', '-', '-'];
308
        $title   = \preg_replace($pattern, $repPat, $title);
309
        // Transformation des caractères accentués
310
        $pattern = [
311
            '/%B0/', // °
312
            '/%E8/', // è
313
            '/%E9/', // é
314
            '/%EA/', // ê
315
            '/%EB/', // ë
316
            '/%E7/', // ç
317
            '/%E0/', // à
318
            '/%E2/', // â
319
            '/%E4/', // ä
320
            '/%EE/', // î
321
            '/%EF/', // ï
322
            '/%F9/', // ù
323
            '/%FC/', // ü
324
            '/%FB/', // û
325
            '/%F4/', // ô
326
            '/%F6/', // ö
327
        ];
328
        $repPat  = ['-', 'e', 'e', 'e', 'e', 'c', 'a', 'a', 'a', 'i', 'i', 'u', 'u', 'u', 'o', 'o'];
329
        $title   = \preg_replace($pattern, $repPat, $title);
330
        $tableau = \explode('-', $title); // Transforms the string in table //Transforme la chaine de caractères en tableau
331
        $tableau = \array_filter($tableau, [__CLASS__, 'emptyString']); // Remove empty strings of the table //Supprime les chaines vides du tableau
332
        $title   = \implode('-', $tableau); // Transforms a character string in table separated by a hyphen //Transforme un tableau en chaine de caractères séparé par un tiret
333
        if ($title && !(\is_array($title))) {
334
            if ($withExt) {
335
                $title .= '.html';
336
            }
337
338
            return $title;
339
        }
340
341
        return '';
342
    }
343
344
    /**
345
     * @param      $text
346
     * @param bool $keyword
347
     *
348
     * @return mixed
349
     */
350
    public function purifyText($text, $keyword = false)
351
    {
352
        //        $text = str_replace(['&nbsp;', ' '], ['<br>', ' '], $text); //for php 5.4
353
        $text = \str_replace('&nbsp;', ' ', $text);
354
        $text = \str_replace('<br>', ' ', $text);
355
        $text = \strip_tags($text);
356
        $text = \html_entity_decode($text);
357
        $text = $this->myts->undoHtmlSpecialChars($text);
358
359
        $text = \str_replace(')', ' ', $text);
360
        $text = \str_replace('(', ' ', $text);
361
        $text = \str_replace(':', ' ', $text);
362
        $text = \str_replace('&euro', ' euro ', $text);
363
        $text = \str_replace('&hellip', '...', $text);
364
        $text = \str_replace('&rsquo', ' ', $text);
365
        $text = \str_replace('!', ' ', $text);
366
        $text = \str_replace('?', ' ', $text);
367
        $text = \str_replace('"', ' ', $text);
368
        $text = \str_replace('-', ' ', $text);
369
        $text = \str_replace('\n', ' ', $text);
370
371
        //        $text = str_replace([')','(',':','&euro','&hellip','&rsquo','!','?','"','-','\n'], [' ' , ' ',  ' ',  ' euro ',  '...',  ' ', ' ', ' ',  ' ', ' ',  ' '], $text); //for PHP 5.4
372
373
        if ($keyword) {
374
            $text = \str_replace('.', ' ', $text);
375
            $text = \str_replace(',', ' ', $text);
376
            $text = \str_replace('\'', ' ', $text);
377
            //            $text = str_replace(['.', ' '], [',', ' '], ['\'', ' '], $text); //for PHP 5.4
378
        }
379
        $text = \str_replace(';', ' ', $text);
380
381
        return $text;
382
    }
383
384
    /**
385
     * @param string $document
386
     *
387
     * @return mixed
388
     */
389
    public function html2text($document)
390
    {
391
        if (empty($document)) {
392
            return '';
393
        }
394
        // PHP Manual:: function preg_replace
395
        // $document should contain an HTML document.
396
        // This will remove HTML tags, javascript sections
397
        // and white space. It will also convert some
398
        // common HTML entities to their text equivalent.
399
        // Credits : newbb2
400
        $search = [
401
            "'<script[^>]*?>.*?</script>'si", // Strip out javascript
402
            "'<img.*?>'si", // Strip out img tags
403
            "'<[\/\!]*?[^<>]*?>'si", // Strip out HTML tags
404
            "'([\r\n])[\s]+'", // Strip out white space
405
            "'&(quot|#34);'i", // Replace HTML entities
406
            "'&(amp|#38);'i",
407
            "'&(lt|#60);'i",
408
            "'&(gt|#62);'i",
409
            "'&(nbsp|#160);'i",
410
            "'&(iexcl|#161);'i",
411
            "'&(cent|#162);'i",
412
            "'&(pound|#163);'i",
413
            "'&(copy|#169);'i",
414
        ]; // evaluate as php
415
416
        $replace = [
417
            '',
418
            '',
419
            '',
420
            '\\1',
421
            '"',
422
            '&',
423
            '<',
424
            '>',
425
            ' ',
426
            \chr(161),
427
            \chr(162),
428
            \chr(163),
429
            \chr(169),
430
        ];
431
432
        $text = \preg_replace($search, $replace, $document);
433
434
        \preg_replace_callback(
435
            '/&#(\d+);/',
436
            static function ($matches) {
437
                return \chr((int)($matches[1]));
438
            },
439
            $document
440
        );
441
442
        return $text;
443
    }
444
}
445