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

diego-ninja / granite / 16608963009

29 Jul 2025 10:37PM UTC coverage: 50.423%. First build
16608963009

Pull #5

github

web-flow
Merge 43d8840d7 into 6a6caca51
Pull Request #5: code: adds phpstan level max, pint with per and github actions

321 of 632 new or added lines in 77 files covered. (50.79%)

1132 of 2245 relevant lines covered (50.42%)

9.88 hits per line

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

0.0
/src/Mapping/Transformers/CollectionTransformer.php
1
<?php
2

3
namespace Ninja\Granite\Mapping\Transformers;
4

5
use Ninja\Granite\Mapping\Contracts\Mapper;
6
use Ninja\Granite\Mapping\Contracts\Transformer;
7
use RuntimeException;
8

9
final class CollectionTransformer implements Transformer
10
{
11
    /**
12
     * @param class-string $destinationType Target item type for collection elements
13
     * @param Mapper|null $mapper ObjectMapper instance
14
     * @param bool $preserveKeys Whether to preserve array keys
15
     * @param bool $recursive Whether to recursively transform nested collections
16
     * @param mixed $itemTransformer Optional transformer for individual items
17
     */
18
    public function __construct(
×
19
        private readonly string $destinationType,
20
        private ?Mapper $mapper = null,
21
        private readonly bool   $preserveKeys = false,
22
        private readonly bool   $recursive = false,
23
        private readonly mixed $itemTransformer = null,
24
    ) {}
×
25

26
    public function setMapper(Mapper $mapper): self
×
27
    {
28
        $this->mapper = $mapper;
×
29
        return $this;
×
30
    }
31

32
    /**
33
     * Transform a collection.
34
     */
35
    public function transform(mixed $value, array $sourceData = []): mixed
×
36
    {
NEW
37
        if (null === $value) {
×
38
            return null;
×
39
        }
40

NEW
41
        if ( ! is_array($value)) {
×
42
            return $value; // Return as is if not an array
×
43
        }
44

45
        $result = [];
×
46

47
        foreach ($value as $key => $item) {
×
48
            $transformedItem = $this->transformItem($item);
×
49

50
            if ($this->preserveKeys) {
×
51
                $result[$key] = $transformedItem;
×
52
            } else {
53
                $result[] = $transformedItem;
×
54
            }
55
        }
56

57
        return $result;
×
58
    }
59

60
    /**
61
     * Transform a single collection item.
62
     */
63
    private function transformItem(mixed $item): mixed
×
64
    {
65
        // Apply item transformer if provided
NEW
66
        if (null !== $this->itemTransformer) {
×
67
            if (is_callable($this->itemTransformer)) {
×
68
                return ($this->itemTransformer)($item);
×
69
            }
70
            if ($this->itemTransformer instanceof Transformer) {
×
71
                return $this->itemTransformer->transform($item);
×
72
            }
73
        }
74

75
        // Handle recursive transformation for nested arrays
76
        if (is_array($item) && $this->recursive) {
×
77
            // If the item is a simple associative array, map it
78
            if ($this->isAssociativeArray($item)) {
×
NEW
79
                if (null === $this->mapper) {
×
NEW
80
                    throw new RuntimeException('Mapper is required for object mapping');
×
81
                }
82
                return $this->mapper->map($item, $this->destinationType);
×
83
            }
84

85
            // If it's a collection itself, recursively transform each item
86
            $nestedResult = [];
×
87
            foreach ($item as $nestedKey => $nestedItem) {
×
88
                $transformedNestedItem = $this->transformItem($nestedItem);
×
89
                if ($this->preserveKeys) {
×
90
                    $nestedResult[$nestedKey] = $transformedNestedItem;
×
91
                } else {
92
                    $nestedResult[] = $transformedNestedItem;
×
93
                }
94
            }
95
            return $nestedResult;
×
96
        }
97

98
        // Standard mapping for non-collection items
99
        if (is_array($item) || is_object($item)) {
×
NEW
100
            if (null === $this->mapper) {
×
NEW
101
                throw new RuntimeException('Mapper is required for object mapping');
×
102
            }
103
            return $this->mapper->map($item, $this->destinationType);
×
104
        }
105

106
        return $item;
×
107
    }
108

109
    /**
110
     * Check if an array is associative (vs sequential).
111
     */
112
    private function isAssociativeArray(array $array): bool
×
113
    {
114
        // An empty array is considered associative for our purposes
115
        if (empty($array)) {
×
116
            return true;
×
117
        }
118

119
        // Check if array keys are sequential integers starting from 0
120
        return array_keys($array) !== range(0, count($array) - 1);
×
121
    }
122
}
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