Test Setup Failed
Pull Request — 0.9 (#98)
by Ben
06:58 queued 03:47
created

Asset::getPath()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
namespace Thinktomorrow\AssetLibrary;
4
5
use Spatie\MediaLibrary\InteractsWithMedia;
6
use Spatie\MediaLibrary\MediaCollections\Models\Media;
7
use Illuminate\Database\Eloquent\Model;
8
use Spatie\MediaLibrary\HasMedia;
9
10
class Asset extends Model implements HasMedia
11
{
12
    use InteractsWithMedia;
0 ignored issues
show
introduced by
The trait Spatie\MediaLibrary\InteractsWithMedia requires some properties which are not provided by Thinktomorrow\AssetLibrary\Asset: $fallbackPath, $mediaConversionRegistrations, $forceDeleting, $fallbackUrl, $media, $collection_name
Loading history...
13
14
    /**
15
     * The asset model always has one collection type. Different collection types for
16
     * the owning model are set on the asset model instead of the media model.
17
     */
18
    const MEDIA_COLLECTION = 'default';
19
20
    /**
21
     * Proxy for the data values on the associated pivot. This is the context data
22
     * relevant and unique for each owner - asset relation.
23
     */
24
    public function hasData(string $key): bool
25
    {
26
        if (!$this->pivot) return false;
0 ignored issues
show
Bug introduced by
The property pivot does not seem to exist on Thinktomorrow\AssetLibrary\Asset. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
27
28
        return $this->pivot->hasData($key);
29
    }
30
31
    /**
32
     * Proxy for the data values on the associated pivot. This is the context data
33
     * relevant and unique for each owner - asset relation.
34
     */
35
    public function getData(string $key, $default = null)
36
    {
37
        if (!$this->pivot) return $default;
0 ignored issues
show
Bug introduced by
The property pivot does not seem to exist on Thinktomorrow\AssetLibrary\Asset. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
38
39
        return $this->pivot->getData($key, $default);
40
    }
41
42
    /**
43
     * Return path of the media file. In case the passed conversion
44
     * does not exist, the path to the original is returned.
45
     */
46
    public function getPath($conversionName = ''): ?string
47
    {
48
        return $this->getFirstMediaPath(self::MEDIA_COLLECTION, $conversionName) ?: null;
49
    }
50
51
    /**
52
     * Return url of the media file. In case the passed conversion
53
     * does not exist, the url to the original is returned.
54
     */
55
    public function getUrl(string $conversionName = '', ?string $format = null): ?string
56
    {
57
        if ($conversionName !== '' && $format) {
58
            $conversionName = $format . '-' . $conversionName;
59
        }
60
61
        if (!$media = $this->getFirstMedia(self::MEDIA_COLLECTION)) {
62
            return $this->getFallbackMediaUrl(self::MEDIA_COLLECTION) ?: null;
63
        }
64
65
        if ($conversionName !== '') {
66
            if ($media->hasGeneratedConversion($conversionName)) {
67
                return $media->getUrl($conversionName) ?: null;
68
            }
69
70
            if (str_contains($conversionName, '-')) {
71
                $conversionNameWithoutFormat = substr($conversionName, strpos($conversionName, '-') + 1);
72
73
                if ($media->hasGeneratedConversion($conversionNameWithoutFormat)) {
74
                    return $media->getUrl($conversionNameWithoutFormat) ?: null;
75
                }
76
            }
77
        }
78
79
        return $media->getUrl() ?: null;
80
    }
81
82
    /**
83
     * Return filename of the media file. In case the passed conversion
84
     * does not exist, the name to the original is returned.
85
     */
86
    public function getFileName(string $conversionName = ''): ?string
87
    {
88
        if (!$path = $this->getFirstMediaPath(self::MEDIA_COLLECTION, $conversionName)) return null;
89
90
        return basename($path);
91
    }
92
93
    public function getBaseName(string $conversionName = ''): string
94
    {
95
        return basename($this->getFileName($conversionName), '.' . $this->getExtension());
0 ignored issues
show
Bug introduced by
It seems like $this->getFileName($conversionName) can also be of type null; however, parameter $path of basename() 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

95
        return basename(/** @scrutinizer ignore-type */ $this->getFileName($conversionName), '.' . $this->getExtension());
Loading history...
96
    }
97
98
    /**
99
     * Checks if the conversion exists. It checks if file
100
     * exists as media record and on the server
101
     */
102
    public function exists(string $conversionName = ''): bool
103
    {
104
        // In case there is no media model attached to our Asset.
105
        if (!$path = $this->getFirstMediaPath(self::MEDIA_COLLECTION, $conversionName)) {
106
            return false;
107
        }
108
109
        // When we specifically check if a conversion exists, we need to explicitly check if the provided path is that of the conversion.
110
        // This is because Media Library falls back to returning the original path if the converted file does not exist.
111
        if ($conversionName) {
112
            $originalPath = $this->getFirstMediaPath(self::MEDIA_COLLECTION, '');
113
            if ($originalPath == $path) return false;
114
        }
115
116
        return file_exists($path);
117
    }
118
119
    public function getSize(): int
120
    {
121
        return $this->getMediaPropertyValue('size', 0);
122
    }
123
124
    public function getHumanReadableSize(): string
125
    {
126
        return $this->getMediaPropertyValue('human_readable_size', '');
127
    }
128
129
    public function getMimeType(): ?string
130
    {
131
        return $this->getMediaPropertyValue('mime_type');
132
    }
133
134
    public function getExtension(): string
135
    {
136
        return $this->getMediaPropertyValue('extension', '');
137
    }
138
139
    public function getExtensionType(): string
140
    {
141
        return match (strtolower($this->getExtension())) {
142
            'xls', 'xlsx', 'numbers', 'sheets' => 'spreadsheet',
143
            'png', 'jpg', 'jpeg', 'gif', 'svg', 'webp' => 'image',
144
            'pdf' => 'pdf',
145
            'mp4', 'webm', 'mpeg', 'mov' => 'video',
146
            default => 'file'
147
        };
148
    }
149
150
    public function isImage(): bool
151
    {
152
        return $this->getExtensionType() == 'image';
153
    }
154
155
    public function getImageWidth(string $conversionName = ''): ?int
156
    {
157
        return $this->getImageDimensions($conversionName)['width'];
158
    }
159
160
    public function getImageHeight(string $conversionName = ''): ?int
161
    {
162
        return $this->getImageDimensions($conversionName)['height'];
163
    }
164
165
    private function getImageDimensions(string $conversionName = ''): array
166
    {
167
        $result = [
168
            'width' => null,
169
            'height' => null,
170
        ];
171
172
        if (!$this->isImage() || !$this->exists($conversionName)) {
173
            return $result;
174
        }
175
176
        if ($dimensions = getimagesize($this->getPath($conversionName))) {
177
            $result['width'] = $dimensions[0];
178
            $result['height'] = $dimensions[1];
179
        }
180
181
        return $result;
182
    }
183
184
    private function getMediaPropertyValue(string $property, $default = null)
185
    {
186
        if (!$mediaModel = $this->getFirstMedia(self::MEDIA_COLLECTION)) {
187
            return $default;
188
        }
189
190
        return $mediaModel->{$property};
191
    }
192
193
    /**
194
     * @deprecated Use getFileName instead
195
     */
196
    public function filename($size = ''): string
197
    {
198
        return $this->getFileName($size);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getFileName($size) could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
199
    }
200
201
    /**
202
     * @deprecated use getUrl() instead
203
     */
204
    public function url($size = ''): string
205
    {
206
        return $this->getUrl($size);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getUrl($size) could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
207
    }
208
209
    /**
210
     * @deprecated use exists() instead
211
     */
212
    public function hasFile(): bool
213
    {
214
        return $this->exists();
215
    }
216
217
    public function getConversions(): array
218
    {
219
        if (!$media = $this->getFirstMedia()) return [];
220
221
        return $media
222
            ->getGeneratedConversions()
223
            ->keys()
224
            ->all();
225
    }
226
227
    /**
228
     * Register the conversions that should be performed.
229
     *
230
     * @param Media|null $media
231
     * @throws \Spatie\Image\Exceptions\InvalidManipulation
232
     */
233
    public function registerMediaConversions(Media $media = null): void
234
    {
235
        $conversions = config('thinktomorrow.assetlibrary.conversions');
236
        $formats = config('thinktomorrow.assetlibrary.formats', []);
237
238
        // Remove format when original is already in one of these formats
239
        $originalFormat = null;
240
        $canKeepOriginalFormat = true;
241
242
        if ($media && false !== $formatKey = array_search($media->extension, $formats)) {
243
            unset($formats[$formatKey]);
244
245
            $originalFormat = $media->extension;
246
            $canKeepOriginalFormat = in_array(strtolower($originalFormat), ['jpg', 'jpeg', 'pjpg', 'png', 'gif']);
247
        }
248
249
        foreach ($conversions as $key => $value) {
250
            $conversion = $this->addMediaConversion($key)
251
                ->width($value['width'])
252
                ->height($value['height']);
253
254
            ($canKeepOriginalFormat || !$originalFormat)
255
                ? $conversion->keepOriginalImageFormat()
256
                : $conversion->format($originalFormat);
257
        }
258
259
        foreach ($formats as $format) {
260
            foreach ($conversions as $conversionName => $values) {
261
                $this->addMediaConversion($format . '-' . $conversionName)
262
                    ->width($value['width'])
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $value seems to be defined by a foreach iteration on line 249. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
263
                    ->height($value['height'])
264
                    ->format($format);
265
            }
266
        }
267
    }
268
}
269