Failed Conditions
Push — master ( 27554e...857869 )
by Luca
09:08
created

Zip::insertLegend()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 50
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 42
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 41
dl 0
loc 50
ccs 42
cts 42
cp 1
rs 8.6417
c 0
b 0
f 0
cc 6
nc 4
nop 2
crap 6
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Application\Service\Exporter;
6
7
use Application\Model\Card;
8
use Application\Model\Export;
9
use Application\Model\User;
10
use Application\Utility;
11
use Ecodev\Felix\Api\Exception;
12
use Ecodev\Felix\Service\ImageResizer;
13
use Laminas\Escaper\Escaper;
14
use ZipArchive;
15
16
/**
17
 * Export multiples cards as zip file.
18
 */
19
class Zip implements Writer
20
{
21
    private ?ZipArchive $zip = null;
22
23
    private int $fileIndex = 0;
24
25
    private Export $export;
26
27
    private readonly Escaper $escape;
28
29 1
    public function __construct(private readonly ImageResizer $imageResizer)
30
    {
31 1
        $this->escape = new Escaper();
0 ignored issues
show
Bug introduced by
The property escape is declared read-only in Application\Service\Exporter\Zip.
Loading history...
32
    }
33
34 2
    public function getExtension(): string
35
    {
36 2
        return 'zip';
37
    }
38
39 3
    public function initialize(Export $export, string $title): void
40
    {
41 3
        $this->fileIndex = 0;
42 3
        $this->export = $export;
43 3
        $this->zip = new ZipArchive();
44 3
        $result = $this->zip->open($export->getPath(), ZipArchive::CREATE | ZipArchive::OVERWRITE);
45
46 3
        if ($result !== true) {
47
            throw new Exception($this->zip->getStatusString());
48
        }
49
    }
50
51 3
    public function write(Card $card): void
52
    {
53 3
        $image = $this->insertImage($card);
54 3
        if ($this->export->isIncludeLegend()) {
55 3
            $this->insertLegend($card, $image);
56
        }
57
    }
58
59 3
    public function finalize(): void
60
    {
61 3
        if ($this->fileIndex === 0) {
62
            $this->zip->addFromString('readme.txt', "Aucune fiche n'était exportable. Probablement parce qu'aucune fiche n'avait d'images.");
0 ignored issues
show
Bug introduced by
The method addFromString() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

62
            $this->zip->/** @scrutinizer ignore-call */ 
63
                        addFromString('readme.txt', "Aucune fiche n'était exportable. Probablement parce qu'aucune fiche n'avait d'images.");

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
63
        }
64
65 3
        $this->zip->close();
66
    }
67
68 3
    private function insertImage(Card $card): string
69
    {
70
        // Skip if no image
71 3
        if (!$card->hasImage() || !is_readable($card->getPath())) {
72 1
            return '';
73
        }
74
75 3
        if ($this->export->getMaxHeight()) {
76
            $path = $this->imageResizer->resize($card, $this->export->getMaxHeight(), false);
77
        } else {
78 3
            $path = $card->getPath();
79
        }
80
81 3
        $extension = pathinfo($path, PATHINFO_EXTENSION);
82 3
        $filename = $card->getId() . ($extension ? '.' . $extension : '');
0 ignored issues
show
Bug introduced by
Are you sure $extension of type array|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

82
        $filename = $card->getId() . ($extension ? '.' . /** @scrutinizer ignore-type */ $extension : '');
Loading history...
83 3
        $added = $this->zip->addFile($path, $filename);
84
85 3
        if ($added) {
86 3
            $this->zip->setCompressionIndex($this->fileIndex++, ZipArchive::CM_STORE);
87
        }
88
89 3
        return $filename;
90
    }
91
92 3
    private function insertLegend(Card $card, string $image): void
93
    {
94 3
        $html = '<!DOCTYPE html>';
95 3
        $html .= '<html lang="fr">';
96 3
        $html .= '<head>';
97 3
        $html .= '<title>Base de données ' . $this->export->getSite() . '</title>';
98 3
        $html .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
99 3
        $html .= '<meta name="author" content="' . $this->escape->escapeHtmlAttr(User::getCurrent() ? User::getCurrent()->getLogin() : '') . '" />';
100 3
        $html .= '<style>';
101 3
        $html .= '.detail table { margin:auto; padding:5px; background-color:#d8e7f3; }';
102 3
        $html .= '.detail th { width:150px; padding-right:5px; text-align:right; }';
103 3
        $html .= '.detail th:first-letter {text-transform:uppercase}';
104 3
        $html .= '.detail td { min-width: 500px }';
105 3
        $html .= '.detail img { max-width:800px; max-height:600px; }';
106 3
        $html .= '</style>';
107 3
        $html .= '</head><body>';
108 3
        $html .= '<div class="detail">';
109 3
        $html .= '<table>';
110 3
        $html .= '<tr><td colspan="2"><a href="' . $this->escape->escapeHtmlAttr($image) . '"><img src="' . $this->escape->escapeHtmlAttr($image) . '" alt="' . $this->escape->escapeHtmlAttr(Utility::richTextToPlainText($card->getName())) . '"/></a></td></tr>';
111
112 3
        $html .= $this->row('titre', $card->getName());
113 3
        $html .= $this->row('titre étendu', $card->getExpandedName());
114
115 3
        $artists = [];
116 3
        foreach ($card->getArtists() as $artist) {
117 1
            $artists[] = $artist->getName();
118
        }
119 3
        $html .= $this->row('artiste', implode('<br>', $artists));
120
121 3
        $html .= $this->row('supplément', $card->getAddition());
122 3
        $html .= $this->row('datation', $card->getDating());
123 3
        $html .= $this->row('domaine', $card->getDilpsDomain());
124 3
        $html .= $this->row('technique & matériel', $card->getMaterial());
125 3
        $html .= $this->row('format', $card->getFormat());
126 3
        $html .= $this->row('adresse', implode(', ', array_filter([$card->getStreet(), $card->getPostcode(), $card->getLocality(), $card->getArea(), $card->getCountry() ? $card->getCountry()->getName() : ''])));
127 3
        $html .= $this->row('institution', $card->getInstitution() ? $card->getInstitution()->getName() : '');
128 3
        $html .= $this->row('literature', $card->getLiterature());
129 3
        $html .= $this->row('page', $card->getPage());
130 3
        $html .= $this->row('planche', $card->getFigure());
131 3
        $html .= $this->row('table', $card->getTable());
132 3
        $html .= $this->row('ISBN', $card->getIsbn());
133
134 3
        $html .= '</table>';
135 3
        $html .= '</div>';
136 3
        $html .= '</body></html>';
137
138 3
        $added = $this->zip->addFromString($card->getId() . '.html', $html);
139
140 3
        if ($added) {
141 3
            $this->zip->setCompressionIndex($this->fileIndex++, ZipArchive::CM_STORE);
142
        }
143
    }
144
145 3
    private function row(string $label, string $value): string
146
    {
147 3
        if (!$value) {
148 3
            return '';
149
        }
150
151 3
        return '<tr><th>' . $label . '</th><td>' . $value . '</td></tr>' . PHP_EOL;
152
    }
153
}
154