equals(ExportFormat::csv)) { return $models->whereNotNull($fileFieldName)->pluck($fileFieldName)->isNotEmpty(); } elseif ($format->equals(ExportFormat::pdf)) { return $models ->whereNotNull($fileFieldName) ->whereNotIn('file_extension', ['jpg', 'jpeg', 'png']) ->isNotEmpty(); } return false; } /** * Return a StreamedResponse with a zip file. * * @param ExportFormat $format * @param \Illuminate\Database\Eloquent\Collection $models * @param string $file * @return \Symfony\Component\HttpFoundation\StreamedResponse */ public function returnExportZip( ExportFormat $format, \Illuminate\Database\Eloquent\Collection $models, string $file ): \Symfony\Component\HttpFoundation\StreamedResponse { return new StreamedResponse(function () use ($file, $models, $format) { // Create zip. $zip = new ZipArchive(); $zipName = $this->createExportZip($zip, $file, $format); // Add attachments. $this->addAttachmentsToZip($zip, $models, $format); $zip->close(); readfile($zipName); unlink($zipName); }, 200, $this->getFileHeaders($format, true)); } /** * Create the zip folder for the export with the main file inside. * * @param ZipArchive $zip * @param string $file * @param ExportFormat $format * @return string|false * * @throws \Exception If the zip opening failed. */ private function createExportZip(ZipArchive &$zip, string $file, ExportFormat $format): string|false { $zipName = tempnam(Storage::disk('private')->path('export'), 'zip'); if (!$zip->open($zipName, ZipArchive::OVERWRITE)) { throw new \Exception(__('Couldn\'t open zip file.')); }; $zip->addFromString($format->fileName(), $file); return $zipName; } /** * Add attachments to zip * * @param ZipArchive $zip * @param \Illuminate\Database\Eloquent\Collection $models * @param ExportFormat $format * @param string $fileFieldName Name of the field containing the file. * @return void */ private function addAttachmentsToZip( ZipArchive &$zip, \Illuminate\Database\Eloquent\Collection $models, ExportFormat $format, string $fileFieldName = 'file' ) { $modelsWithFilesToZip = $models->whereNotNull($fileFieldName) ->when($format->equals(ExportFormat::pdf), function ($models) { return $models->whereNotIn('file_extension', ['jpg', 'jpeg', 'png']); }); foreach ($modelsWithFilesToZip as $model) { $filePath = FileHelper::getPrivateFilePath($model->{$fileFieldName}); if (Storage::disk('private')->exists($filePath)) { $zip->addFile( Storage::disk('private')->path($filePath), $model->export_file_name ); } } } /** * Get file headers to use with StreamedResponse. * * @param ExportFormat $format * @param boolean $isZip * @return array */ public function getFileHeaders(ExportFormat $format, bool $isZip = false): array { if ($isZip) { return [ 'Content-Type' => 'application/zip', 'Content-Disposition' => 'attachment; filename="export.zip"', ]; }; return $format->fileHeaders(); } /** * Transform Array into CSV. * * @param array $lines * @param string $delimiter * @param string $enclosure * @param string $escape_char * @return string|false */ private function array2csv( array $lines, string $delimiter = ',', string $enclosure = '"', string $escape_char = "\\" ) { $f = fopen('php://temp', 'r+'); // UTF-8 BOM. $BOM = "\xEF\xBB\xBF"; fwrite($f, $BOM); foreach ($lines as $item) { fputcsv($f, $item, $delimiter, $enclosure, $escape_char); } rewind($f); $csvContent = stream_get_contents($f); fclose($f); return $csvContent; } /** * Generate CSV with given models. * * @param \Illuminate\Database\Eloquent\Collection $models * @return string|false */ private function generateCsv(\Illuminate\Database\Eloquent\Collection $models) { // CSV Header. $class = get_class($models->first()); $csvlines[] = $class::getCsvHeaders(); foreach ($models as $model) { $csvlines[] = $model->getFormattedCsvLine(); } return $this->array2csv($csvlines, ';'); } /** * Generate PDF with models datas. * * @param \Illuminate\Database\Eloquent\Collection $models * @param string $fileFieldName * @return \Barryvdh\DomPDF\PDF */ private function generatePdf( \Illuminate\Database\Eloquent\Collection $models, string $fileFieldName = 'file' ): \Barryvdh\DomPDF\PDF { // Convert pictures to base64. foreach ($models->whereIn('file_extension', ['jpg', 'jpeg', 'png']) as $model) { $filePath = FileHelper::getPrivateFilePath($model->{$fileFieldName}); $model->fileBase64 = sprintf( 'data:%s;base64,%s', File::mimeType(Storage::disk('private')->path($filePath)), base64_encode(Storage::disk('private')->get($filePath)) ); } // Create temp folder if it doesn't exists. Needed to allow base64 pictures to be displayed in pdf. if (!Storage::disk('private')->exists('temp')) { Storage::disk('private')->makeDirectory('temp'); } $modelClassName = class_basename($models->first()); return Pdf::setOptions(['tempDir' => Storage::disk('private')->path('temp')]) ->loadView( sprintf( 'export.pdf', str($modelClassName)->lower()->plural() ), [ 'models' => $models, 'modelName' => str($modelClassName)->lower() ] ); } }