Issues (18)

src/Service/ImageService.php (2 issues)

Labels
Severity
1
<?php
2
3
namespace App\Service;
4
5
use App\Entity\Image;
6
use App\Repository\WanderRepository;
7
use App\Utils\ExifHelper;
8
use Deployer\Logger\Logger;
9
use Exception;
10
use Liip\ImagineBundle\Imagine\Cache\CacheManager;
11
use PHPExif\Adapter\Exiftool;
12
use PHPExif\Reader\Reader;
13
use Psr\Log\LoggerInterface;
14
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
15
use Symfony\Component\Security\Core\Security;
16
use Vich\UploaderBundle\Templating\Helper\UploaderHelper;
17
use App\Utils\ExifHelperInterface;
18
19
class ImageService {
20
21
    /** @var UploaderHelper */
22
    private $uploaderHelper;
23
24
    /** @var CacheManager */
25
    private $imagineCacheManager;
26
27
    /** @var UrlGeneratorInterface */
28
    private $router;
29
30
    /** @var LoggerInterface */
31
    private $logger;
32
33
    /** @var WanderRepository */
34
    private $wanderRepository;
35
36
    /** @var Reader */
37
    private $reader;
38
39
    /** @var string */
40
    private $imagesDirectory;
41
42
    /** @var LocationService */
43
    private $locationService;
44
45
    /** @var string */
46
    private $exiftoolPath;
47
48
    public function __construct(
49
        UploaderHelper $uploaderHelper,
50
        CacheManager $imagineCacheManager,
51
        UrlGeneratorInterface $router,
52
        LoggerInterface $logger,
53
        WanderRepository $wanderRepository,
54
        LocationService $locationService,
55
        string $imagesDirectory,
56
        ?string $exiftoolPath)
57
    {
58
        $this->uploaderHelper = $uploaderHelper;
59
        $this->imagineCacheManager = $imagineCacheManager;
60
        $this->router = $router;
61
        $this->logger = $logger;
62
        $this->wanderRepository = $wanderRepository;
63
        $this->locationService = $locationService;
64
        $this->imagesDirectory = $imagesDirectory;
65
        $this->exiftoolPath = $exiftoolPath;
66
67
        if ($exiftoolPath !== null) {
68
            // Will throw if path is wrong
69
            $adapter = new Exiftool([
70
                'toolpath' => $exiftoolPath
71
            ]);
72
            $this->reader = new Reader($adapter);
73
        } else {
74
            $this->reader = Reader::factory(Reader::TYPE_EXIFTOOL);
75
        }
76
    }
77
78
    public function setCalculatedImageUris(Image $image): void
79
    {
80
        $image_asset_path = $this->uploaderHelper->asset($image);
81
        $image->setImageUri($image_asset_path);
0 ignored issues
show
It seems like $image_asset_path can also be of type null; however, parameter $imageUri of App\Entity\Image::setImageUri() 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

81
        $image->setImageUri(/** @scrutinizer ignore-type */ $image_asset_path);
Loading history...
82
        $image->setMarkerImageUri($this->imagineCacheManager->getBrowserPath($image_asset_path, 'marker_thumb'));
83
        $image->setMediumImageUri($this->imagineCacheManager->getBrowserPath($image_asset_path, 'map_popup_image'));
84
        $image->setImageShowUri($this->router->generate('image_show', ['id' => $image->getId()]));
85
    }
86
87
    /**
88
     * Location was a late addition and we have a Command to update existing ones. We don't want to touch
89
     * any other existing data, so this is a special one-off to set Location.
90
     */
91
    public function setLocationFromEXIF(Image $image): void
92
    {
93
        if ($image->getMimeType() !== 'image/jpeg') {
94
            $this->logger->info('Ignoring non-JPEG file when trying to set properties from EXIT.');
95
            return;
96
        }
97
98
        try {
99
            $exif = $this->reader->read($this->imagesDirectory . '/' . $image->getName());
100
            /** @var ExifHelperInterface */
101
            $exifHelper = new ExifHelper($exif);
102
            // Don't want to overwrite anything we've already set.
103
            if ($image->getLocation() === null || $image->getLocation() === '') {
104
                $image->setLocation($exifHelper->getLocation());
105
            }
106
        }
107
        catch(Exception $e) {
108
            // We've started to rely on the information gathered here, so I think
109
            // this should be a proper error now.
110
            throw new Exception('Error getting image Exif information: ' . $e->getMessage(), $e->getCode(), $e);
111
        }
112
    }
113
114
    public function setPropertiesFromEXIF(
115
            Image $image,
116
            bool $updateRelatedWander = true
117
        ): void
118
    {
119
        if ($image->getMimeType() !== 'image/jpeg') {
120
            $this->logger->info('Ignoring non-JPEG file when trying to set properties from EXIT.');
121
            return;
122
        }
123
124
        try {
125
            $exif = $this->reader->read($this->imagesDirectory . '/' . $image->getName());
126
            /** @var ExifHelperInterface */
127
            $exifHelper = new ExifHelper($exif);
128
129
            $image->setTitle($exifHelper->getTitle());
130
            $image->setDescription($exifHelper->getDescription());
131
            $image->setLatlng($exifHelper->getGPS());
132
            $image->setTagsText(implode(",", $exifHelper->getKeywords() ?? []));
133
            $image->setRating($exifHelper->getRating());
134
135
            $neighbourhood = $exifHelper->getLocation();
136
            if ($neighbourhood === null && $image->hasLatlng()) {
137
                // If we didn't set the location from the EXIF, this will try setting it
138
                // from the GPS co-ordinates.
139
                $neighbourhood = $this->locationService->getLocationName($image->getLatitude(), $image->getLongitude());
140
            }
141
            if ($neighbourhood !== null) {
142
                $image->setLocation($neighbourhood);
143
            }
144
145
            $capturedAt = $exifHelper->getCreationDate();
146
            if ($capturedAt instanceof \DateTime) {
147
                $image->setCapturedAt($capturedAt);
148
                if ($updateRelatedWander) {
149
                    // Try and find associated wander by looking for
150
                    // wanders whose timespan includes this image.
151
                    // TODO: Work out a way of adding some windage so images
152
                    // shot a little time either side of the track log still
153
                    // match.
154
                    $wander = $this->wanderRepository->findFirstWhereIncludesDate($capturedAt);
155
                    if ($wander !== null) {
156
                        $image->setWander($wander);
0 ignored issues
show
It seems like $wander can also be of type integer; however, parameter $wander of App\Entity\Image::setWander() does only seem to accept App\Entity\Wander|null, 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

156
                        $image->setWander(/** @scrutinizer ignore-type */ $wander);
Loading history...
157
                    }
158
                }
159
            }
160
        }
161
        catch(Exception $e) {
162
            // We've started to rely on the information gathered here, so I think
163
            // this should be a proper error now.
164
            throw new Exception('Error getting image Exif information: ' . $e->getMessage(), $e->getCode(), $e);
165
        }
166
    }
167
}
168
169