Passed
Push — dev ( 27f9c6...416221 )
by
unknown
05:20
created

Lincable::getExtension()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Lincable\Eloquent;
4
5
use File;
6
use Lincable\MediaManager;
7
use Lincable\Http\FileRequest;
8
use Lincable\Http\File\FileFactory;
9
use Illuminate\Container\Container;
10
use Lincable\Http\File\FileResolver;
11
use Illuminate\Http\File as IlluminateFile;
12
use Lincable\Exceptions\LinkNotFoundException;
13
14
trait Lincable
15
{
16
    use CloneLinks;
17
18
    /**
19
     * Resolved media manager instance.
20
     *
21
     * @var \Lincable\MediaManager
22
     */
23
    protected static $mediaManager;
24
25
    /**
26
     * Boots the trait.
27
     *
28
     * @return void
29
     */
30 31
    protected static function bootLincable()
31
    {
32
        static::deleted(function ($model) {
33 3
            if (! $model->shouldKeepMediaWhenDeleted()) {
34 1
                static::getMediaManager()->delete($model);
0 ignored issues
show
Bug introduced by
The method delete() does not exist on Lincable\MediaManager. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

34
                static::getMediaManager()->/** @scrutinizer ignore-call */ delete($model);
Loading history...
35
            }
36 31
        });
37 31
    }
38
39
    /**
40
     * Return the raw url saved on database.
41
     *
42
     * @return string
43
     *
44
     * @throws \Lincable\Exceptions\LinkNotFoundException
45
     */
46 26
    public function getRawUrl()
47
    {
48 26
        return $this->getAttributeFromArray($this->getUrlField());
0 ignored issues
show
Bug introduced by
It seems like getAttributeFromArray() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

48
        return $this->/** @scrutinizer ignore-call */ getAttributeFromArray($this->getUrlField());
Loading history...
49
    }
50
51
    /**
52
     * Return the full url media from model.
53
     *
54
     * @return void
55
     */
56 2
    public function getUrl()
57
    {
58 2
        return static::getMediaManager()->url($this);
0 ignored issues
show
Bug Best Practice introduced by
The expression return static::getMediaManager()->url($this) also could return the type string which is incompatible with the documented return type void.
Loading history...
Bug introduced by
$this of type Lincable\Eloquent\Lincable is incompatible with the type Illuminate\Database\Eloquent\Model expected by parameter $model of Lincable\MediaManager::url(). ( Ignorable by Annotation )

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

58
        return static::getMediaManager()->url(/** @scrutinizer ignore-type */ $this);
Loading history...
59
    }
60
61
    /**
62
     * Escope to easily create a fresh model from a FileRequest class.
63
     *
64
     * @param  mixed  $query
65
     * @param  \Lincable\Http\FileRequest  $fileRequest
66
     * @return mixed
67
     */
68 1
    public function scopeCreateWithFileRequest($query, FileRequest $fileRequest)
69
    {
70 1
        return tap(
71 1
            $query->newModelInstance($fileRequest->all()),
72
            function ($instance) use ($fileRequest) {
73 1
                $instance->perfomCreateWithFileRequest($fileRequest);
74 1
            }
75
        );
76
    }
77
78
    /**
79
     * Execute creation events and upload process for the file request.
80
     *
81
     * @param  \Lincable\Http\FileRequest  $request
82
     * @return void
83
     */
84 1
    public function perfomCreateWithFileRequest(FileRequest $request)
85
    {
86 1
        if ($request->getFile() === null) {
87
            return $this->save();
0 ignored issues
show
Bug introduced by
It seems like save() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

87
            return $this->/** @scrutinizer ignore-call */ save();
Loading history...
88
        }
89
90 1
        if ($this->fireModelEvent('creating') === false) {
0 ignored issues
show
Bug introduced by
It seems like fireModelEvent() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

90
        if ($this->/** @scrutinizer ignore-call */ fireModelEvent('creating') === false) {
Loading history...
91
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type void.
Loading history...
92
        }
93
94 1
        $silentEvents = $this->getSilentUploadEvents();
95
        
96 1
        \Event::fakeFor(
97
            function () use ($request) {
98
                // First we create the model on database, then we are allowed to proceed
99
                // sending the file to storage, no more breaks stops us from finishing,
100
                // unless upload failed.
101 1
                $this->save();
102 1
                $this->link($request);
103 1
            },
104
            array_map(function ($event) {
105 1
                return "eloquent.{$event}: ".static::class;
106 1
            }, $silentEvents)
107
        );
108
109 1
        $this->fireModelEvent('created');
110 1
    }
111
112
    /**
113
     * Link the model to a file.
114
     *
115
     * @param  mixed  $file
116
     * @return bool
117
     */
118 19
    public function link($file)
119
    {
120
        // Resolve the file object to link the model. It can
121
        // be a symfony uploaded file or a file request, which
122
        // is preferable for linking.
123 19
        $file = FileResolver::resolve($file);
124
        
125
        // Handle the file upload to the disk storage. All errors on upload are covered
126
        // for better handling upload events. Once the upload has been executed with
127
        // success, the model is auto updated, setting the url_field model configuration
128
        // with the path to the new file. On error, an event of failure is dispatched and
129
        // a HTTPException is also reported, if not covered will return a 409 HTTP status.
130 19
        $saved = static::getMediaManager()
131 19
            ->upload($file, $this, $this->getCustomUploadHeaders())
0 ignored issues
show
Bug introduced by
$this of type Lincable\Eloquent\Lincable is incompatible with the type Illuminate\Database\Eloquent\Model expected by parameter $model of Lincable\MediaManager::upload(). ( Ignorable by Annotation )

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

131
            ->upload($file, /** @scrutinizer ignore-type */ $this, $this->getCustomUploadHeaders())
Loading history...
132 18
            ->save();
133
134
        // verifies whether it is necessary to update the updated_at field
135 18
        if ($saved && $this->wasRecentlyCreated) {
0 ignored issues
show
Bug Best Practice introduced by
The property wasRecentlyCreated does not exist on Lincable\Eloquent\Lincable. Since you implemented __get, consider adding a @property annotation.
Loading history...
136 18
            return $this->touch();
0 ignored issues
show
Bug introduced by
It seems like touch() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

136
            return $this->/** @scrutinizer ignore-call */ touch();
Loading history...
137
        }
138
        return $saved;
139
    }
140
141
    /**
142
     * Execute a container callable with the file as argument.
143
     *
144
     * @param  mixed $callback
145
     * @return this
146
     */
147 4
    public function withMedia($callback)
148
    {
149 4
        $this->ensureHasUrl();
150
151
        // Get the current media manager of application.
152 4
        $mediaManager = static::getMediaManager();
153
154
        // Create a temporary file with the model file contents. Provide the
155
        // the default disk registered on media manager.
156 4
        $file = $mediaManager->get($this);
0 ignored issues
show
Bug introduced by
$this of type Lincable\Eloquent\Lincable is incompatible with the type Illuminate\Database\Eloquent\Model expected by parameter $model of Lincable\MediaManager::get(). ( Ignorable by Annotation )

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

156
        $file = $mediaManager->get(/** @scrutinizer ignore-type */ $this);
Loading history...
157
158
        try {
159
            // Execute the callable with the temporary file. You also can receive the
160
            // model instance as second argument.
161 4
            Container::getInstance()->call($callback, [$file, $this]);
162
        } catch (\Exception $ex) {
163
            // Delete the temporary file wheter it exists.
164
            File::delete($file->path());
165
166
            // Throw exception again to show developer something bad happened.
167
            throw $ex;
168
        }
169
170 4
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Illuminate\Database\Eloquent\Model which is incompatible with the documented return type Lincable\Eloquent\Lincable.
Loading history...
171
    }
172
173
    /**
174
     * Return the url field to link the model.
175
     *
176
     * @return string
177
     */
178 27
    public function getUrlField()
179
    {
180 27
        return isset($this->urlField)
0 ignored issues
show
Bug Best Practice introduced by
The property urlField does not exist on Lincable\Eloquent\Lincable. Since you implemented __get, consider adding a @property annotation.
Loading history...
181 1
            ? $this->urlField
182 27
            : config('lincable.models.url_field');
183
    }
184
185
    /**
186
     * Return the name of the file.
187
     *
188
     * @return string
189
     */
190 6
    public function getFileName()
191
    {
192 6
        $this->ensureHasUrl();
193 6
        return FileFactory::fileName($this->getRawUrl());
194
    }
195
196
    /**
197
     * Return the file extension.
198
     *
199
     * @return string
200
     */
201 2
    public function getExtension()
202
    {
203 2
        return FileFactory::extension($this->getFileName());
204
    }
205
206
    /**
207
     * Fulfill the url on correct attribute name.
208
     *
209
     * @param  string  $url
210
     * @return void
211
     */
212 20
    public function fillUrl(string $url)
213
    {
214
        // Fill the url with unguarded permissions.
215
        static::unguarded(function () use ($url) {
216 20
            $this->fill([$this->getUrlField() => ltrim($url, '/')]);
0 ignored issues
show
Bug introduced by
The method fill() does not exist on Lincable\Eloquent\Lincable. Did you maybe mean fillUrl()? ( Ignorable by Annotation )

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

216
            $this->/** @scrutinizer ignore-call */ 
217
                   fill([$this->getUrlField() => ltrim($url, '/')]);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
217 20
        });
218
219 20
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Lincable\Eloquent\Lincable which is incompatible with the documented return type void.
Loading history...
220
    }
221
222
    /**
223
     * Return the media manager instance.
224
     *
225
     * @return \Lincable\MediaManager
226
     */
227 19
    public static function getMediaManager()
228
    {
229 19
        if (static::$mediaManager === null) {
230
            static::$mediaManager = resolve(MediaManager::class);
231
        }
232
233 19
        return static::$mediaManager;
234
    }
235
    
236
    /**
237
     * Set the newly media manager.
238
     *
239
     * @param  \Lincable\MediaManager  $manager
240
     * @return void
241
     */
242 29
    public static function setMediaManager(MediaManager $manager)
243
    {
244 29
        static::$mediaManager = $manager;
245 29
    }
246
247
    /**
248
     * Determine wheter shoul keep the media for the model.
249
     *
250
     * @return bool
251
     */
252 3
    public function shouldKeepMediaWhenDeleted()
253
    {
254
        return (bool) (
255 3
            isset($this->keepMediaOnDelete)
0 ignored issues
show
Bug Best Practice introduced by
The property keepMediaOnDelete does not exist on Lincable\Eloquent\Lincable. Since you implemented __get, consider adding a @property annotation.
Loading history...
256 1
                ? $this->keepMediaOnDelete
257 3
                : config('lincable.keep_media_on_delete', false)
258
            );
259
    }
260
261
    /**
262
     * Returns the list of uploda headers for model.
263
     *
264
     * @return array
265
     */
266 19
    public function getCustomUploadHeaders()
267
    {
268
        return (array) (
269 19
            isset($this->customUploadHeaders)
0 ignored issues
show
Bug Best Practice introduced by
The property customUploadHeaders does not exist on Lincable\Eloquent\Lincable. Since you implemented __get, consider adding a @property annotation.
Loading history...
270
                ? $this->customUploadHeaders
271 19
                : config('lincable.upload_headers', [])
272
        );
273
    }
274
275
    /**
276
     * List of events to not be fired when creating the model
277
     * from a FileRequest. As the model is only considered really
278
     * created after file upload is ready, we only fire events after that.
279
     *
280
     * @return array
281
     */
282 1
    protected function getSilentUploadEvents()
283
    {
284
        return (array) (
285 1
            $this->silentUploadEvents ??
0 ignored issues
show
Bug Best Practice introduced by
The property silentUploadEvents does not exist on Lincable\Eloquent\Lincable. Since you implemented __get, consider adding a @property annotation.
Loading history...
286 1
            config('lincable.models.silent_upload_events', [])
287
        );
288
    }
289
290
    /**
291
     * Forward getter call.
292
     *
293
     * @param  mixed  $key
294
     * @return mixed
295
     */
296 3
    public function __get($key)
297
    {
298 3
        if ($key === $this->getUrlField()) {
299
            // Let the model to use own resolution logic to create the link.
300 3
            if ($this->hasGetMutator($key)) {
0 ignored issues
show
Bug introduced by
It seems like hasGetMutator() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

300
            if ($this->/** @scrutinizer ignore-call */ hasGetMutator($key)) {
Loading history...
301 1
                return $this->mutateAttribute($key, $this->getRawUrl());
0 ignored issues
show
Bug introduced by
It seems like mutateAttribute() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

301
                return $this->/** @scrutinizer ignore-call */ mutateAttribute($key, $this->getRawUrl());
Loading history...
302
            }
303
304 2
            return $this->getUrl();
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getUrl() targeting Lincable\Eloquent\Lincable::getUrl() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
305
        }
306
307
        return $this->getAttribute($key);
0 ignored issues
show
Bug introduced by
It seems like getAttribute() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

307
        return $this->/** @scrutinizer ignore-call */ getAttribute($key);
Loading history...
308
    }
309
310
    /**
311
     * Get content as a string of HTML.
312
     *
313
     * @return string
314
     */
315 1
    public function toHtml()
316
    {
317 1
        $url = $this->{$this->getUrlField()};
318
319 1
        $options = collect($this->getHtmlOptions())
320
            ->map(function ($value, $key) {
321
                if (is_int($key)) {
322
                    $key = $value;
323
                    $value = '';
324
                }
325
326
                return $key.'="'.$value.'"';
327 1
            })
328 1
            ->implode(' ');
329
330 1
        return '<img src="'.$url.'" '.$options.'>';
331
    }
332
333
    /**
334
     * Return the key -> value array for htmlable element.
335
     *
336
     * @return array
337
     */
338 1
    protected function getHtmlOptions()
339
    {
340 1
        return [];
341
    }
342
343
    /**
344
     * Ensures the model will have an url stored in attributes.
345
     *
346
     * @return void
347
     *
348
     * @throws \Lincable\Exceptions\LinkNotFoundException
349
     */
350 7
    protected function ensureHasUrl()
351
    {
352 7
        if ($this->getRawUrl() === null) {
0 ignored issues
show
introduced by
The condition $this->getRawUrl() === null is always false.
Loading history...
353
            // The preview image could not be found for model.
354
            throw new LinkNotFoundException(
355
                'Model ['.static::class.'] does not a file linked with.'
356
            );
357
        }
358 7
    }
359
}
360