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

AbstractAnonymizer::generateFakeData()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 26
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

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