Test Failed
Push — master ( 6b0f8d...930d65 )
by Kanstantsin
05:49
created

Alias::getAssetPath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 2
dl 0
loc 7
ccs 0
cts 3
cp 0
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace tkanstantsin\fileupload\config;
5
6
use tkanstantsin\fileupload\model\IFile;
7
use tkanstantsin\fileupload\model\Type;
8
9
/**
10
 * Class Alias represent config for model
11
 * @todo: add `accept` type.
12
 */
13
class Alias
14
{
15
    public const DEFAULT_MAX_SIZE = 5 * 1000 * 1000; // 5 MB
16
    public const DEFAULT_MAX_COUNT = 5;
17
    public const DEFAULT_HASH_LENGTH = 3;
18
    /**
19
     * @see hash_algos()
20
     */
21
    public const DEFAULT_HASH_METHOD = 'crc32'; // not crypto-strong, but fast (as needed)
22
23
    /**
24
     * Alias name
25
     * @var string
26
     */
27
    public $name;
28
29
    /**
30
     * Owner model class
31
     * @var string
32
     */
33
    public $class;
34
    /**
35
     * @var string
36
     */
37
    public $directory;
38
39
    /**
40
     * Max file size in bytes
41
     * @var int
42
     */
43
    public $maxSize;
44
    /**
45
     * Max file count
46
     * @var int
47
     */
48
    public $maxCount;
49
    /**
50
     * Whether it is allowed multiple files for one model
51
     * @var bool
52
     */
53
    public $multiple;
54
55
    /**
56
     * Hash method like crc32 or md5
57
     * @var string
58
     */
59
    public $hashMethod;
60
    /**
61
     * Length of hash generated by hash method
62
     * @var int
63
     */
64
    public $cacheHashLength;
65
66
    /**
67
     * @var callable
68
     */
69
    public $filePathClosure;
70
    /**
71
     * @var callable
72
     */
73
    public $assetNameClosure;
74
75
76
    /**
77
     * Alias constructor.
78
     * @param array $config
79
     * @throws InvalidConfigException
80
     */
81 1
    public function __construct(array $config = [])
82
    {
83 1
        foreach ($config as $key => $value) {
84 1
            $this->$key = $value;
85
        }
86
87 1
        if (preg_match('/^[a-z0-9-_]$/i', $this->name)) {
88
            throw new InvalidConfigException(sprintf('Alias name must contain only latin letters, digits, hyphen (-) and underscore. `%s` got.', $this->name));
89
        }
90 1
        if (!\is_int($this->maxSize) || $this->maxSize <= 0) {
91
            throw new InvalidConfigException(sprintf('Maximum file size must be positive integer but `%s` got.', $this->maxSize));
92
        }
93 1
        if (!\is_int($this->maxCount) || $this->maxCount <= 0) {
94
            throw new InvalidConfigException(sprintf('Maximum file count must be positive integer but `%s` got.', $this->maxCount));
95
        }
96
        if (!\in_array($this->hashMethod, hash_algos(), true)) {
97
            throw new InvalidConfigException(sprintf('Hash method `%s` not found.', $this->hashMethod));
98 1
        }
99
        // TODO: create interface with all such methods.
100
        // Implement base version. And allow to use custom realizations.
101 1
        if ($this->filePathClosure !== null && !\is_callable($this->filePathClosure)) {
102
            throw new InvalidConfigException('FilePathClosure must be callable.');
103
        }
104 1
        if ($this->assetNameClosure !== null && !\is_callable($this->assetNameClosure)) {
105
            throw new InvalidConfigException('AssetNameClosure must be callable.');
106
        }
107
    }
108
109
    /**
110
     * Returns file path in contentFS
111 1
     * @param IFile $file
112
     * @return string|null
113 1
     */
114
    public function getFilePath(IFile $file): ?string
115
    {
116
        if ($this->filePathClosure !== null) {
117 1
            return \call_user_func($this->filePathClosure, $file);
118 1
        }
119 1
120
        return $file->getId() !== null
121
            ? $this->getFileDirectory($file) . DIRECTORY_SEPARATOR . $this->getFileName($file)
122
            : null;
123
    }
124
125
    /**
126
     * Returns path for caching files.
127
     *
128
     * @param IFile  $file
129
     * @param string $formatName
130
     *
131
     * @return string
132
     */
133
    public function getAssetPath(IFile $file, string $formatName): string
134
    {
135
        return implode('/', array_filter([
136
            Type::$folderPrefix[$file->getType()] . '_' . $formatName,
137
            $file->getModelAlias(),
138
            mb_substr($file->getHash(), 0, $this->cacheHashLength),
139
            $this->getAssetName($file),
140
        ]));
141
    }
142
143
    /**
144
     * @param IFile $file
145
     * @return string
146
     */
147
    public function getAssetName(IFile $file): string
148
    {
149
        if ($this->assetNameClosure !== null) {
150
            return \call_user_func($this->assetNameClosure, $file);
151
        }
152
153
        return $file->getId() . '_' . $file->getFullName();
154
    }
155
156 1
    /**
157
     * @param IFile $file
158 1
     * @return string
159
     */
160
    public function getFileName(IFile $file): string
161
    {
162
        return $file->getId() . ($file->getExtension() !== null ? '.' . $file->getExtension() : '');
163
    }
164
165
    /**
166 1
     * Returns target directory for uploaded file
167
     * @param IFile $file
168 1
     * @return string
169 1
     */
170
    public function getFileDirectory(IFile $file): string
171
    {
172 1
        return implode(DIRECTORY_SEPARATOR, array_filter([
173
            $this->directory,
174
            // TODO: check if used correct hash.
175
            // Which value should be passed into getDirectoryHash? Directory name or file id?
176
            $this->getDirectoryHash((string) $file->getId()),
177
        ]));
178
    }
179
180 1
    /**
181
     * @param string $value E.g. directory name
182 1
     * @return string
183 1
     */
184 1
    protected function getDirectoryHash(string $value): ?string
185
    {
186
        return $this->cacheHashLength > 0
187
            ? mb_substr(hash($this->hashMethod, $value), 0, $this->cacheHashLength)
188
            : null;
189
    }
190
}