Passed
Push — master ( 246ca5...f72f04 )
by Caen
03:27 queued 14s
created

Image::make()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Hyde\Framework\Models\Support;
4
5
use Hyde\Framework\Actions\Constructors\FindsContentLengthForImageObject;
6
use Hyde\Framework\Contracts\FrontMatter\Support\FeaturedImageSchema;
7
use Hyde\Framework\Hyde;
8
9
/**
10
 * Holds the information for an image.
11
 *
12
 * $schema = [
13
 *    'path'         => '?string',
14
 *    'url'          => '?string',
15
 *    'description'  => '?string',
16
 *    'title'        => '?string',
17
 *    'copyright'    => '?string',
18
 *    'license'      => '?string',
19
 *    'licenseUrl'   => '?string',
20
 *    'author'       => '?string',
21
 *    'credit'       => '?string'
22
 * ];
23
 *
24
 * @see \Hyde\Framework\Testing\Feature\ImageModelTest
25
 * @phpstan-consistent-constructor
26
 */
27
class Image implements FeaturedImageSchema, \Stringable
28
{
29
    /**
30
     * The image's path (if it is stored locally (in the _media directory)).
31
     * Example: image.jpg.
32
     *
33
     * @var string|null
34
     */
35
    public ?string $path;
36
37
    /**
38
     * The image's URL (if stored externally).
39
     * Example: https://example.com/media/image.jpg.
40
     *
41
     * Will override the path property if both are set.
42
     *
43
     * @var string|null
44
     */
45
    public ?string $url;
46
47
    /**
48
     * The image's description. (Used for alt text for screen readers.)
49
     * You should always set this to provide accessibility.
50
     * Example: "This is an image of a cat sitting in a basket.".
51
     *
52
     * @var string|null
53
     */
54
    public ?string $description;
55
56
    /**
57
     * The image's title. (Shows a tooltip on hover.)
58
     * Example: "My Cat Archer".
59
     *
60
     * @var string|null
61
     */
62
    public ?string $title;
63
64
    /**
65
     * The image's copyright.
66
     * Example: "Copyright (c) 2020 John Doe".
67
     *
68
     * @var string|null
69
     */
70
    public ?string $copyright;
71
72
    /**
73
     * The image's license name.
74
     * Example: "CC BY-NC-SA 4.0".
75
     *
76
     * @var string|null
77
     */
78
    public ?string $license;
79
80
    /**
81
     * The image's license URL.
82
     * Example: "https://creativecommons.org/licenses/by-nc-sa/4.0/".
83
     *
84
     * @var string|null
85
     */
86
    public ?string $licenseUrl;
87
88
    /**
89
     * The image's author.
90
     * Example: "John Doe".
91
     *
92
     * @var string|null
93
     */
94
    public ?string $author;
95
96
    /**
97
     * The image's source (for attribution).
98
     * Example: "https://unsplash.com/photos/example".
99
     *
100
     * @var string|null
101
     */
102
    public ?string $credit = null;
103
104
    public function __construct(array $data = [])
105
    {
106
        foreach ($data as $key => $value) {
107
            $this->{$key} = $value;
108
        }
109
110
        if (isset($this->path)) {
111
            $this->path = basename($this->path);
0 ignored issues
show
Bug introduced by
It seems like $this->path 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

111
            $this->path = basename(/** @scrutinizer ignore-type */ $this->path);
Loading history...
112
        }
113
    }
114
115
    /** @inheritDoc */
116
    public function __toString()
117
    {
118
        return $this->getLink();
119
    }
120
121
    /** Dynamically create an image based on string or front matter array */
122
    public static function make(string|array $data): static
123
    {
124
        if (is_string($data)) {
0 ignored issues
show
introduced by
The condition is_string($data) is always false.
Loading history...
125
            return static::fromSource($data);
126
        }
127
128
        return new static($data);
129
    }
130
131
    public static function fromSource(string $image): static
132
    {
133
        return str_starts_with($image, 'http')
134
            ? new static(['url' => $image])
135
            : new static(['path' => $image]);
136
    }
137
138
    public function getSource(): string
139
    {
140
        return $this->url ?? $this->getPath() ?? throw new \Exception('Attempting to get source from Image that has no source.');
141
    }
142
143
    public function getLink(): string
144
    {
145
        return Hyde::image($this->getSource());
146
    }
147
148
    public function getContentLength(): int
149
    {
150
        return (new FindsContentLengthForImageObject($this))->execute();
151
    }
152
153
    public function getImageAuthorAttributionString(): string|null
154
    {
155
        if (isset($this->author)) {
156
            if (isset($this->credit)) {
157
                return '<span itemprop="creator" itemscope="" itemtype="http://schema.org/Person"><a href="'.e($this->credit).'" rel="author noopener nofollow" itemprop="url"><span itemprop="name">'.e($this->author).'</span></a></span>';
158
            } else {
159
                return '<span itemprop="creator" itemscope="" itemtype="http://schema.org/Person"><span itemprop="name">'.e($this->author).'</span></span>';
160
            }
161
        }
162
163
        return null;
164
    }
165
166
    public function getCopyrightString(): string|null
167
    {
168
        if (isset($this->copyright)) {
169
            return '<span itemprop="copyrightNotice">'.e($this->copyright).'</span>';
170
        }
171
172
        return null;
173
    }
174
175
    public function getLicenseString(): string|null
176
    {
177
        if (isset($this->license) && isset($this->licenseUrl)) {
178
            return '<a href="'.e($this->licenseUrl).'" rel="license nofollow noopener" itemprop="license">'.e($this->license).'</a>';
179
        }
180
181
        if (isset($this->license)) {
182
            return '<span itemprop="license">'.e($this->license).'</span>';
183
        }
184
185
        return null;
186
    }
187
188
    public function getFluentAttribution(): string
189
    {
190
        $attribution = [];
191
192
        $getImageAuthorAttributionString = $this->getImageAuthorAttributionString();
193
        if ($getImageAuthorAttributionString !== null) {
194
            $attribution[] = 'Image by '.$getImageAuthorAttributionString;
195
        }
196
197
        $getCopyrightString = $this->getCopyrightString();
198
        if ($getCopyrightString !== null) {
199
            $attribution[] = $getCopyrightString;
200
        }
201
202
        $getLicenseString = $this->getLicenseString();
203
        if ($getLicenseString !== null) {
204
            $attribution[] = 'License '.$getLicenseString;
205
        }
206
207
        return implode('. ', $attribution);
208
    }
209
210
    /**
211
     * Used in resources\views\components\post\image.blade.php to add meta tags with itemprop attributes.
212
     *
213
     * @return array
214
     */
215
    public function getMetadataArray(): array
216
    {
217
        $metadata = [];
218
219
        if (isset($this->description)) {
220
            $metadata['text'] = $this->description;
221
        }
222
223
        if (isset($this->title)) {
224
            $metadata['name'] = $this->title;
225
        }
226
227
        $metadata['url'] = $this->getLink();
228
        $metadata['contentUrl'] = $this->getLink();
229
230
        return $metadata;
231
    }
232
233
    protected function getPath(): ?string
234
    {
235
        if (isset($this->path)) {
236
            return basename($this->path);
0 ignored issues
show
Bug introduced by
It seems like $this->path 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

236
            return basename(/** @scrutinizer ignore-type */ $this->path);
Loading history...
237
        }
238
239
        return null;
240
    }
241
}
242