Test Setup Failed
Push — master ( 51dfb8...86fe89 )
by Ben
28:20 queued 08:12
created

AbstractMediaFieldHandler::getDisk()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Thinktomorrow\Chief\Media\Application;
6
7
use Illuminate\Support\Str;
8
use Illuminate\Http\Request;
9
use Thinktomorrow\AssetLibrary\Asset;
10
use Thinktomorrow\AssetLibrary\HasAsset;
11
use Thinktomorrow\Chief\Fields\Types\MediaField;
12
use Thinktomorrow\AssetLibrary\Application\AddAsset;
13
use Thinktomorrow\Chief\Media\DuplicateAssetException;
14
use Thinktomorrow\AssetLibrary\Application\DetachAsset;
15
use Thinktomorrow\AssetLibrary\Application\ReplaceAsset;
16
use Thinktomorrow\AssetLibrary\Application\AssetUploader;
17
use Thinktomorrow\AssetLibrary\Application\SortAssets;
18
19
abstract class AbstractMediaFieldHandler
20
{
21
    use ChecksExistingAssets;
22
23
    /** @var ReplaceAsset */
24
    protected $replaceAsset;
25
26
    /** @var AddAsset */
27
    protected $addAsset;
28
29
    /** @var DetachAsset */
30
    protected $detachAsset;
31
32
    /** @var AssetUploader */
33
    protected $assetUploader;
34
35
    /** @var SortAssets */
36
    protected $sortAssets;
37
38
    /** @var string the media disk where the files should be stored. */
39
    private $disk = '';
40
41
    final public function __construct(AddAsset $addAsset, ReplaceAsset $replaceAsset, DetachAsset $detachAsset, SortAssets $sortAssets, AssetUploader $assetUploader)
42
    {
43
        $this->replaceAsset = $replaceAsset;
44
        $this->addAsset = $addAsset;
45
        $this->detachAsset = $detachAsset;
46
        $this->sortAssets = $sortAssets;
47
        $this->assetUploader = $assetUploader;
48
    }
49
50
    protected function getCollection(): string
51
    {
52
        // Default collection for the media records. - for the time being this is not used in favor of the Asset types.
53
        return 'default';
54
    }
55
56
    protected function setDisk(string $disk): void
57
    {
58
        $this->disk = $disk;
59
    }
60
61
    protected function getDisk(): string
62
    {
63
        return $this->disk;
64
    }
65
66
    protected function handlePayload(HasAsset $model, MediaField $field, string $locale, $values)
67
    {
68
        foreach ($values as $key => $value) {
69
            $keyIsAttachedAssetId = $this->isKeyAnAttachedAssetId($model->assetRelation, $locale, $field->getKey(), $key);
0 ignored issues
show
Bug introduced by
Accessing assetRelation on the interface Thinktomorrow\AssetLibrary\HasAsset suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
70
71
            if ($this->shouldNotBeProcessed($value, $key, $keyIsAttachedAssetId)) {
72
                continue;
73
            }
74
75
            /*
76
             * when value is null, it means that the asset is queued for detachment
77
             * if key isn't an attached asset reference, we ignore it because this
78
             * means that a newly uploaded asset was deleted in the same request
79
             */
80
            if (is_null($value)) {
81
                if ($keyIsAttachedAssetId) {
82
                    $this->detach($model, $locale, $field->getKey(), $key);
83
                }
84
85
                continue;
86
            }
87
88
            // If key refers to an already existing asset, it is queued for replacement by a new one
89
            if ($keyIsAttachedAssetId) {
90
                $this->replace($model, $locale, $field->getKey(), $key, $value);
91
                continue;
92
            }
93
94
            $this->new($model, $locale, $field->getKey(), $value);
95
        }
96
    }
97
98
    abstract protected function new(HasAsset $model, string $locale, string $type, $value): Asset;
99
100
    protected function replace(HasAsset $model, string $locale, string $type, $currentAssetId, $value): Asset
101
    {
102
        $asset = $this->looksLikeAnAssetId($value)
103
            ? Asset::find($value)
104
            : $this->createNewAsset($model, $locale, $type, $value);
105
106
        $this->replaceAsset->handle($model, $currentAssetId, $asset->id, $type, $locale);
107
108
        return $asset;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $asset could return the type null which is incompatible with the type-hinted return Thinktomorrow\AssetLibrary\Asset. Consider adding an additional type-check to rule them out.
Loading history...
109
    }
110
111
    protected function detach(HasAsset $model, string $locale, string $type, $assetId)
112
    {
113
        $this->detachAsset->detach($model, $assetId, $type, $locale);
114
    }
115
116
    abstract protected function createNewAsset(HasAsset $model, string $locale, string $type, $value): Asset;
117
118
    protected function shouldNotBeProcessed($value, $key, bool $keyIsAttachedAssetId): bool
119
    {
120
        // If the async upload is not finished yet and the user already uploads, the slim passes an "undefined" as value.
121
        if ($value === "undefined") {
122
            return true;
123
        }
124
125
        // Passed id => id that are the same, refer to an already attached asset so skip this.
126
        if ($key == $value && $keyIsAttachedAssetId) {
127
            return true;
128
        }
129
130
        return false;
131
    }
132
133
    /**
134
     * @param HasAsset $model
135
     * @param string $locale
136
     * @param string $type
137
     * @param $assetId
138
     * @return Asset
139
     * @throws DuplicateAssetException
140
     * @throws \Spatie\MediaLibrary\Exceptions\FileCannotBeAdded
141
     */
142
    protected function newExistingAsset(HasAsset $model, string $locale, string $type, $assetId): Asset
143
    {
144
        $existingAsset = Asset::find($assetId);
145
146
        if ($model->assetRelation()->where('asset_pivots.type', $type)->where('asset_pivots.locale', $locale)->get()->contains($existingAsset)) {
147
            throw new DuplicateAssetException();
148
        }
149
150
        return $this->addAsset->add($model, $existingAsset, $type, $locale, null, $this->getCollection(), $this->getDisk());
151
    }
152
153
    /**
154
     * @param string $filename
155
     * @return string
156
     */
157
    protected function sluggifyFilename(string $filename): string
158
    {
159
        if (false === strpos($filename, '.')) {
160
            return $filename;
161
        }
162
163
        $extension = substr($filename, strrpos($filename, '.') + 1);
164
        $filename = substr($filename, 0, strrpos($filename, '.'));
165
166
        return Str::slug($filename) . '.' . $extension;
167
    }
168
169
    protected function sort(HasAsset $model, MediaField $field, Request $request)
170
    {
171
        if ($request->has('filesOrder')) {
172
            foreach ($request->input('filesOrder') as $locale => $fileIdInput) {
173
                $fileIds = $this->getFileIdsFromInput($field->getKey(), $fileIdInput);
174
175
                if (!empty($fileIds)) {
176
                    $this->sortAssets->handle($model, $fileIds, $field->getKey(), $locale);
177
                }
178
            }
179
        }
180
    }
181
182
    /**
183
     * @param string $key
184
     * @param array $fileIdInput
185
     * @return array
186
     */
187
    private function getFileIdsFromInput(string $key, array $fileIdInput): array
188
    {
189
        $values = isset($fileIdInput[$key])
190
            ? $fileIdInput[$key]
191
            : (
192
                isset($fileIdInput['files-' . $key])
193
                ? $fileIdInput['files-' . $key]
194
                : ''
195
            );
196
197
        if (!$values) {
198
            return [];
199
        }
200
201
        return explode(',', $values);
202
    }
203
}
204