Bläddra i källkod

формирование отдельных файлов на каждый товар, заархивированных в zip

Alexander Musikhin 2 år sedan
förälder
incheckning
9928e31670

+ 10 - 6
app/Http/Controllers/ExportController.php

@@ -3,9 +3,11 @@
 namespace App\Http\Controllers;
 
 use App\Jobs\GenerateDocxJob;
+use App\Jobs\GenerateSeparateDocxJob;
 use App\Models\Product;
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Log;
+use Illuminate\Support\Str;
 
 class ExportController extends Controller
 {
@@ -55,29 +57,31 @@ class ExportController extends Controller
             $i++;
 
         }
-//dd($vars_for_template);
+        //dd($vars_for_template);
         // prepared vars - run job
 
 
         $filename = 'Наш_Двор_' . date('YmdHis') . '.docx';
-        if($products->count() > 200){
-            GenerateDocxJob::dispatch($vars_for_template, count($products), $filename, $request->template)->onConnection('database');
+
+        $connection = ($products->count() > 200) ? 'database' : 'sync';
+        if(isset($request->separate_docs) && ($request->separate_docs == 'yes')){
+            GenerateSeparateDocxJob::dispatch($vars_for_template, $products->count(), $filename, $request->template)->onConnection($connection);
+            $filename = Str::replace('.docx', '.zip', $filename);
         } else {
-            GenerateDocxJob::dispatch($vars_for_template, count($products), $filename, $request->template)->onConnection('sync');
+            GenerateDocxJob::dispatch($vars_for_template, count($products), $filename, $request->template)->onConnection($connection);
         }
 
-
         Log::notice('Created export job. Execution time: ' . microtime(true) - LARAVEL_START);
 
         $data['filename'] = $filename;
         return redirect()->route('wait_export', $data);
-
     }
 
     public function wait_export(Request $request, $filename){
         $fn = public_path('exported/docx/' . $filename . '.txt');
         if(file_exists($fn)){
             $data['percent'] = file_get_contents($fn);
+            if($data['percent'] < 0) $data['percent'] = 0;
         } else {
             $data['percent'] = 0;
         }

+ 96 - 0
app/Jobs/GenerateSeparateDocxJob.php

@@ -0,0 +1,96 @@
+<?php
+
+namespace App\Jobs;
+
+use Illuminate\Bus\Queueable;
+use Illuminate\Contracts\Queue\ShouldBeUnique;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Foundation\Bus\Dispatchable;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\SerializesModels;
+use Illuminate\Support\Facades\Log;
+use Illuminate\Support\Str;
+use PhpOffice\PhpWord\TemplateProcessor;
+
+class GenerateSeparateDocxJob implements ShouldQueue
+{
+    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+
+    protected $vars;
+    protected $products_count;
+    protected $filename;
+    protected $template;
+
+    /**
+     * Create a new job instance.
+     *
+     * @return void
+     */
+    public function __construct($vars, $products_count, $filename, $template)
+    {
+        $this->vars = $vars;
+        $this->products_count = $products_count;
+        $this->filename = $filename;
+        $this->template = $template;
+    }
+
+    /**
+     * Execute the job.
+     *
+     * @return void
+     */
+    public function handle()
+    {
+        $tmpfile = public_path('exported/docx/' . Str::replace('.docx', '.zip', $this->filename) . '.txt');
+
+        $file_for_arch = [];
+        for ($i = 0; $i < $this->products_count; $i++) {
+            $my_template = new TemplateProcessor(storage_path('templates/' . $this->template));
+            $tmp_vars = [];
+            foreach ($this->vars as $k => $v) {
+                if (Str::endsWith($k, '#' . $i + 1)) {
+                    $tmp_vars[Str::replace('#' . $i + 1, '#1', $k)] = $v;
+                }
+            }
+            $my_template->cloneBlock('product_block', 1, true, true, $tmp_vars);
+            foreach ($tmp_vars as $k => $v) {
+                $file = public_path() . '/' . env('IMAGES_PATH') . '/' . $v;
+                if (str_starts_with($k, 'image') && file_exists($file) && $v !== '') {
+                    $my_template->setImageValue($k, ['path' => $file, 'width' => 270, 'height' => 180]);
+                } elseif (Str::startsWith($k, 'num')) {
+                    $my_template->setValue($k, 1);
+                } elseif (Str::startsWith($k, 'page_br')) {
+                    $my_template->setValue($k, '');
+                } else {
+                    $my_template->setValue($k, $v);
+                }
+            }
+
+            if (($i % 10) == 0) {
+                $f = fopen($tmpfile, 'w+');
+                $percent = round(($i - 2) / ($this->products_count / 100), 0);
+                fwrite($f, $percent);
+                fclose($f);
+            }
+
+            $filename = Str::replace('.docx', '_' . str_pad($i + 1, 4, 0, STR_PAD_LEFT) . '.docx', $this->filename);
+            $my_template->saveAs(public_path('exported/docx/') . $filename);
+            $file_for_arch[] = $filename;
+        }
+
+        $zip_file = public_path('exported/docx/') . Str::replace('.docx', '.zip', $this->filename);
+        $zip = new \ZipArchive();
+        $zip->open($zip_file, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
+        foreach ($file_for_arch as $file_docx) {
+            $zip->addFile(public_path('exported/docx/') . $file_docx, $file_docx);
+        }
+        $zip->close();
+
+        foreach ($file_for_arch as $file_docx) {
+            unlink(public_path('exported/docx/') . $file_docx);
+        }
+        unlink($tmpfile);
+
+        Log::notice('Generation finished: ' . $i . ' / ' . $this->products_count . '  Execution time: ' . microtime(true) - LARAVEL_START);
+    }
+}

+ 1 - 0
resources/views/products/select_export.blade.php

@@ -31,6 +31,7 @@
                                 <option value="5">Только характеристики</option>
                             </select>
                         </div>
+                        <label class="form-check-label"><input type="checkbox" name="separate_docs" value="yes" class="form-check-input me-3 mb-3"> Отдельными документами</label>
                     </div>
                     <input type="hidden" name="ids" value="{{ json_encode($ids) }}">
                     <button onclick="this.disabled()" type="submit" class="btn btn-primary">Экспорт в .docx</button>

+ 1 - 0
todo.txt

@@ -1,3 +1,4 @@
++ формирование отдельных файлов на каждый товар, заархивированных в ZIP
 + если ничего не выбрано, кнопка экспорт не доступна
 + верстку адаптиную поправить
 + Вынести импорт и экспорт в jobs (позволит импортировать/экспортировать в фоне)