Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
65 / 65
100.00% covered (success)
100.00%
7 / 7
CRAP
100.00% covered (success)
100.00%
1 / 1
ModuleDefinitionDto
100.00% covered (success)
100.00%
64 / 64
100.00% covered (success)
100.00%
7 / 7
19
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 fromArray
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
3
 parseSections
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
4
 parseFields
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 parseFilters
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
4
 parseRelations
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 toArray
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5/** @license For full copyright and license information, please see the LICENSE.md file. */
6
7namespace App\Core\ModuleBuilder\Domain\Model;
8
9defined('AMMONLY_APP') || exit('Direct script access is forbidden.');
10
11/**
12 * Composite Module Definition DTO.
13 *
14 * Aggregates complete module configuration: basic info, sections, fields,
15 * filters, and relations for atomic creation or updates.
16 *
17 * @package App\Core\ModuleBuilder\Domain\Model
18 */
19final readonly class ModuleDefinitionDto
20{
21    /**
22     * @param ModuleBasicInfoDto     $basicInfo Module essentials.
23     * @param list<ModuleSectionDto> $sections  Form block sections.
24     * @param list<ModuleFieldDto>   $fields    Field definitions with UiTypes.
25     * @param list<ModuleFilterDto>  $filters   DataGrid list filters.
26     * @param list<ModuleRelationDto>$relations Related module relations.
27     * @param int|null               $id        Existing module ID if editing.
28     */
29    public ModuleBasicInfoDto $basic;
30
31    public function __construct(
32        public ModuleBasicInfoDto $basicInfo,
33        public array $sections = [],
34        public array $fields = [],
35        public array $filters = [],
36        public array $relations = [],
37        public ?int $id = null
38    ) {
39        $this->basic = $basicInfo;
40    }
41
42    /**
43     * Creates composite definition from request payload array.
44     *
45     * @param array<string, mixed> $data
46     * @return self
47     */
48    public static function fromArray(array $data): self
49    {
50        $id = isset($data['id']) && is_numeric($data['id']) ? (int) $data['id'] : null;
51        $basicData = (array) ($data['basic_info'] ?? $data['basic'] ?? $data['module'] ?? $data);
52        $basicInfo = ModuleBasicInfoDto::fromArray($basicData);
53
54        $sections = self::parseSections((array) ($data['sections'] ?? []));
55        $fields = self::parseFields((array) ($data['fields'] ?? []), $basicInfo->tableAlias);
56        $filters = self::parseFilters((array) ($data['filters'] ?? []), $fields);
57        $relations = self::parseRelations((array) ($data['relations'] ?? []));
58
59        return new self(
60            basicInfo: $basicInfo,
61            sections: $sections,
62            fields: $fields,
63            filters: $filters,
64            relations: $relations,
65            id: $id
66        );
67    }
68
69    /**
70     * @param array<mixed> $rawSections
71     * @return list<ModuleSectionDto>
72     */
73    private static function parseSections(array $rawSections): array
74    {
75        if (empty($rawSections)) {
76            return [
77                new ModuleSectionDto(
78                    name: 'general_info',
79                    label: 'Podstawowe informacje',
80                    sortOrder: 10,
81                    isDefault: true
82                ),
83            ];
84        }
85
86        $sections = [];
87        foreach ($rawSections as $sec) {
88            if (is_array($sec)) {
89                $sections[] = ModuleSectionDto::fromArray($sec);
90            }
91        }
92
93        return $sections;
94    }
95
96    /**
97     * @param array<mixed> $rawFields
98     * @return list<ModuleFieldDto>
99     */
100    private static function parseFields(array $rawFields, string $tableAlias): array
101    {
102        $fields = [];
103        foreach ($rawFields as $fld) {
104            if (is_array($fld)) {
105                $fields[] = ModuleFieldDto::fromArray($fld, $tableAlias);
106            }
107        }
108
109        return $fields;
110    }
111
112    /**
113     * @param array<mixed> $rawFilters
114     * @param list<ModuleFieldDto> $fields
115     * @return list<ModuleFilterDto>
116     */
117    private static function parseFilters(array $rawFilters, array $fields): array
118    {
119        if (empty($rawFilters)) {
120            $visFields = array_map(static fn(ModuleFieldDto $f): string => $f->fieldKey, array_slice($fields, 0, 5));
121            return [
122                new ModuleFilterDto(
123                    name: 'default',
124                    label: 'Wszystkie rekordy',
125                    visibleFields: $visFields
126                ),
127            ];
128        }
129
130        $filters = [];
131        foreach ($rawFilters as $flt) {
132            if (is_array($flt)) {
133                $filters[] = ModuleFilterDto::fromArray($flt);
134            }
135        }
136
137        return $filters;
138    }
139
140    /**
141     * @param array<mixed> $rawRelations
142     * @return list<ModuleRelationDto>
143     */
144    private static function parseRelations(array $rawRelations): array
145    {
146        $relations = [];
147        foreach ($rawRelations as $rel) {
148            if (is_array($rel)) {
149                $relations[] = ModuleRelationDto::fromArray($rel);
150            }
151        }
152
153        return $relations;
154    }
155
156    /**
157     * Serializes composite definition to array.
158     *
159     * @return array<string, mixed>
160     */
161    public function toArray(): array
162    {
163        $basicData = $this->basicInfo->toArray();
164
165        return [
166            'id' => $this->id,
167            'basic_info' => $basicData,
168            'basic' => $basicData,
169            'sections' => array_map(static fn(ModuleSectionDto $s): array => $s->toArray(), $this->sections),
170            'fields' => array_map(static fn(ModuleFieldDto $f): array => $f->toArray(), $this->fields),
171            'filters' => array_map(static fn(ModuleFilterDto $flt): array => $flt->toArray(), $this->filters),
172            'relations' => array_map(static fn(ModuleRelationDto $r): array => $r->toArray(), $this->relations),
173        ];
174    }
175}