Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
45.45% covered (danger)
45.45%
20 / 44
66.67% covered (warning)
66.67%
12 / 18
CRAP
0.00% covered (danger)
0.00%
0 / 1
Files
45.45% covered (danger)
45.45%
20 / 44
66.67% covered (warning)
66.67%
12 / 18
221.60
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __toString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 rewind
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 current
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 key
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 count
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 next
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 valid
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 first
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 unwrap
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 json
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isset
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 len
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 files
50.00% covered (danger)
50.00%
7 / 14
0.00% covered (danger)
0.00%
0 / 1
19.12
 fileItem
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 effectiveFiles
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
20
 hasFile
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2
3declare(strict_types=1);
4
5namespace Cosray\Value;
6
7use Cosray\Field\Capability\Translatable;
8use Cosray\Field\Field;
9use Cosray\Field\Owner;
10use Cosray\Schema\TranslateMode;
11use Iterator;
12
13class Files extends Value implements Iterator
14{
15    protected int $pointer = 0;
16
17    public function __construct(
18        Owner $owner,
19        Field&Translatable $field,
20        ValueContext $context,
21        protected int $index = 0,
22    ) {
23        parent::__construct($owner, $field, $context);
24    }
25
26    public function __toString(): string
27    {
28        return 'Files: count(' . count($this->unwrap()) . ')';
29    }
30
31    public function rewind(): void
32    {
33        $this->pointer = 0;
34    }
35
36    public function current(): File
37    {
38        return $this->get($this->pointer);
39    }
40
41    public function key(): int
42    {
43        return $this->pointer;
44    }
45
46    public function count(): int
47    {
48        return count($this->files());
49    }
50
51    public function next(): void
52    {
53        $this->pointer++;
54    }
55
56    public function valid(): bool
57    {
58        return $this->fileItem($this->pointer) !== null;
59    }
60
61    public function get(int $index): File
62    {
63        return new File($this->owner, $this->field, $this->context, $index);
64    }
65
66    public function first(): File
67    {
68        return new File($this->owner, $this->field, $this->context, 0);
69    }
70
71    public function unwrap(): array
72    {
73        return $this->files();
74    }
75
76    public function json(): mixed
77    {
78        return $this->unwrap();
79    }
80
81    public function isset(): bool
82    {
83        return $this->fileItem(0) !== null;
84    }
85
86    protected function len(): int
87    {
88        return count($this->files());
89    }
90
91    protected function files(): array
92    {
93        $value = $this->data['value'] ?? [];
94
95        if (
96            !isset($this->data['type'])
97            && isset($this->data['files'])
98            && is_array($this->data['files'])
99        ) {
100            if (
101                $this->field->translateMode() === TranslateMode::Asymmetric
102                && !array_is_list($this->data['files'])
103            ) {
104                return $this->effectiveFiles($this->data['files']);
105            }
106
107            return $this->data['files'];
108        }
109
110        if (!is_array($value)) {
111            return [];
112        }
113
114        if ($this->field->translateMode() === TranslateMode::Asymmetric) {
115            return $this->effectiveFiles($value);
116        }
117
118        $files = $value[Field::NEUTRAL_LOCALE] ?? [];
119
120        return is_array($files) ? $files : [];
121    }
122
123    protected function fileItem(int $index): ?array
124    {
125        $item = $this->files()[$index] ?? null;
126
127        return is_array($item) ? $item : null;
128    }
129
130    /** @param array<string, mixed> $map */
131    protected function effectiveFiles(array $map): array
132    {
133        $locale = $this->locale;
134
135        while ($locale) {
136            $files = $map[$locale->id] ?? null;
137
138            if ($this->hasFile($files)) {
139                return $files;
140            }
141
142            $locale = $locale->fallback();
143        }
144
145        $files = $map[Field::NEUTRAL_LOCALE] ?? null;
146
147        return $this->hasFile($files) ? $files : [];
148    }
149
150    protected function hasFile(mixed $files): bool
151    {
152        if (!is_array($files)) {
153            return false;
154        }
155
156        foreach ($files as $file) {
157            if (is_array($file) && ($file['file'] ?? null)) {
158                return true;
159            }
160        }
161
162        return false;
163    }
164}