Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
45.71% covered (danger)
45.71%
16 / 35
22.22% covered (danger)
22.22%
2 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
FileUri
45.71% covered (danger)
45.71%
16 / 35
22.22% covered (danger)
22.22%
2 / 9
40.04
0.00% covered (danger)
0.00%
0 / 1
 toFile
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
20
 getStream
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 moveTo
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSize
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getError
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getClientFilename
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getClientMediaType
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 createRandom
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 createSchema
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2namespace Apie\Core\ValueObjects;
3
4use Apie\Core\Attributes\Description;
5use Apie\Core\Attributes\ExampleValue;
6use Apie\Core\Attributes\FakeMethod;
7use Apie\Core\Attributes\SchemaMethod;
8use Apie\Core\FileStorage\StoredFile;
9use Faker\Generator;
10use Psr\Http\Message\StreamInterface;
11use Psr\Http\Message\UploadedFileInterface;
12use ReflectionClass;
13use ReflectionProperty;
14
15/**
16 * @phpstan-ignore apie.conflicting.interface
17 */
18#[Description('URL to download file')]
19#[FakeMethod('createRandom')]
20#[SchemaMethod('createSchema')]
21#[ExampleValue('https://example.com/file.pdf', 'A URL pointing to a file')]
22class FileUri extends Uri implements UploadedFileInterface
23{
24    private StoredFile $loadedFile;
25
26    final protected function toFile(): UploadedFileInterface
27    {
28        if (!isset($this->loadedFile)) {
29            $contentType = null;
30            if (class_exists('GuzzleHttp\Client')) {
31                $client = new \GuzzleHttp\Client(['connect_timeout' => 10, 'timeout' => 10]);
32                try {
33                    $response = $client->request('HEAD', $this->toNative());
34                    $contentType = $response->getHeaderLine('Content-Type');
35                    // Use $contentType as needed
36                } catch (\Exception $e) {
37                    // Fallback to existing logic
38                }
39            }
40            $context = stream_context_create([
41                'http' => ['timeout' => 10],
42            ]);
43            $stream = fopen($this->toNative(), 'rb', false, $context);
44            $this->loadedFile = StoredFile::createFromResource($stream, clientMimeType: $contentType);
45        }
46        
47        return $this->loadedFile;
48    }
49
50    public function getStream(): StreamInterface
51    {
52        return $this->toFile()->getStream();
53    }
54
55    public function moveTo($targetPath): void
56    {
57        $this->toFile()->moveTo($targetPath);
58    }
59
60    public function getSize(): ?int
61    {
62        return $this->toFile()->getSize();
63    }
64
65    public function getError(): int
66    {
67        return $this->toFile()->getError();
68    }
69
70    public function getClientFilename(): ?string
71    {
72        return $this->toFile()->getClientFilename();
73    }
74
75    public function getClientMediaType(): ?string
76    {
77        return $this->toFile()->getClientMediaType();
78    }
79
80    public static function createRandom(Generator $faker): Uri
81    {
82        $refl = new ReflectionClass(static::class);
83        $instance = $refl->newInstanceWithoutConstructor();
84        $prop = new ReflectionProperty(Uri::class, 'internal');
85        $prop->setValue($instance, $faker->url());
86        $instance->loadedFile = $faker->fakeClass(StoredFile::class);
87        return $instance;
88    }
89
90    /**
91     * @return array<string, string|null>
92     */
93    public static function createSchema(): array
94    {
95        $attr = new ReflectionClass(static::class);
96        $description = null;
97        foreach ($attr->getAttributes(Description::class) as $descriptionAttr) {
98            $descriptionInstance = $descriptionAttr->newInstance();
99            $description = $descriptionInstance->description;
100        }
101        return [
102            'type' => 'string',
103            'format' => 'fileuri',
104            'description' => $description,
105        ];
106    }
107}