Handler::testPattern()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 13
nc 2
nop 1
dl 0
loc 23
rs 9.8333
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace MazenTouati\NoEmoji;
5
6
use MazenTouati\Simple2wayConfig\S2WConfig;
7
use MazenTouati\NoEmoji\Entities\File;
8
use MazenTouati\NoEmoji\Entities\GroupsFactory;
9
use MazenTouati\NoEmoji\Entities\Group;
10
11
/**
12
 * Uses the scrapped unicodes to generate a RegEx pattern
13
 *
14
 * @author Mazen Touati <[email protected]>
15
 */
16
class Handler
17
{
18
    /**
19
     * The class instance
20
     *
21
     * @var Handler
22
     */
23
    private static $_instance = null;
24
25
    /**
26
     * Emoji unicodes
27
     *
28
     * @var array
29
     */
30
    private $_unicodes = [];
31
32
    /**
33
     * Unicodes as intervals
34
     *
35
     * @var array
36
     */
37
    private $_ranges = [];
38
39
    /**
40
     * The produced pattern
41
     *
42
     * @var string
43
     */
44
    private $_pattern = '';
45
46
    /**
47
     * Configuration object
48
     *
49
     * @var S2WConfig
50
     */
51
    public $config;
52
53
    /**
54
     * Retrieves the singleton instance
55
     *
56
     * @return Handler
57
     */
58
    public static function getInstance()
59
    {
60
        if (self::$_instance == null) {
61
            self::$_instance = new Handler();
62
        }
63
64
        return self::$_instance;
65
    }
66
67
    /**
68
     * Initializes the Scrapper
69
     *
70
     * @param S2WConfig $c Configuration object
71
     *
72
     * @return Handler
73
     */
74
    public static function factory(S2WConfig $c)
75
    {
76
        $instance = self::getInstance();
77
        $instance->config = $c;
78
79
        $file = new File($c, 'storage.output.json');
80
        $instance->_unicodes = $file->fromJSON(true);
81
82
        return $instance;
83
    }
84
85
    /**
86
     * Starts the Handling
87
     *
88
     * @return Handler
89
     */
90
    public function run()
91
    {
92
        $this->_splitXbitUnicodes(Group::SINGLE_UNIT_20_BIT);
93
        $this->_splitXbitUnicodes(Group::MULTI_UNIT_20_BIT);
94
        $this->_splitXbitUnicodes(Group::SINGLE_UNIT_16_BIT);
95
        $this->_fusionXbitUnicodes(Group::MULTI_UNIT_16_BIT);
96
        $this->_transformRangesToPattern();
97
        return $this;
98
    }
99
100
    /**
101
     * Divides the unicodes into intervals
102
     *
103
     * @param string $bitsKey The holder array's key for the bits
104
     *
105
     * @return bool|void
106
     */
107
    private function _splitXbitUnicodes($bitsKey)
108
    {
109
        if (!isset($this->_unicodes[$bitsKey])) {
110
            return false;
111
        }
112
113
        $data = $this->_unicodes[$bitsKey];
114
        sort($data);
115
116
        $ranges = [
117
            [$data[0]]
118
        ];
119
        $rangesIndex = 0;
120
        $lastRangeIndex = 0;
121
122
        foreach ($data as $k => $unicode) {
123
            if ($k === 0) {
124
                continue;
125
            }
126
127
            $lastItem = $ranges[$rangesIndex][$lastRangeIndex];
128
129
            if (hexdec($unicode) - hexdec($lastItem) === 1) {
130
                $ranges[$rangesIndex][] = $unicode;
131
                $lastRangeIndex++;
132
            } else {
133
                $ranges[] = [$unicode];
134
                $lastRangeIndex = 0;
135
                $rangesIndex++;
136
            }
137
        }
138
139
        $this->_ranges = array_merge($this->_ranges, $ranges);
140
    }
141
142
    /**
143
     * Glues the multi unit values into RegEx pattern
144
     *
145
     * @param  string $bitsKey The holder array's key for the bits
146
     *
147
     * @return void
148
     */
149
    private function _fusionXbitUnicodes(string $bitsKey)
150
    {
151
        $data = $this->_unicodes[$bitsKey];
152
153
        $patternString = '';
154
        foreach ($data as $unicode) {
155
            $bytes = explode(' ', $unicode);
156
            $bytesPattern = '';
157
158
            foreach ($bytes as $byte) {
159
                $bytesPattern .= '\x{' . $byte . '}';
160
            }
161
162
            $patternString .= '|' . $bytesPattern;
163
        }
164
165
        if (empty($this->_pattern)) {
166
            $patternString = ltrim($patternString, '|');
167
        }
168
        $this->_pattern .= $patternString;
169
    }
170
171
    /**
172
     * Transforms the ranges to a RegEx pattern
173
     *
174
     * @return void
175
     */
176
    private function _transformRangesToPattern(): void
177
    {
178
        $reducedRanges = [];
179
        foreach ($this->_ranges as $range) {
180
            if (isset($range[1])) {
181
                $first = reset($range);
182
                $last = end($range);
183
                $reducedRanges[] = '[\x{' . $first . '}-\x{' . $last . '}]';
184
            } else {
185
                $reducedRanges[] = '\x{' . $range[0] . '}';
186
            }
187
        }
188
189
        if (!empty($this->_pattern)) {
190
            $this->_pattern .= '|';
191
        }
192
193
        $this->_pattern .= implode('|', $reducedRanges);
194
    }
195
196
    /**
197
     * Exports the unicodes data into JSON file
198
     *
199
     * @return boolean|array Returns false on error or an Array holds the created file details
200
     */
201
    public function export()
202
    {
203
        $base = $this->config->get('storage.base');
204
        $output = $this->config->get('storage.output.ranges');
205
        $fileTitle = $this->config->get('storage.output.rangesFileTitle', 'Undefined Title');
206
207
        $content = '\'' . $this->_pattern . '\'';
208
209
        return File::toText($base . $output, $fileTitle, $content);
210
    }
211
212
    /**
213
     * Tests the produced pattern efficiency catching the Emojis
214
     *
215
     * @param string $replacement The replacement for the Emoji
216
     *
217
     * @return boolean|array Returns false on error or an array holds the created file details
218
     */
219
    public function testPattern($replacement = '@GOT_YOU')
220
    {
221
        $file = new File($this->config);
222
223
        $pattern = '(' . $this->_pattern . ').*\n';
224
        $count = 0;
225
226
        $file->replaceContent(function ($content) use ($pattern, $replacement, &$count) {
227
            $newContent = preg_replace('/' . $pattern . '/mu', $replacement . "\n", $content, -1, $count);
228
            return iconv(mb_detect_encoding($newContent), 'UTF-16', $newContent);
229
        });
230
231
        $base = $this->config->get('storage.base');
232
        $fileTitle = $this->config->get('storage.output.testFileTitle', 'Undefined Title');
233
        $output = $this->config->get('storage.output.test');
234
235
        $export = File::toText($base . $output, $fileTitle, $file->content);
236
237
        if (!is_array($export)) {
238
            return false;
239
        }
240
241
        return array_merge($export, ['count' => $count]);
242
    }
243
}
244