jon48/webtrees-lib

View on GitHub
app/Module/Certificates/Factories/CertificateImageFactory.php

Summary

Maintainability
A
3 hrs
Test Coverage
<?php

/**
 * webtrees-lib: MyArtJaub library for webtrees
 *
 * @package MyArtJaub\Webtrees
 * @subpackage Certificates
 * @author Jonathan Jaubart <dev@jaubart.com>
 * @copyright Copyright (c) 2021-2022, Jonathan Jaubart
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License, version 3
 */

declare(strict_types=1);

namespace MyArtJaub\Webtrees\Module\Certificates\Factories;

use Fig\Http\Message\StatusCodeInterface;
use Fisharebest\Webtrees\Auth;
use Fisharebest\Webtrees\MediaFile;
use Fisharebest\Webtrees\Webtrees;
use Fisharebest\Webtrees\Contracts\ImageFactoryInterface;
use Fisharebest\Webtrees\Contracts\UserInterface;
use Fisharebest\Webtrees\Factories\ImageFactory;
use Intervention\Image\AbstractFont;
use Intervention\Image\Image;
use Intervention\Image\Exception\NotReadableException;
use League\Flysystem\FilesystemException;
use League\Flysystem\UnableToReadFile;
use MyArtJaub\Webtrees\Module\Certificates\Model\Certificate;
use MyArtJaub\Webtrees\Module\Certificates\Model\Watermark;
use MyArtJaub\Webtrees\Module\Certificates\Services\CertificateFilesystemService;
use Psr\Http\Message\ResponseInterface;
use BadMethodCallException;
use InvalidArgumentException;
use Throwable;

/**
 * Make a certificate image (from a certificate file).
 */
class CertificateImageFactory extends ImageFactory implements ImageFactoryInterface
{
    /**
     * @var CertificateFilesystemService $filesystem_service
     */
    private $filesystem_service;

    /**
     * Constructor for the Certificate Image Factory
     *
     * @param CertificateFilesystemService $filesystem_service
     */
    public function __construct(CertificateFilesystemService $filesystem_service)
    {
        $this->filesystem_service = $filesystem_service;
    }

    /**
     * Check is a file MIME type is supported by the system.
     *
     * @param string $mime
     * @return bool
     */
    public function isMimeTypeSupported(string $mime): bool
    {
        return array_key_exists($mime, self::SUPPORTED_FORMATS);
    }

    /**
     * Create a full-size version of a certificate.
     *
     * @param Certificate $certificate
     * @param bool $add_watermark
     * @param Watermark $watermark
     * @throws InvalidArgumentException
     * @return ResponseInterface
     */
    public function certificateFileResponse(
        Certificate $certificate,
        bool $add_watermark = false,
        Watermark $watermark = null
    ): ResponseInterface {
        $filesystem =  $this->filesystem_service->filesystem($certificate->tree());
        $filename   = $certificate->path();

        if (!$add_watermark) {
            return $this->fileResponse($filesystem, $filename, false);
        }

        try {
            $image = $this->imageManager()->make($filesystem->readStream($filename));
            $image = $this->autorotateImage($image);

            if ($watermark === null) {
                throw new InvalidArgumentException('Watermark data not defined');
            }

            $width = $image->width();
            $height = $image->height();

            $watermark->adjustSize($width);
            $watermark_x = (int) ceil($watermark->textLengthEstimate() * 1.5);
            $watermark_y = $watermark->size() * 12 + 1;

            $font_definition = function (AbstractFont $font) use ($watermark): void {
                $font->file(Webtrees::ROOT_DIR . 'resources/fonts/DejaVuSans.ttf');
                $font->color($watermark->color());
                $font->size($watermark->size());
                $font->valign('top');
            };

            for ($i = min((int) ceil($width * 0.1), $watermark_x); $i < $width; $i += $watermark_x) {
                for ($j = min((int) ceil($height * 0.1), $watermark_y); $j < $height; $j += $watermark_y) {
                    $image = $image->text($watermark->text(), $i, $j, $font_definition);
                }
            }

            $format  = static::SUPPORTED_FORMATS[$image->mime()] ?? 'jpg';
            $quality = $this->extractImageQuality($image, static::GD_DEFAULT_IMAGE_QUALITY);
            $data    = (string) $image->encode($format, $quality);

            return $this->imageResponse($data, $image->mime(), '');
        } catch (NotReadableException $ex) {
            return $this->replacementImageResponse(pathinfo($filename, PATHINFO_EXTENSION))
            ->withHeader('X-Image-Exception', $ex->getMessage());
        } catch (FilesystemException | UnableToReadFile $ex) {
            return $this->replacementImageResponse((string) StatusCodeInterface::STATUS_NOT_FOUND);
        } catch (Throwable $ex) {
            return $this->replacementImageResponse((string) StatusCodeInterface::STATUS_INTERNAL_SERVER_ERROR)
            ->withHeader('X-Image-Exception', $ex->getMessage());
        }
    }

    /**
     * Does a full-sized certificate need a watermark?
     *
     * @param Certificate $certificate
     * @param UserInterface $user
     * @return bool
     */
    public function certificateNeedsWatermark(Certificate $certificate, UserInterface $user): bool
    {
        $tree = $certificate->tree();
        $watermark_level = (int) ($tree->getPreference('MAJ_CERTIF_SHOW_NO_WATERMARK', (string) Auth::PRIV_HIDE));

        return Auth::accessLevel($tree, $user) > $watermark_level;
    }

    /**
     * Neutralise the methods associated with MediaFile.
     */

    /**
     * {@inheritDoc}
     * @see \Fisharebest\Webtrees\Factories\ImageFactory::mediaFileResponse()
     */
    public function mediaFileResponse(MediaFile $media_file, bool $add_watermark, bool $download): ResponseInterface
    {
        throw new BadMethodCallException("Invalid method for Certificates");
    }

    /**
     * {@inheritDoc}
     * @see \Fisharebest\Webtrees\Factories\ImageFactory::mediaFileThumbnailResponse()
     */
    public function mediaFileThumbnailResponse(
        MediaFile $media_file,
        int $width,
        int $height,
        string $fit,
        bool $add_watermark
    ): ResponseInterface {
        throw new BadMethodCallException("Invalid method for Certificates");
    }

    /**
     * {@inheritDoc}
     * @see \Fisharebest\Webtrees\Factories\ImageFactory::createWatermark()
     */
    public function createWatermark(int $width, int $height, MediaFile $media_file): Image
    {

        throw new BadMethodCallException("Invalid method for Certificates");
    }

    /**
     * {@inheritDoc}
     * @see \Fisharebest\Webtrees\Factories\ImageFactory::fileNeedsWatermark()
     */
    public function fileNeedsWatermark(MediaFile $media_file, UserInterface $user): bool
    {
        throw new BadMethodCallException("Invalid method for Certificates");
    }

    /**
     * {@inheritDoc}
     * @see \Fisharebest\Webtrees\Factories\ImageFactory::thumbnailNeedsWatermark()
     */
    public function thumbnailNeedsWatermark(MediaFile $media_file, UserInterface $user): bool
    {
        throw new BadMethodCallException("Invalid method for Certificates");
    }
}