Test Failed
Push — dev ( 03caf0...a74f67 )
by
unknown
05:10
created

Lincable::shouldOverwrite()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 0
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 2
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
     * Determine wheter the model already has a file linked and should to reuse the same url
27
     *
28
     * @return void
29
     */
30 21
    public function shouldOverwrite()
31
    {
32 21
        $overwrite = $this->overwriteExisting ?? config('lincable.overwriteExsting');
0 ignored issues
show
Bug Best Practice introduced by
The property overwriteExisting does not exist on Lincable\Eloquent\Lincable. Since you implemented __get, consider adding a @property annotation.
Loading history...
33 21
        return ($this->getRawUrl() && $overwrite);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getRawUrl() && $overwrite returns the type boolean which is incompatible with the documented return type void.
Loading history...
34
    }
35
36
    /**
37
     * Boots the trait.
38
     *
39
     * @return void
40
     */
41 31
    protected static function bootLincable()
42
    {
43
        static::deleted(function ($model) {
44 3
            if (! $model->shouldKeepMediaWhenDeleted()) {
45 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

45
                static::getMediaManager()->/** @scrutinizer ignore-call */ delete($model);
Loading history...
46
            }
47 31
        });
48 31
    }
49
50
    /**
51
     * Return the raw url saved on database.
52
     *
53
     * @return string
54
     *
55
     * @throws \Lincable\Exceptions\LinkNotFoundException
56
     */
57 26
    public function getRawUrl()
58
    {
59 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

59
        return $this->/** @scrutinizer ignore-call */ getAttributeFromArray($this->getUrlField());
Loading history...
60
    }
61
62
    /**
63
     * Return the full url media from model.
64
     *
65
     * @return void
66
     */
67 2
    public function getUrl()
68
    {
69 2
        return static::getMediaManager()->url($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::url(). ( Ignorable by Annotation )

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

69
        return static::getMediaManager()->url(/** @scrutinizer ignore-type */ $this);
Loading history...
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...
70
    }
71
72
    /**
73
     * Escope to easily create a fresh model from a FileRequest class.
74
     *
75
     * @param  mixed  $query
76
     * @param  \Lincable\Http\FileRequest  $fileRequest
77
     * @return mixed
78
     */
79 1
    public function scopeCreateWithFileRequest($query, FileRequest $fileRequest)
80
    {
81 1
        return tap(
82 1
            $query->newModelInstance($fileRequest->all()),
83
            function ($instance) use ($fileRequest) {
84 1
                $instance->perfomCreateWithFileRequest($fileRequest);
85 1
            }
86
        );
87
    }
88
89
    /**
90
     * Execute creation events and upload process for the file request.
91
     *
92
     * @param  \Lincable\Http\FileRequest  $request
93
     * @return void
94
     */
95 1
    public function perfomCreateWithFileRequest(FileRequest $request)
96
    {
97 1
        if ($request->getFile() === null) {
98
            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

98
            return $this->/** @scrutinizer ignore-call */ save();
Loading history...
99
        }
100
101 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

101
        if ($this->/** @scrutinizer ignore-call */ fireModelEvent('creating') === false) {
Loading history...
102
            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...
103
        }
104
105 1
        $silentEvents = $this->getSilentUploadEvents();
106
        
107 1
        \Event::fakeFor(
108
            function () use ($request) {
109
                // First we create the model on database, then we are allowed to proceed
110
                // sending the file to storage, no more breaks stops us from finishing,
111
                // unless upload failed.
112 1
                $this->save();
113 1
                $this->link($request);
114 1
            },
115
            array_map(function ($event) {
116 1
                return "eloquent.{$event}: ".static::class;
117 1
            }, $silentEvents)
118
        );
119
120 1
        $this->fireModelEvent('created');
121 1
    }
122
123
    /**
124
     * Link the model to a file.
125
     *
126
     * @param  mixed  $file
127
     * @return bool
128
     */
129 19
    public function link($file)
130
    {
131
        // Resolve the file object to link the model. It can
132
        // be a symfony uploaded file or a file request, which
133
        // is preferable for linking.
134 19
        $file = FileResolver::resolve($file);
135
        
136
        // Handle the file upload to the disk storage. All errors on upload are covered
137
        // for better handling upload events. Once the upload has been executed with
138
        // success, the model is auto updated, setting the url_field model configuration
139
        // with the path to the new file. On error, an event of failure is dispatched and
140
        // a HTTPException is also reported, if not covered will return a 409 HTTP status.
141 19
        $saved = static::getMediaManager()
142 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

142
            ->upload($file, /** @scrutinizer ignore-type */ $this, $this->getCustomUploadHeaders())
Loading history...
143 18
            ->save();
144
145
        // verifies whether it is necessary to update the updated_at field
146 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...
147 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

147
            return $this->/** @scrutinizer ignore-call */ touch();
Loading history...
148
        }
149
        return $saved;
150
    }
