Passed
Branch feature/2.1-geodispersion-dev (1d61a8)
by Jonathan
61:21
created

CertificateImageFactory   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 160
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 45
c 1
b 0
f 0
dl 0
loc 160
rs 10
wmc 16

9 Methods

Rating   Name   Duplication   Size   Complexity  
A mediaFileThumbnailResponse() 0 8 1
A certificateNeedsWatermark() 0 5 1
A isMimeTypeSupported() 0 3 1
B certificateFileResponse() 0 53 8
A __construct() 0 3 1
A createWatermark() 0 4 1
A fileNeedsWatermark() 0 3 1
A thumbnailNeedsWatermark() 0 3 1
A mediaFileResponse() 0 3 1
1
<?php
2
3
/**
4
 * webtrees-lib: MyArtJaub library for webtrees
5
 *
6
 * @package MyArtJaub\Webtrees
7
 * @subpackage Certificates
8
 * @author Jonathan Jaubart <[email protected]>
9
 * @copyright Copyright (c) 2021, Jonathan Jaubart
10
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License, version 3
11
 */
12
13
declare(strict_types=1);
14
15
namespace MyArtJaub\Webtrees\Module\Certificates\Factories;
16
17
use Fig\Http\Message\StatusCodeInterface;
18
use Fisharebest\Webtrees\Auth;
19
use Fisharebest\Webtrees\MediaFile;
20
use Fisharebest\Webtrees\Webtrees;
21
use Fisharebest\Webtrees\Contracts\ImageFactoryInterface;
22
use Fisharebest\Webtrees\Contracts\UserInterface;
23
use Fisharebest\Webtrees\Factories\ImageFactory;
24
use Intervention\Image\AbstractFont;
25
use Intervention\Image\Image;
26
use Intervention\Image\Exception\NotReadableException;
27
use League\Flysystem\FilesystemException;
28
use League\Flysystem\UnableToReadFile;
29
use MyArtJaub\Webtrees\Module\Certificates\Model\Certificate;
30
use MyArtJaub\Webtrees\Module\Certificates\Model\Watermark;
31
use MyArtJaub\Webtrees\Module\Certificates\Services\CertificateFilesystemService;
32
use Psr\Http\Message\ResponseInterface;
33
use BadMethodCallException;
34
use InvalidArgumentException;
35
use Throwable;
36
37
/**
38
 * Make a certificate image (from a certificate file).
39
 */
