Passed
Push — dev ( 6b1ce9...6175a2 )
by Yan
05:04
created

Lincable::perfomCreateWithFileRequest()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 34
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 2.003

Importance

Changes 0
Metric Value
cc 2
eloc 19
nc 2
nop 1
dl 0
loc 34
ccs 10
cts 11
cp 0.9091
crap 2.003
rs 9.6333
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 ($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

86
        if ($this->/** @scrutinizer ignore-call */ fireModelEvent('creating') === false) {
Loading history...
87
            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...
88
        }
89
90
        // List of events to not be fired when creating the model
91
        // from a FileRequest. As the model is only considered really
92
        // created after file upload is ready, we only fire events after that.
93
        $fakeEvents = [
94 1
            'created',
95
            'creating',
96
            'updated',
97
            'updating',
98
            'saved',
99
            'saving',
100
            'deleted',
101
            'deleting'
102
        ];
103
104 1
        \Event::fakeFor(
105
            function () use ($request) {
106
                // First we create the model on database, then we are allowed to proceed 
107
                // sending the file to storage, no more breaks stops us from finishing, 
108
                // unless upload failed. 
109 1
                $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

109
                $this->/** @scrutinizer ignore-call */ 
110
                       save();
Loading history...
110 1
                $this->link($request);
111 1
            },
112
            array_map(function ($event) {
113 1
                return "eloquent.{$event}: ".static::class;
114 1
            }, $fakeEvents)
115
        );
116
117 1
        $this->fireModelEvent('created');
118 1
    }
119
120
    /**
121
     * Link the model to a file.
122
     *
123
     * @param  mixed  $file
124
     * @return bool
125
     */
126 19
    public function link($file)
127
    {
128
        // Resolve the file object to link the model. It can
129
        // be a symfony uploaded file or a file request, which
130
        // is preferable for linking.
131 19
        $file = FileResolver::resolve($file);
132
        
133
        // Handle the file upload to the disk storage. All errors on upload are covered
134
        // for better handling upload events. Once the upload has been executed with
135
        // success, the model is auto updated, setting the url_field model configuration
136
        // with the path to the new file. On error, an event of failure is dispatched and
137
        // a HTTPException is also reported, if not covered will return a 409 HTTP status.
138 19
        return static::getMediaManager()
139 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

139
            ->upload($file, /** @scrutinizer ignore-type */ $this, $this->getCustomUploadHeaders())
Loading history...
140 18
            ->save();  
141
    }
142
143
    /**
144
     * Execute a container callable with the file as argument.
145
     *
146
     * @param  mixed $callback
147
     * @return this
148
     */
149 4
    public function withMedia($callback)
150
    {
151 4
        $this->ensureHasUrl();
152
153
        // Get the current media manager of application.
154 4
        $mediaManager = static::getMediaManager();
155
156
        // Create a temporary file with the model file contents. Provide the
157
        // the default disk registered on media manager.
158 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

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

218
            $this->/** @scrutinizer ignore-call */ 
219
                   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...
219 20
        });
220
221 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...
222
    }
223
224
    /**
225
     * Return the media manager instance.
226
     *
227
     * @return \Lincable\MediaManager 
228
     */
229 19
    public static function getMediaManager()
230
    {
231 19
        if (static::$mediaManager === null) {
232
            static::$mediaManager = resolve(MediaManager::class);
233
        }
234
235 19
        return static::$mediaManager;
236
    }
237
    
238
    /**
239
     * Set the newly media manager.
240
     *
241
     * @param  \Lincable\MediaManager  $manager
242
     * @return void 
243
     */
244 29
    public static function setMediaManager(MediaManager $manager)
245
    {
246 29
        static::$mediaManager = $manager;
247 29
    }
248
249
    /**
250
     * Determine wheter shoul keep the media for the model.
251
     * 
252
     * @return bool
253
     */
254 3
    public function shouldKeepMediaWhenDeleted()
255
    {        
256
        return (bool) (
257 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...
258 1
                ? $this->keepMediaOnDelete 
259 3
                : config('lincable.keep_media_on_delete', false)
260
            );
261
    }
262
263
    /**
264
     * Returns the list of uploda headers for model.
265
     *
266
     * @return array
267
     */
268 19
    public function getCustomUploadHeaders()
269
    {
270
        return (array) (
271 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...
272
                ? $this->customUploadHeaders
273 19
                : config('lincable.upload_headers', [])
274
        );
275
    }
276
277
    /**
278
     * Forward getter call.
279
     *
280
     * @param  mixed  $key
281
     * @return mixed
282
     */
283 3
    public function __get($key)
284
    {
285 3
        if ($key === $this->getUrlField()) {
286
            // Let the model to use own resolution logic to create the link.
287 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

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

288
                return $this->/** @scrutinizer ignore-call */ mutateAttribute($key, $this->getRawUrl());
Loading history...
289
            }
290
291 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...
292
        }
293
294
        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

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