151
152
    /**
153
     * Execute a container callable with the file as argument.
154
     *
155
     * @param  mixed $callback
156
     * @return this
157
     */
158 3
    public function withMedia($callback)
159
    {
160 3
        $this->ensureHasUrl();
161
162
        // Get the current media manager of application.
163 3
        $mediaManager = static::getMediaManager();
164
165
        // Create a temporary file with the model file contents. Provide the
166
        // the default disk registered on media manager.
167 3
        $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

167
        $file = $mediaManager->get(/** @scrutinizer ignore-type */ $this);
Loading history...
168
169
        try {
170
            // Execute the callable with the temporary file. You also can receive the
171
            // model instance as second argument.
172 3
            Container::getInstance()->call($callback, [$file, $this]);
173
        } catch (\Exception $ex) {
174
            // Delete the temporary file wheter it exists.
175
            File::delete($file->path());
176
177
            // Throw exception again to show developer something bad happened.
178
            throw $ex;
179
        }
180
181 3
        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...
182
    }
183
184
    /**
185
     * Return the url field to link the model.
186
     *
187
     * @return string
188
     */
189 27
    public function getUrlField()
190
    {
191 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...
192 1
            ? $this->urlField
193 27
            : config('lincable.models.url_field');
194
    }
195
196
    /**
197
     * Return the name of the file.
198
     *
199
     * @return string
200
     */
201 5
    public function getFileName()
202
    {
203 5
        $this->ensureHasUrl();
204 5
        return FileFactory::fileName($this->getRawUrl());
205
    }
206
207
    /**
208
     * Return the file extension.
209
     *
210
     * @return string
211
     */
212 2
    public function getExtension()
213
    {
214 2
        return FileFactory::extension($this->getFileName());
215
    }
216
217
    /**
218
     * Fulfill the url on correct attribute name.
219
     *
220
     * @param  string  $url
221
     * @return void
222
     */
223 20
    public function fillUrl(string $url)
224
    {
225
        // Fill the url with unguarded permissions.
226
        static::unguarded(function () use ($url) {
227 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

227
            $this->/** @scrutinizer ignore-call */ 
228
                   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...
228 20
        });
229
230 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...
231
    }
232
233
    /**
234
     * Return the media manager instance.
235
     *
236
     * @return \Lincable\MediaManager
237
     */
238 19
    public static function getMediaManager()
239
    {
240 19
        if (static::$mediaManager === null) {
241
            static::$mediaManager = resolve(MediaManager::class);
242
        }
243
244 19
        return static::$mediaManager;
245
    }
246
    
247
    /**
248
     * Set the newly media manager.
249
     *
250
     * @param  \Lincable\MediaManager  $manager
251
     * @return void
252
     */
253 29
    public static function setMediaManager(MediaManager $manager)
254
    {
255 29
        static::$mediaManager = $manager;
256 29
    }
257
258
    /**
259
     * Determine wheter shoul keep the media for the model.
260
     *
261
     * @return bool
262
     */
263 3
    public function shouldKeepMediaWhenDeleted()
264
    {
265
        return (bool) (
266 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...
267 1
                ? $this->keepMediaOnDelete
268 3
                : config('lincable.keep_media_on_delete', false)
269
            );
270
    }
271
272
    /**
273
     * Returns the list of uploda headers for model.
274
     *
275
     * @return array
276
     */
277 19
    public function getCustomUploadHeaders()
278
    {
279
        return (array) (
280 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...
281
                ? $this->customUploadHeaders
282 19
                : config('lincable.upload_headers', [])
283
        );
284
    }
285
286
    /**
287
     * List of events to not be fired when creating the model
288
     * from a FileRequest. As the model is only considered really
289
     * created after file upload is ready, we only fire events after that.
290
     *
291
     * @return array
292
     */
293 1
    protected function getSilentUploadEvents()
294
    {
295
        return (array) (
296 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...
297 1
            config('lincable.models.silent_upload_events', [])
298
        );
299
    }
300
301
    /**
302
     * Forward getter call.
303
     *
304
     * @param  mixed  $key
305
     * @return mixed
306
     */
307 3
    public function __get($key)
308
    {
309 3
        if ($key === $this->getUrlField()) {
310
            // Let the model to use own resolution logic to create the link.
311 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

311
            if ($this->/** @scrutinizer ignore-call */ hasGetMutator($key)) {
Loading history...
312 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

312
                return $this->/** @scrutinizer ignore-call */ mutateAttribute($key, $this->getRawUrl());
Loading history...
313
            }
314
315 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...
316
        }
317
318
        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

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