40
class CertificateImageFactory extends ImageFactory implements ImageFactoryInterface
41
{
42
    /**
43
     * @var CertificateFilesystemService $filesystem_service
44
     */
45
    private $filesystem_service;
46
47
    /**
48
     * Constructor for the Certificate Image Factory
49
     *
50
     * @param CertificateFilesystemService $filesystem_service
51
     */
52
    public function __construct(CertificateFilesystemService $filesystem_service)
53
    {
54
        $this->filesystem_service = $filesystem_service;
55
    }
56
57
    /**
58
     * Check is a file MIME type is supported by the system.
59
     *
60
     * @param string $mime
61
     * @return bool
62
     */
63
    public function isMimeTypeSupported(string $mime): bool
64
    {
65
        return array_key_exists($mime, self::INTERVENTION_FORMATS);
66
    }
67
68
    /**
69
     * Create a full-size version of a certificate.
70
     *
71
     * @param Certificate $certificate
72
     * @param bool $add_watermark
73
     * @param Watermark $watermark
74
     * @throws InvalidArgumentException
75
     * @return ResponseInterface
76
     */
77
    public function certificateFileResponse(
78
        Certificate $certificate,
79
        bool $add_watermark = false,
80
        Watermark $watermark = null
81
    ): ResponseInterface {
82
        $filesystem =  $this->filesystem_service->filesystem($certificate->tree());
83
        $filename   = $certificate->path();
84
85
        if (!$add_watermark) {
86
            return $this->fileResponse($filesystem, $filename, false);
87
        }
88
89
        try {
90
            $image = $this->imageManager()->make($filesystem->readStream($filename));
91
            $image = $this->autorotateImage($image);
92
93
            if ($watermark == null) {
94
                throw new InvalidArgumentException('Watermark data not defined');
95
            }
96
97
            $width = $image->width();
98
            $height = $image->height();
99
100
            $watermark->adjustSize($width);
101
            $watermark_x = (int) ceil($watermark->textLengthEstimate() * 1.5);
102
            $watermark_y = $watermark->size() * 12 + 1;
103
104
            $font_definition = function (AbstractFont $font) use ($watermark): void {
105
                $font->file(Webtrees::ROOT_DIR . 'resources/fonts/DejaVuSans.ttf');
106
                $font->color($watermark->color());
107
                $font->size($watermark->size());
108
                $font->valign('top');
109
            };
110
111
            for ($i = min((int) ceil($width * 0.1), $watermark_x); $i < $width; $i += $watermark_x) {
112
                for ($j = min((int) ceil($height * 0.1), $watermark_y); $j < $height; $j += $watermark_y) {
113
                    $image = $image->text($watermark->text(), $i, $j, $font_definition);
114
                }
115
            }
116
117
            $format  = static::INTERVENTION_FORMATS[$image->mime()] ?? 'jpg';
118
            $quality = $this->extractImageQuality($image, static::GD_DEFAULT_IMAGE_QUALITY);
119
            $data    = (string) $image->encode($format, $quality);
120
121
            return $this->imageResponse($data, $image->mime(), '');
122
        } catch (NotReadableException $ex) {
123
            return $this->replacementImageResponse(pathinfo($filename, PATHINFO_EXTENSION))
0 ignored issues
show
Bug introduced by
It seems like pathinfo($filename, MyAr...ies\PATHINFO_EXTENSION) can also be of type array; however, parameter $text of Fisharebest\Webtrees\Fac...lacementImageResponse() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

123
            return $this->replacementImageResponse(/** @scrutinizer ignore-type */ pathinfo($filename, PATHINFO_EXTENSION))
Loading history...
124
            ->withHeader('X-Image-Exception', $ex->getMessage());
125
        } catch (FilesystemException | UnableToReadFile $ex) {
126
            return $this->replacementImageResponse((string) StatusCodeInterface::STATUS_NOT_FOUND);
127
        } catch (Throwable $ex) {
128
            return $this->replacementImageResponse((string) StatusCodeInterface::STATUS_INTERNAL_SERVER_ERROR)
129
            ->withHeader('X-Image-Exception', $ex->getMessage());
130
        }
131
    }
132
133
    /**
134
     * Does a full-sized certificate need a watermark?
135
     *
136
     * @param Certificate $certificate
137
     * @param UserInterface $user
138
     * @return bool
139
     */
140
    public function certificateNeedsWatermark(Certificate $certificate, UserInterface $user): bool
141
    {
142
        $tree = $certificate->tree();
143
144
        return Auth::accessLevel($tree, $user) > $tree->getPreference('MAJ_CERTIF_SHOW_NO_WATERMARK');
145
    }
146
147
    /**
148
     * Neutralise the methods associated with MediaFile.
149
     */
150
151
    /**
152
     * {@inheritDoc}
153
     * @see \Fisharebest\Webtrees\Factories\ImageFactory::mediaFileResponse()
154
     */
155
    public function mediaFileResponse(MediaFile $media_file, bool $add_watermark, bool $download): ResponseInterface
156
    {
157
        throw new BadMethodCallException("Invalid method for Certificates");
158
    }
159
160
    /**
161
     * {@inheritDoc}
162
     * @see \Fisharebest\Webtrees\Factories\ImageFactory::mediaFileThumbnailResponse()
163
     */
164
    public function mediaFileThumbnailResponse(
165
        MediaFile $media_file,
166
        int $width,
167
        int $height,
168
        string $fit,
169
        bool $add_watermark
170
    ): ResponseInterface {
171
        throw new BadMethodCallException("Invalid method for Certificates");
172
    }
173
174
    /**
175
     * {@inheritDoc}
176
     * @see \Fisharebest\Webtrees\Factories\ImageFactory::createWatermark()
177
     */
178
    public function createWatermark(int $width, int $height, MediaFile $media_file): Image
179
    {
180
181
        throw new BadMethodCallException("Invalid method for Certificates");
182
    }
183
184
    /**
185
     * {@inheritDoc}
186
     * @see \Fisharebest\Webtrees\Factories\ImageFactory::fileNeedsWatermark()
187
     */
188
    public function fileNeedsWatermark(MediaFile $media_file, UserInterface $user): bool
189
    {
190
        throw new BadMethodCallException("Invalid method for Certificates");
191
    }
192
193
    /**
194
     * {@inheritDoc}
195
     * @see \Fisharebest\Webtrees\Factories\ImageFactory::thumbnailNeedsWatermark()
196
     */
197
    public function thumbnailNeedsWatermark(MediaFile $media_file, UserInterface $user): bool
198
    {
199
        throw new BadMethodCallException("Invalid method for Certificates");
200
    }
201
}
202