• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

valkyrjaio / valkyrja / 15659546660

15 Jun 2025 04:39AM UTC coverage: 47.202% (-0.4%) from 47.589%
15659546660

push

github

MelechMizrachi
Update Config.

5331 of 11294 relevant lines covered (47.2%)

16.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.08
/src/Valkyrja/Http/Message/Factory/UploadedFileFactory.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of the Valkyrja Framework package.
7
 *
8
 * (c) Melech Mizrachi <melechmizrachi@gmail.com>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13

14
namespace Valkyrja\Http\Message\Factory;
15

16
use Psr\Http\Message\UploadedFileInterface;
17
use Valkyrja\Http\Message\Exception\InvalidArgumentException;
18
use Valkyrja\Http\Message\File\Contract\UploadedFile;
19
use Valkyrja\Http\Message\File\Enum\UploadError;
20
use Valkyrja\Http\Message\File\UploadedFile as HttpUploadedFile;
21

22
use function array_keys;
23
use function array_map;
24
use function is_array;
25
use function is_string;
26

27
/**
28
 * Abstract Class UploadedFileFactory.
29
 *
30
 * @author Melech Mizrachi
31
 */
32
abstract class UploadedFileFactory
33
{
34
    /**
35
     * Normalize uploaded files.
36
     * Transforms each value into an UploadedFile instance, and ensures
37
     * that nested arrays are normalized.
38
     *
39
     * @param array<array-key, mixed> $files The files
40
     *
41
     * @throws InvalidArgumentException for unrecognized values
42
     *
43
     * @return array<array-key, mixed>
44
     */
45
    public static function normalizeFiles(array $files): array
46
    {
47
        $normalized = [];
14✔
48

49
        foreach ($files as $key => $value) {
14✔
50
            if ($value instanceof UploadedFile) {
14✔
51
                $normalized[$key] = $value;
4✔
52

53
                continue;
4✔
54
            }
55

56
            if (is_array($value) && isset($value['tmp_name'])) {
12✔
57
                $normalized[$key] = self::createUploadedFileFromSpec($value);
8✔
58

59
                continue;
8✔
60
            }
61

62
            if (is_array($value)) {
4✔
63
                $normalized[$key] = self::normalizeFiles($value);
4✔
64

65
                continue;
2✔
66
            }
67

68
            throw new InvalidArgumentException('Invalid value in files specification');
2✔
69
        }
70

71
        return $normalized;
12✔
72
    }
73

74
    public static function fromPsr(UploadedFileInterface $file): UploadedFile
75
    {
76
        return new HttpUploadedFile(
8✔
77
            stream: StreamFactory::fromPsr($file->getStream()),
8✔
78
            uploadError: UploadError::from($file->getError()),
8✔
79
            size: (int) $file->getSize(),
8✔
80
            fileName: $file->getClientFilename(),
8✔
81
            mediaType: $file->getClientMediaType(),
8✔
82
        );
8✔
83
    }
84

85
    /**
86
     * @param UploadedFileInterface ...$files
87
     *
88
     * @return UploadedFile[]
89
     */
90
    public static function fromPsrArray(UploadedFileInterface ...$files): array
91
    {
92
        return array_map(
8✔
93
            static fn (UploadedFileInterface $file): UploadedFile => UploadedFileFactory::fromPsr($file),
8✔
94
            $files,
8✔
95
        );
8✔
96
    }
97

98
    /**
99
     * Create and return an UploadedFile instance from a $_FILES specification.
100
     * If the specification represents an array of values, this method will
101
     * delegate to normalizeNestedFileSpec() and return that return value.
102
     *
103
     * @param array<array-key, mixed> $value $_FILES struct
104
     *
105
     * @throws InvalidArgumentException
106
     *
107
     * @return UploadedFile|UploadedFile[]
108
     */
109
    private static function createUploadedFileFromSpec(array $value): UploadedFile|array
110
    {
111
        $tmpName = $value['tmp_name'] ?? null;
8✔
112

113
        if (is_array($tmpName)) {
8✔
114
            return self::normalizeNestedFileSpec($value);
6✔
115
        }
116

117
        if (! is_string($tmpName)) {
8✔
118
            throw new InvalidArgumentException('Temp file name expected to be a string');
×
119
        }
120

121
        return new HttpUploadedFile(
8✔
122
            $tmpName,
8✔
123
            null,
8✔
124
            UploadError::from((int) $value['error']),
8✔
125
            (int) $value['size'],
8✔
126
            (string) $value['name'],
8✔
127
            (string) $value['type']
8✔
128
        );
8✔
129
    }
130

131
    /**
132
     * Normalize an array of file specifications.
133
     * Loops through all nested files and returns a normalized array of
134
     * UploadedFileInterface instances.
135
     *
136
     * @param array<array-key, mixed> $files
137
     *
138
     * @throws InvalidArgumentException
139
     *
140
     * @return UploadedFile[]
141
     *
142
     * @psalm-suppress InvalidReturnType Cannot do recursive return type
143
     * @psalm-suppress InvalidReturnStatement Cannot do recursive return type
144
     * @psalm-suppress MixedArrayAccess tmp_name should exist
145
     */
146
    private static function normalizeNestedFileSpec(array $files = []): array
147
    {
148
        $normalizedFiles = [];
6✔
149
        $filesTmpName    = $files['tmp_name'];
6✔
150

151
        if (! is_array($filesTmpName)) {
6✔
152
            throw new InvalidArgumentException('Expecting tmp name to be a nested array of files');
×
153
        }
154

155
        foreach (array_keys($filesTmpName) as $key) {
6✔
156
            $spec                  = [
6✔
157
                'tmp_name' => $files['tmp_name'][$key] ?? '',
6✔
158
                'size'     => $files['size'][$key] ?? 0,
6✔
159
                'error'    => $files['error'][$key] ?? 0,
6✔
160
                'name'     => $files['name'][$key] ?? null,
6✔
161
                'type'     => $files['type'][$key] ?? null,
6✔
162
            ];
6✔
163
            $normalizedFiles[$key] = self::createUploadedFileFromSpec($spec);
6✔
164
        }
165

166
        return $normalizedFiles;
6✔
167
    }
168
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc