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 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 66
DedupGenerateSingleFile
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 12
306
0.00% covered (danger)
0.00%
0 / 66
 __construct
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 3
 launch
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 7
 generatePaths
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 10
 createFile
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 9
 zip
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 8
 setFilename
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 6
 getZipPath
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 1
 getFilePath
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 1
 get
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 8
 chunk
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 6
 getHashs
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 eachHash
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 6
1<?php
2
3namespace Qmp\Laravel\Deduplication\Console\Commands;
4
5use Closure;
6use Exception;
7use Illuminate\Support\Facades\Storage;
8use Illuminate\Support\Str;
9use Qmp\Laravel\Deduplication\Exceptions\ZipErrorException;
10use Qmp\Laravel\Deduplication\Models\Session;
11use Qmp\Laravel\Deduplication\Models\SessionData;
12use ZipArchive;
13
14class DedupGenerateSingleFile extends BaseCommand
15{
16    /**
17     * The download folder
18     */
19    const DOWNLOAD_DIRECTORY = 'download';
20
21    /**
22     * The created file extension
23     */
24    const FILE_EXTENSION = '.txt';
25
26    /**
27     * The zip file extension
28     */
29    const ZIP_EXTENSION = '.zip';
30
31
32    /**
33     * The size of hash for the chunk method
34     */
35    const HASHS_CHUNK_SIZE = 10000;
36
37    /**
38     * The name and signature of the console command.
39     *
40     * @var string
41     */
42    protected $signature = 'dedup:generate-single-files {sessionId}
43                                    {--site-id= : The site id}
44                                    {--throw-error : Throw errors if catch}';
45
46    /**
47     * The console command description.
48     *
49     * @var string
50     */
51    protected $description = 'Generate file after deduplication';
52
53    /** The dedup disk
54     *
55     * @var \Illuminate\Contracts\Filesystem\Filesystem
56     */
57    protected $disk;
58
59    /**
60     *  The current session model
61     */
62    protected $sessionConfig;
63
64    /**
65     * Undocumented variable
66     *
67     * @var integer
68     */
69    protected $count = 0;
70
71    /**
72     * Undocumented variable
73     *
74     * @var int
75     */
76    protected $siteId = null;
77
78    /**
79     * Undocumented variable
80     *
81     * @var resource|false
82     */
83    protected $fileRessource = null;
84
85    /**
86     * Undocumented variable
87     *
88     * @var string
89     */
90    protected $filename = "";
91    /**
92     * Create a new command instance.
93     *
94     * @return void
95     */
96    public function __construct()
97    {
98        parent::__construct();
99        $this->disk = Storage::disk('deduplication');
100    }
101
102    /**
103     * Undocumented function
104     *
105     * @return void
106     */
107    protected function launch(): void
108    {
109        $this->siteId = (int) $this->option('site-id');
110        $this->sessionConfig = Session::findOrFail($this->argument('sessionId'));
111
112        $this->generatePaths()
113            ->createFile()
114            ->zip()
115            ->setFilename();
116    }
117
118    /**
119     * Generate all paths and filenames
120     *
121     * @return \Qmp\Laravel\Deduplication\Console\Commands\DedupGenerateSingleFile
122     */
123    protected function generatePaths(): DedupGenerateSingleFile
124    {
125        $fileNameParts = collect([
126            $this->sessionConfig->name, // Session name
127            collect($this->sessionConfig->sites)->recursive()->where('id', $this->siteId)->first()->get('name'), // Site name
128            $this->sessionConfig->id, // Session id
129            date('m-Y') // Month/year
130        ]);
131
132        $filename = Str::slug($fileNameParts->implode('-'));
133
134        $this->filename = $filename . self::FILE_EXTENSION;
135        $this->zipname = $filename . self::ZIP_EXTENSION;
136        $this->savePath = $this->sessionConfig->id . '/' . self::DOWNLOAD_DIRECTORY . '/' . $this->siteId . '/';
137
138        return $this;
139    }
140
141    /**
142     * Create file for a single site
143     *
144     * @param string $siteId
145     * @return \Qmp\Laravel\Deduplication\Console\Commands\DedupGenerateSingleFile
146     */
147    protected function createFile(): DedupGenerateSingleFile
148    {
149
150        $this->info("Création du fichier  : " . $this->getFilePath(true) . " ...");
151
152        $this->disk->put($this->getFilePath(), '');
153        $this->fileRessource = fopen($this->disk->path($this->getFilePath()), "w");
154
155        $this->startTimer('chunk', 'total');
156        $this->get();
157
158        fclose($this->fileRessource);
159
160        $this->info("write done for $this->count entries in : " . $this->getTimer('total'));
161        $this->info("Fichier : " . $this->getFilePath(true) . " ok !");
162
163        return $this;
164    }
165
166    /**
167     * Zip file
168     *
169     * @return \Qmp\Laravel\Deduplication\Console\Commands\DedupGenerateSingleFile
170     */
171    protected function zip(): DedupGenerateSingleFile
172    {
173        $this->info("Création du zip : " . $this->getZipPath(true) . " ...");
174
175        $zip = new ZipArchive;
176        if ($zip->open($this->disk->path($this->getZipPath()), ZipArchive::CREATE) === TRUE) {
177            $zip->addFile($this->disk->path($this->getFilePath()), $this->getFilePath(true));
178            $zip->close();
179            $this->info('zip Ok !');
180        } else {
181            throw new ZipErrorException("Erreur lors de la creation du zip " . $this->getZipPath(true));
182        }
183
184        return $this;
185    }
186
187    /**
188     * Add download filename into DB
189     *
190     * @return void
191     */
192    protected function setFilename(): void
193    {
194        $array = [
195            'zip' => $this->getZipPath(),
196            'file' => $this->getFilePath(),
197            'basename' => $this->getFilePath(true),
198            'count' => $this->count
199        ];
200
201        $this->sessionConfig->setKeyFilter('sites.$id', 'output_file', $array, [$this->siteId]);
202    }
203
204    /**
205     * Get zipfile or full zip path
206     *
207     * @param boolean $onlyFilename
208     * @return string
209     */
210    protected function getZipPath($onlyFilename = false): string
211    {
212        return $onlyFilename ? $this->zipname : $this->savePath . $this->zipname;
213    }
214
215    /**
216     * Get filename or full file path
217     *
218     * @param boolean $onlyFilename
219     * @return string
220     */
221    protected function getFilePath($onlyFilename = false): string
222    {
223        return $onlyFilename ? $this->filename : $this->savePath . $this->filename;
224    }
225
226    /**
227     * Get All hash at once
228     *
229     * @return void
230     */
231    protected function get(): void
232    {
233        try {
234            $this->startTimer('hashsGet');
235            $hashs = $this->getHashs()->get();
236            $this->info('Get Hashs in ' . $this->getTimer('hashsGet'));
237
238            $this->startTimer('hashEntry');
239            $hashs->each(Closure::fromCallable([$this, 'eachHash']));
240        } catch (Exception $e) {
241            $this->chunk();
242        }
243    }
244
245    /**
246     * Get hash by chunk
247     *
248     * @return void
249     */
250    protected function chunk(): void
251    {
252        $this->getHashs()->chunk(self::HASHS_CHUNK_SIZE, function ($hashs) {
253            $this->info('chunk OK : ' .  $this->getTimer('chunk', true));
254            $this->info('write start');
255
256            $hashs->each(Closure::fromCallable([$this, 'eachHash']));
257        });
258    }
259
260    /**
261     * Get all hashs for one site id and one session
262     *
263     */
264    protected function getHashs()
265    {
266        return SessionData::where(['site_id' => $this->siteId, 'active' => false, "session_id" => $this->sessionConfig->id])->select('hash');
267    }
268
269    /**
270     * Closure to execute on each entry
271     *
272     * @param [type] $hash
273     * @return void
274     */
275    protected function eachHash($hash): void
276    {
277        $this->count++;
278        $string = $hash->hash . "\r\n";
279        fwrite($this->fileRessource, $string, strlen($string));
280
281        if ($this->count % 50000 === 0) {
282            $this->info("write $this->count entries in : " . $this->filename . " - " . $this->getTimer('hashEntry'));
283        }
284    }
285}