Passed
Push — master ( cef086...22be2e )
by Emmanuel
01:44
created

AbstractAnonymizer::checkColIsInEntity()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

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