Completed
Push — master ( 4a880b...4a9e4f )
by Emmanuel
21:39 queued 20:01
created

AbstractAnonymizer   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 249
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 23
dl 0
loc 249
ccs 65
cts 65
cp 1
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A setPretend() 0 5 1
A getWhereConditionInConfig() 0 9 2
A setReturnRes() 0 5 1
A setConfiguration() 0 4 1
B whatToDoWithEntity() 0 23 6
A setLimit() 0 8 2
A checkEntityIsInConfig() 0 10 3
B generateFakeData() 0 31 5
A checkColIsInEntity() 0 4 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
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 17
    public function setConfiguration(Reader $configuration): void
113
    {
114 17
        $this->configuration = $configuration;
115 17
        $this->configEntites = $configuration->getConfigValues()['entities'];
116 17
    }
117
118
119
    /**
120
     * Limit of fake generated records for updates and creates
121
     * @param int $limit
122
     * @return mixed
123
     */
124 13
    public function setLimit(int $limit)
125
    {
126 13
        $this->limit = $limit;
127 13
        if ($this->limit < $this->batchSize) {
128 12
            $this->batchSize = $this->limit;
129
        }
130
131 13
        return $this;
132
    }
133
134
135
    /**
136
     * Activate or deactivate the pretending mode (dry run)
137
     * @param  bool $pretend
138
     * @return mixed
139
     */
140 14
    public function setPretend(bool $pretend)
141
    {
142 14
        $this->pretend = $pretend;
143
144 14
        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 13
    public function setReturnRes(bool $returnRes)
155
    {
156 13
        $this->returnRes = $returnRes;
157
158 13
        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 16
    protected function whatToDoWithEntity(): int
168
    {
169 16
        $this->checkEntityIsInConfig();
170
171 14
        $entityConfig = $this->configEntites[$this->entity];
172
173 14
        $actions = 0;
174 14
        if (array_key_exists('delete', $entityConfig) && $entityConfig['delete'] === true) {
175 5
            $actions |= self::TRUNCATE_TABLE;
176
        }
177
178 14
        if (array_key_exists('cols', $entityConfig)) {
179 14
            switch ($entityConfig['action']) {
180 14
                case 'update':
181 10
                    $actions |= self::UPDATE_TABLE;
182 10
                    break;
183 4
                case 'insert':
184 4
                    $actions |= self::INSERT_TABLE;
185 4
                    break;
186
            }
187
        }
188
189 14
        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 5
    public function getWhereConditionInConfig(): string
199
    {
200 5
        $this->checkEntityIsInConfig();
201
202 5
        if (!array_key_exists('delete_where', $this->configEntites[$this->entity])) {
203 2
            return '';
204
        }
205
206 3
        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 12
    protected function generateFakeData(): array
216
    {
217 12
        $this->checkEntityIsInConfig();
218
219 12
        $faker = \Faker\Factory::create($this->configuration->getConfigValues()['language']);
220 12
        $faker->addProvider(new \Edyan\Neuralyzer\Faker\Provider\Base($faker));
221
222 12
        $colsInConfig = $this->configEntites[$this->entity]['cols'];
223 12
        $row = [];
224 12
        foreach ($colsInConfig as $colName => $colProps) {
225 12
            $this->checkColIsInEntity($colName);
226 11
            $data = call_user_func_array(
227 11
                [$faker, $colProps['method']],
228 11
                $colProps['params']
229
            );
230
231 11
            if (!is_scalar($data)) {
232 1
                $msg = "You must use faker methods that generate strings: '{$colProps['method']}' forbidden";
233 1
                throw new NeuralizerConfigurationException($msg);
234
            }
235
236 11
            $row[$colName] = trim($data);
237
238 11
            $colLength = $this->entityCols[$colName]['length'];
239
            // Cut the value if too long ...
240 11
            if (!empty($colLength) && strlen($row[$colName]) > $colLength) {
241 11
                $row[$colName] = substr($row[$colName], 0, ($colLength - 1));
242
            }
243
        }
244
245 10
        return $row;
246
    }
247
248
249
    /**
250
     * Make sure that entity is defined in the configuration
251
     *
252
     * @throws NeuralizerConfigurationException
253
     */
254 16
    private function checkEntityIsInConfig(): void
255
    {
256 16
        if (empty($this->configEntites)) {
257 1
            throw new NeuralizerConfigurationException(
258 1
                'No entities found. Have you loaded a configuration file ?'
259
            );
260
        }
261 15
        if (!array_key_exists($this->entity, $this->configEntites)) {
262 1
            throw new NeuralizerConfigurationException(
263 1
                "No configuration for that entity ({$this->entity})"
264
            );
265
        }
266 14
    }
267
268
    /**
269
     * Verify a column is defined in the real entityCols
270
     *
271
     * @throws NeuralizerConfigurationException
272
     * @param  string $colName [description]
273
     */
274 12
    private function checkColIsInEntity(string $colName): void
275
    {
276 12
        if (!array_key_exists($colName, $this->entityCols)) {
277 1
            throw new NeuralizerConfigurationException("Col $colName does not exist");
278
        }
279 11
    }
280
}
281