Passed
Push — dev ( 6175a2...27f9c6 )
by Yan
06:16
created

Lincable::getSilentUploadEvents()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 5
ccs 3
cts 3
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
        return 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
135
    /**
136
     * Execute a container callable with the file as argument.
137
     *
138
     * @param  mixed $callback
139
     * @return this
140
     */
141 4
    public function withMedia($callback)
142
    {
143 4
        $this->ensureHasUrl();
144
145
        // Get the current media manager of application.
146 4
        $mediaManager = static::getMediaManager();
147
148
        // Create a temporary file with the model file contents. Provide the
149
        // the default disk registered on media manager.
150 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

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

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

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

295
                return $this->/** @scrutinizer ignore-call */ mutateAttribute($key, $this->getRawUrl());
Loading history...
296
            }
297
298 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...
299
        }
300
301
        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

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