Completed
Pull Request — master (#9)
by Sander
04:49
created

AbstractAnonymizer::setReturnRes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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