AbstractAnonymizer::checkColIsInEntity()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 2
cts 2
cp 1
cc 2
nc 2
nop 1
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * neuralyzer : Data Anonymization Library and CLI Tool
7
 *
8
 * PHP Version 7.2
9
 *
10
 * @author    Emmanuel Dyan
11
 * @author    Rémi Sauvat
12
 *
13
 * @copyright 2020 Emmanuel Dyan
14
 *
15
 * @package edyan/neuralyzer
16
 *
17
 * @license GNU General Public License v2.0
18
 *
19
 * @link https://github.com/edyan/neuralyzer
20
 */
21
22
namespace Edyan\Neuralyzer\Anonymizer;
23
24
use Edyan\Neuralyzer\Configuration\Reader;
25
use Edyan\Neuralyzer\Exception\NeuralyzerConfigurationException;
26
27
/**
28
 * Abstract Anonymizer, that can be implemented as DB Anonymizer for example
29
 * Its goal is only to anonymize any data, from a simple array
30
 * not to write or read it from anywhere
31
 */
32
abstract class AbstractAnonymizer
33
{
34
    /**
35
     * Update data into table
36
     */
37
    public const UPDATE_TABLE = 1;
38
39
    /**
40
     * Insert data into table
41
     */
42
    public const INSERT_TABLE = 2;
43
44
    /**
45
     * Set the batch size for updates
46
     *
47
     * @var int
48
     */
49
    protected $batchSize = 1000;
50
51
    /**
52
     * Contains the configuration object
53
     *
54
     * @var Reader
55
     */
56
    protected $configuration;
57
58
    /**
59
     * Configuration of entities
60
     *
61
     * @var array
62
     */
63
    protected $configEntities = [];
64
65
    /**
66
     * List of used fakers
67
     *
68
     * @var array<\Faker\Generator>|array<\Faker\UniqueGenerator>
69
     */
70
    protected $fakers = [];
71
72
    /**
73
     * Current table (entity) to process
74
     *
75
     * @var string
76
     */
77
    protected $entity;
78
79
    /**
80
     * Current table (entity) Columns
81
     *
82
     * @var array
83
     */
84
    protected $entityCols;
85
86
    /**
87
     * Limit the number of updates or create
88
     *
89
     * @var int
90
     */
91
    protected $limit = 0;
92
93
    /**
94
     * Pretend we do the update, but do nothing
95
     *
96
     * @var bool
97
     */
98
    protected $pretend = true;
99
100
    /**
101
     * Return the generated SQL
102
     *
103
     * @var bool
104
     */
105
    protected $returnRes = false;
106
107
    /**
108
     * @var \Faker\Generator
109
     */
110
    protected $faker;
111
112
    /**
113
     * Process the entity according to the anonymizer type
114
     *
115
     * @param string        $entity   Entity's name
116
     * @param callable|null $callback Callback function with current row num as parameter
117
     *
118
     * @return array
119
     */
120
    abstract public function processEntity(
121
        string $entity,
122
        ?callable $callback = null
123
    ): array;
124
125
    /**
126
     * Set the configuration
127
     */
128
    public function setConfiguration(Reader $configuration): void
129 31
    {
130
        $this->configuration = $configuration;
131 31
        $this->configEntities = $configuration->getConfigValues()['entities'];
132 31
        $this->initFaker();
133 31
    }
134 31
135
    /**
136
     * Limit of fake generated records for updates and creates
137
     *
138
     * @return mixed
139
     */
140
    public function setLimit(int $limit)
141
    {
142
        $this->limit = $limit;
143
        if ($this->limit < $this->batchSize) {
144 24
            $this->batchSize = $this->limit;
145
        }
146 24
147 24
        return $this;
148 23
    }
149
150
    /**
151 24
     * Activate or deactivate the pretending mode (dry run)
152
     *
153
     * @return mixed
154
     */
155
    public function setPretend(bool $pretend)
156
    {
157
        $this->pretend = $pretend;
158
159
        return $this;
160
    }
161
162 28
    /**
163
     * Return or not a result (like an SQL Query that has
164 28
     * been generated with fake data)
165
     *
166 28
     * @return mixed
167
     */
168
    public function setReturnRes(bool $returnRes)
169
    {
170
        $this->returnRes = $returnRes;
171
172
        return $this;
173
    }
174
175
    /**
176
     * Evaluate, from the configuration if I have to update or Truncate the table
177
     *
178 27
     * @throws NeuralyzerConfigurationException
179
     */
180 27
    protected function whatToDoWithEntity(): int
181
    {
182 27
        $this->checkEntityIsInConfig();
183
184
        $entityConfig = $this->configEntities[$this->entity];
185
186
        $actions = 0;
187
        if (array_key_exists('cols', $entityConfig)) {
188
            switch ($entityConfig['action']) {
189
                case 'update':
190
                    $actions |= self::UPDATE_TABLE;
191
                    break;
192 26
                case 'insert':
193
                    $actions |= self::INSERT_TABLE;
194 26
                    break;
195
            }
196 24
        }
197
198 24
        return $actions;
199 24
    }
200 24
201 24
    /**
202 18
     * Generate fake data for an entity and return it as an Array
203 18
     *
204 6
     * @return array
205 6
     *
206 6
     * @throws NeuralyzerConfigurationException
207
     */
208
    protected function generateFakeData(): array
209
    {
210 24
        $this->checkEntityIsInConfig();
211
        $colsInConfig = $this->configEntities[$this->entity]['cols'];
212
        $row = [];
213
        foreach ($colsInConfig as $colName => $colProps) {
214
            $this->checkColIsInEntity($colName);
215
            $data = \call_user_func_array(
216
                [$this->getFakerObject($this->entity, $colName, $colProps), $colProps['method']],
217
                $colProps['params']
218
            );
219
            if (! is_scalar($data)) {
220
                $msg = "You must use faker methods that generate strings: '{$colProps['method']}' forbidden";
221
                throw new NeuralyzerConfigurationException($msg);
222
            }
223
            $row[$colName] = trim($data);
224
            $colLength = $this->entityCols[$colName]['length'];
225
            // Cut the value if too long ...
226
            if (! empty($colLength) && \strlen($row[$colName]) > $colLength) {
227
                $row[$colName] = substr($row[$colName], 0, $colLength - 1);
228
            }
229
        }
230
231
        return $row;
232
    }
233
234
    /**
235
     * Make sure that entity is defined in the configuration
236
     *
237
     * @throws NeuralyzerConfigurationException
238
     */
239
    protected function checkEntityIsInConfig(): void
240
    {
241
        if (empty($this->configEntities)) {
242
            throw new NeuralyzerConfigurationException(
243
                'No entities found. Have you loaded a configuration file ?'
244
            );
245
        }
246
        if (! array_key_exists($this->entity, $this->configEntities)) {
247
            throw new NeuralyzerConfigurationException(
248
                "No configuration for that entity ({$this->entity})"
249
            );
250
        }
251
    }
252
253
    /**
254
     * Verify a column is defined in the real entityCols
255 26
     *
256
     * @throws NeuralyzerConfigurationException
257 26
     */
258 1
    protected function checkColIsInEntity(string $colName): void
259 1
    {
260
        if (! array_key_exists($colName, $this->entityCols)) {
261
            throw new NeuralyzerConfigurationException("Col ${colName} does not exist");
262 25
        }
263 1
    }
264 1
265
    /**
266
     * Init Faker and add additional methods
267 24
     */
268
    protected function initFaker(): void
269
    {
270
        $language = $this->configuration->getConfigValues()['language'];
271
        $this->faker = \Faker\Factory::create($language);
272
        $this->faker->addProvider(new \Edyan\Neuralyzer\Faker\Provider\Base($this->faker));
273
        $this->faker->addProvider(new \Edyan\Neuralyzer\Faker\Provider\Json($this->faker));
274
        $this->faker->addProvider(new \Edyan\Neuralyzer\Faker\Provider\UniqueWord($this->faker, $language));
275
    }
276 22
277
    /**
278 22
     * Get the faker object for a entity column
279 1
     *
280
     * @param array  $colProps
281 21
     *
282
     * @return \Faker\Generator|\Faker\UniqueGenerator
283
     */
284
    protected function getFakerObject(string $entityName, string $colName, array $colProps)
285
    {
286 31
        if (! isset($this->fakers[$entityName][$colName])) {
287
            $fakerClone = clone $this->faker;
288 31
            $this->fakers[$entityName][$colName] = isset($colProps['unique']) && $colProps['unique'] === true ? $fakerClone->unique() : $fakerClone;
289 31
        }
290 31
291 31
        return $this->fakers[$entityName][$colName];
292 31
    }
293
}
294