Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 88
DedupReadSingleFile
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 7
462
0.00% covered (danger)
0.00%
0 / 88
 __construct
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 5
 handle
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 21
 deletePrevious
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 11
 updatePonderation
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 10
 insertFile
0.00% covered (danger)
0.00%
0 / 1
72
0.00% covered (danger)
0.00%
0 / 27
 addToChunk
0.00% covered (danger)
0.00%
0 / 1
20
0.00% covered (danger)
0.00%
0 / 9
 insert
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 5
1<?php
2
3namespace Qmp\Laravel\Deduplication\Console\Commands;
4
5use Closure;
6use DateTime;
7use Illuminate\Console\Command;
8use Illuminate\Support\Collection;
9use Illuminate\Support\Facades\Storage;
10use Qmp\Laravel\Deduplication\Models\{Session, SessionData};
11use Qmp\Laravel\ToolsLaravel\Traits\Timer;
12use Qmp\Laravel\ToolsLaravel\FileReader\FileReader;
13use MongoDB\BSON\UTCDateTime;
14use MongoDB\Driver\WriteConcern;
15
16class DedupReadSingleFile extends Command
17{
18
19    use Timer;
20
21    /**
22     *
23     */
24    const CHUNK_SIZE = 10000;
25
26
27    /**
28     * The name and signature of the console command.
29     *
30     * @var string
31     */
32    protected $signature = 'dedup:read-single-file {sessionId}
33                            {--user-id= : The user id}
34                            {--site-id= : The site id}
35                            {--check-ponderation= : Wether to delete entries or just update ponderation}
36                            {--type= : The type only for blacklists}';
37
38    /**
39     * The console command description.
40     *
41     * @var string
42     */
43    protected $description = 'Read one file and instert into db';
44
45    /**
46     * Undocumented variable
47     *
48     * @var \Illuminate\Support\Collection
49     */
50    protected $chunk;
51
52    /**
53     * Undocumented variable
54     *
55     * @var \Illuminate\Contract\Filesystem\Filesystem
56     */
57    protected $disk;
58
59    /** The addToChunk closure
60     *
61     * @var Closure
62     */
63    protected $addToChunk;
64
65    /**
66     * Hash Type
67     *
68     * @var string
69     */
70    protected $hashType;
71
72    /**
73     * Undocumented variable
74     *
75     * @var integer
76     */
77    protected $count = 0;
78
79    /**
80     * Undocumented variable
81     *
82     * @var integer
83     */
84    protected $totalCount = 0;
85
86    /**
87     * Undocumented variable
88     *
89     * @var [type]
90     */
91    protected $sessionConfig;
92
93    /** 
94     * The mongo hash structure
95     *
96     * @var array
97     */
98    protected $structure = [
99        'hash' => null,
100        'session_id' => null,
101        'user_id' => 0,
102        'site_id' => 0,
103        'ponderation' => 0,
104        'active' => true,
105        'description_dedup_false' => '',
106        'filename' => null,
107        'updated_at' => null,
108    ];
109
110    /**
111     * Create a new command instance.
112     *
113     * @return void
114     */
115    public function __construct()
116    {
117        parent::__construct();
118        $this->disk = Storage::disk('deduplication');
119        $this->addToChunk = Closure::fromCallable([$this, 'addToChunk']);
120        $this->chunk = collect();
121    }
122
123    /**
124     * Execute the console command.
125     *
126     * @return void
127     */
128    public function handle(): void
129    {
130        $this->totalCount = 0;
131        $this->counr = 0;
132        $this->sessionConfig = Session::findOrFail($this->argument('sessionId'));
133
134        $sessionConfig = collect($this->sessionConfig)->recursive();
135
136        $this->hashType = $sessionConfig->get('hashType');
137        $this->structure['session_id'] = $this->argument('sessionId');
138
139        if ($type = $this->option('type')) {
140            $listInfo = $sessionConfig->get('blackLists')
141                ->where('type', $type)
142                ->first();
143            $this->deletePrevious($listInfo);
144            $this->insertFile($listInfo, true);
145        } else {
146            $listInfo = $sessionConfig->get('sites')
147                ->where('user_id', $this->option('user-id'))
148                ->where('id', $this->option('site-id'))
149                ->first();
150            if ($this->option('check-ponderation') === 'true') {
151                $this->updatePonderation($listInfo->get('ponderation'));
152            } else {
153                $this->deletePrevious($listInfo);
154            }
155            $this->insertFile($listInfo);
156        }
157    }
158
159
160    /**
161     * Undocumented function
162     *
163     * @param Collection $site
164     * @return void
165     */
166    protected function deletePrevious(Collection $site)
167    {
168        $this->info('Check previous entries...');
169
170        $old = SessionData::where('session_id', $this->argument('sessionId'))
171            ->where('user_id', (int) $this->option('user-id'))
172            ->where('site_id', (int) $this->option('site-id'));
173
174        if ($old->first()) {
175            $this->startTimer('delete');
176            $this->info('Suppression des anciennes lignes du site ' . $site->get('name'));
177            $old->delete([
178                "writeConcern" => new WriteConcern(0)
179            ]);
180            $this->info('Remove duration : ' . $this->getTimer('delete'));
181        }
182    }
183
184    /**
185     * Undocumented function
186     *
187     * @param [type] $newPonderation
188     * @return void
189     */
190    protected function updatePonderation($newPonderation)
191    {
192        $this->info('Check if ponderation has change ..');
193
194        $query = SessionData::where('session_id', $this->argument('sessionId'))
195            ->where('user_id', (int) $this->option('user-id'))
196            ->where('site_id', (int) $this->option('site-id'));
197
198        $currentPonderation = $query->first()->ponderation;
199
200        if ($currentPonderation !== $newPonderation) {
201            $this->info("Update ponderation from $currentPonderation to $newPonderation...");
202            $query->update(['ponderation' => $newPonderation]);
203        } else {
204            $this->info('Nothing change !');
205        }
206    }
207
208    /**
209     * Insert file into DB
210     *
211     * @param Collection $site
212     * @param boolean $blackList
213     * @return void
214     */
215    protected function insertFile(Collection $site, bool $blackList = false): void
216    {
217        $timerName = $site->get('name') ?? 'tmr_' . rand(0, 1000) . rand(0, 500);
218
219        $this->totalCount = $site->dotGet('input_file.count');
220
221        $this->startTimer($timerName);
222        $type = $blackList ? 'blacklist' : 'editors';
223        $this->info("Insterting $type hashs ... ");
224
225        if ($site->get('name')) {
226            $this->info("Name :" . $site->get('user_name') . ' - Site : ' . $site->get('name'));
227        }
228
229        if (!$blackList) {
230            $this->structure['ponderation'] = $site->get('ponderation');
231            $this->structure['user_id'] = $site->get('user_id');
232            $this->structure['site_id'] = $site->get('id');
233        }
234
235        $input_file = $site->get('input_file');
236
237        $this->structure['filename'] = $input_file->get('file');
238        $this->structure['updated_at'] = new UTCDateTime(new DateTime());
239        $reader = new FileReader($this->disk->path($input_file->get('file')));
240
241        if ($capping = $site->get('capping')) {
242            $this->info('Capping file to ' . $capping . " entries");
243            $reader->randomCapping($capping, $input_file->get('count'));
244        }
245
246        $reader->each($this->addToChunk);
247
248        // Final insert of remaining chunks
249        $this->insert();
250
251        $path = $blackList ? 'blacklists.$type.input_file' : 'sites.$id.input_file';
252        $filter = $blackList ? 'customerHashedList' : $site->get('id');
253
254        $this->sessionConfig->setKeyFilter($path, 'inserted', true, [$filter]);
255
256        if ($site->get('name')) {
257            $this->info('Insert done for ' . $site->get('user_name') . ': ' . $site->get('name') . ' - ' . $this->getTimer($timerName));
258        } else {
259            $this->info('Insert done for blacklist: ' . $this->option('type') . ' - ' . $this->getTimer($timerName));
260        }
261    }
262
263    /**
264     * Add hash to chunk
265     *
266     * @param string $hash
267     * @return void
268     */
269    protected function addToChunk(string $hash): void
270    {
271        $hash = trim($hash);
272
273        if ($hash !== "") {
274            if (filter_var($hash, FILTER_VALIDATE_EMAIL) !== false) {
275                $hash = hash($this->hashType, $hash);
276            }
277            $this->structure['hash'] = strtolower($hash);
278
279            $this->chunk->push($this->structure);
280
281            if ($this->chunk->count() >= self::CHUNK_SIZE) {
282
283                $this->insert();
284            }
285        }
286    }
287
288    /**
289     * Insert the given chunk
290     *
291     * @return void
292     */
293    protected function insert(): void
294    {
295        $this->count += $this->chunk->count();
296
297        SessionData::insert($this->chunk->toArray(), ["writeConcern" => ["w" => 0]]);
298        $this->line("Inserted : $this->count / $this->totalCount");
299        $this->chunk = collect();
300    }
301}