Completed
Push — master ( 8f7e97...7b40cd )
by Nekrasov
11:06 queued 11:06
created

Anonymizer::handlePossibleClosure()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 12
rs 9.4286
cc 3
eloc 6
nc 3
nop 1
1
<?php
2
3
namespace Arrilot\DataAnonymization;
4
5
use Arrilot\DataAnonymization\Database\DatabaseInterface;
6
use Faker\Factory;
7
use Mockery\CountValidator\Exception;
8
9
class Anonymizer
10
{
11
    /**
12
     * Database interactions object.
13
     *
14
     * @var DatabaseInterface
15
     */
16
    protected $database;
17
18
    /**
19
     * Generator object (e.g faker).
20
     *
21
     * @var mixed
22
     */
23
    protected $generator;
24
25
    /**
26
     * Blueprints for tables.
27
     *
28
     * @var array
29
     */
30
    protected $blueprints = [];
31
32
    /**
33
     * Constructor.
34
     *
35
     * @param DatabaseInterface $database
36
     * @param mixed $generator
37
     */
38
    public function __construct(DatabaseInterface $database, $generator = null)
39
    {
40
        $this->database = $database;
41
42
        $this->setGenerator($generator);
43
    }
44
45
    /**
46
     * Setter for generator.
47
     *
48
     * @param mixed $generator
49
     *
50
     * @return $this
51
     */
52
    public function setGenerator($generator)
53
    {
54
        if ($generator !== null) {
55
            $this->generator = $generator;
56
        }
57
58
        if (class_exists('\Faker\Factory')) {
59
            $this->generator = Factory::create();
60
        }
61
62
        return $this;
63
    }
64
65
    /**
66
     * Getter for generator.
67
     *
68
     * @return mixed
69
     */
70
    public function getGenerator()
71
    {
72
        return $this->generator;
73
    }
74
75
    /**
76
     * Perform data anonymization.
77
     *
78
     * @return void
79
     */
80
    public function run()
81
    {
82
        foreach ($this->blueprints as $table => $blueprint) {
83
            $this->applyBlueprint($blueprint);
84
        }
85
    }
86
87
    /**
88
     * Describe a table with a given callback.
89
     *
90
     * @param string   $name
91
     * @param callable $callback
92
     *
93
     * @return void
94
     */
95
    public function table($name, callable $callback)
96
    {
97
        $blueprint = new Blueprint($name, $callback);
98
99
        $this->blueprints[$name] = $blueprint->build();
100
    }
101
102
    /**
103
     * Apply blueprint to the database.
104
     *
105
     * @param Blueprint $blueprint
106
     *
107
     * @return void
108
     */
109
    protected function applyBlueprint(Blueprint $blueprint)
110
    {
111
        foreach ($blueprint->columns as $column) {
112
            $this->updateColumn($blueprint->table, $blueprint->primary, $column);
113
        }
114
    }
115
116
    /**
117
     * Update all needed values of a give column.
118
     *
119
     * @param string $table
120
     * @param array  $primary
121
     * @param array  $column
122
     */
123
    protected function updateColumn($table, $primary, $column)
124
    {
125
        $rows = $this->database->getRows(
126
            $table,
127
            $this->mergeColumns($primary, $column['name']),
128
            $column['where']
129
        );
130
131
        if (empty($rows)) {
132
            return;
133
        }
134
135
        foreach ($rows as $rowNum => $row) {
136
            $this->database->updateByPrimary(
137
                $table,
138
                Helpers::arrayOnly($row, $primary),
139
                $column['name'],
140
                $this->calculateNewValue($column['replace'], $rowNum)
141
            );
142
        }
143
    }
144
145
    /**
146
     * Calculate new value for each row.
147
     *
148
     * @param string|callable $replace
149
     * @param int             $rowNum
150
     *
151
     * @return string
152
     */
153
    protected function calculateNewValue($replace, $rowNum)
154
    {
155
        $value = $this->handlePossibleClosure($replace);
156
157
        return $this->replacePlaceholders($value, $rowNum);
158
    }
159
160
    /**
161
     * Replace placeholders
162
     *
163
     * @param mixed $value
164
     * @param int   $rowNum
165
     *
166
     * @return mixed
167
     */
168
    protected function replacePlaceholders($value, $rowNum)
169
    {
170
        if (!is_string($value)) {
171
            return $value;
172
        }
173
174
        return str_replace('#row#', $rowNum, $value);
175
    }
176
177
    /**
178
     * @param $replace
179
     * @return mixed
180
     */
181
    protected function handlePossibleClosure($replace)
182
    {
183
        if (!is_callable($replace)) {
184
            return $replace;
185
        }
186
187
        if ($this->generator === null) {
188
            throw new Exception('You forgot to set a generator');
189
        }
190
191
        return call_user_func($replace, $this->generator);
192
    }
193
194
    /**
195
     * Merge columns for select.
196
     *
197
     * @param array  $primary
198
     * @param string $columnName
199
     *
200
     * @return array
201
     */
202
    protected function mergeColumns($primary, $columnName)
203
    {
204
        return array_merge($primary, [
205
            $columnName,
206
        ]);
207
    }
208
}
209