Completed
Push — master ( 0bbd02...0f69a3 )
by Hamidreza
01:23
created

File::scopeFilter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
1
<?php
2
3
namespace Hamidrezaniazi\Upolo\Models;
4
5
use App\Filters\FileFilters;
6
use Hamidrezaniazi\Upolo\Contracts\HasFileInterface;
7
use Hamidrezaniazi\Upolo\Guard;
8
use Illuminate\Contracts\Auth\Authenticatable as User;
9
use Illuminate\Database\Eloquent\Builder;
10
use Illuminate\Database\Eloquent\Model;
11
use Illuminate\Database\Eloquent\Relations\BelongsTo;
12
use Illuminate\Database\Eloquent\Relations\MorphTo;
13
use Illuminate\Http\UploadedFile;
14
use Illuminate\Support\Str;
15
16
/**
17
 * Class File.
18
 *
19
 * @property int id
20
 * @property string uuid
21
 * @property string path
22
 * @property string disk
23
 * @property string filename
24
 * @property string type
25
 * @property string flag
26
 * @property string mime
27
 * @property HasFileInterface owner
28
 * @property User creator
29
 */
30
class File extends Model
31
{
32
    /**
33
     * @return BelongsTo
34
     */
35
    public function creator(): BelongsTo
36
    {
37
        return $this->belongsTo(Guard::getGuardClassName());
38
    }
39
40
    /**
41
     * @return MorphTo
42
     */
43
    public function owner(): MorphTo
44
    {
45
        return $this->morphTo();
46
    }
47
48
    /**
49
     * Apply all relevant thread filters.
50
     *
51
     * @param Builder $query
52
     * @param FileFilters $filters
53
     * @return Builder
54
     */
55
    public function scopeFilter(Builder $query, FileFilters $filters): Builder
56
    {
57
        return $filters->apply($query);
58
    }
59
60
    /**
61
     * @param Builder $query
62
     * @param HasFileInterface $owner
63
     * @return Builder
64
     */
65
    public function scopeWhereOwnerIs(Builder $query, HasFileInterface $owner): Builder
66
    {
67
        return $query->where('owner_type', $owner->getMorphClass())->where('owner_id', $owner->getKey());
0 ignored issues
show
Bug introduced by
The method getMorphClass() does not seem to exist on object<Hamidrezaniazi\Up...racts\HasFileInterface>.

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...
Bug introduced by
The method getKey() does not seem to exist on object<Hamidrezaniazi\Up...racts\HasFileInterface>.

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...
68
    }
69
70
    /**
71
     * @param Builder $query
72
     * @param int $ownerId
73
     * @return Builder
74
     */
75
    public function scopeWhereOwnerIdIs(Builder $query, int $ownerId): Builder
76
    {
77
        return $query->where('owner_id', $ownerId);
78
    }
79
80
    /**
81
     * @param Builder $query
82
     * @param string $ownerType
83
     * @return Builder
84
     */
85
    public function scopeWhereOwnerTypeIs(Builder $query, string $ownerType): Builder
86
    {
87
        return $query->where('owner_type', $ownerType);
88
    }
89
90
    /**
91
     * @param User $creator
92
     * @param UploadedFile $uploadedFile
93
     * @param HasFileInterface $owner
94
     * @param string $disk
95
     * @param string|null $type
96
     * @param string|null $flag
97
     * @return File
98
     */
99
    public function upload(
100
        User $creator,
101
        UploadedFile $uploadedFile,
102
        ?HasFileInterface $owner = null,
103
        ?string $disk = 'public',
104
        ?string $type = null,
105
        ?string $flag = null
106
    ): self {
107
        $uuid = Str::uuid();
108
        $path = sprintf('%s/%s', $creator->getKey(), $uuid);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Illuminate\Contracts\Auth\Authenticatable as the method getKey() does only exist in the following implementations of said interface: Illuminate\Foundation\Auth\User.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
109
        $path = $uploadedFile->store($path, $disk);
110
111
        $file = new self();
112
        $file->uuid = $uuid;
113
        $file->creator()->associate($creator);
0 ignored issues
show
Documentation introduced by
$creator is of type object<Illuminate\Contracts\Auth\Authenticatable>, but the function expects a object<Illuminate\Databa...t\Model>|integer|string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
114
        $file->owner()->associate($owner);
0 ignored issues
show
Documentation introduced by
$owner is of type object<Hamidrezaniazi\Up...\HasFileInterface>|null, but the function expects a object<Illuminate\Database\Eloquent\Model>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
115
        $file->filename = $uploadedFile->getClientOriginalName();
116
        $file->mime = $uploadedFile->getClientMimeType();
117
        $file->disk = $disk;
118
        $file->type = $type;
119
        $file->flag = $flag;
120
        $file->path = $path;
121
        $file->save();
122
123
        return $file;
124
    }
125
}
126