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

NIT-Administrative-Systems / dynamic-forms / 13506106128

24 Feb 2025 07:22PM UTC coverage: 59.275% (-34.7%) from 94.003%
13506106128

Pull #480

github

nie7321
Additional annotations
Pull Request #480: Laravel 12

818 of 1380 relevant lines covered (59.28%)

44.49 hits per line

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

84.31
/src/Forms/Form.php
1
<?php
2

3
namespace Northwestern\SysDev\DynamicForms\Forms;
4

5
use Illuminate\Support\Arr;
6
use Northwestern\SysDev\DynamicForms\ComponentRegistry;
7
use Northwestern\SysDev\DynamicForms\Components\BaseComponent;
8
use Northwestern\SysDev\DynamicForms\Components\ComponentInterface;
9
use Northwestern\SysDev\DynamicForms\Components\CustomSubcomponentDeserialization;
10
use Northwestern\SysDev\DynamicForms\Components\ResourceValues;
11
use Northwestern\SysDev\DynamicForms\Components\UploadInterface;
12
use Northwestern\SysDev\DynamicForms\Errors\InvalidDefinitionError;
13
use Northwestern\SysDev\DynamicForms\FileComponentRegistry;
14
use Northwestern\SysDev\DynamicForms\Forms\Concerns\HandlesTree;
15
use Northwestern\SysDev\DynamicForms\ResourceRegistry;
16

17
class Form
18
{
19
    use HandlesTree;
20

21
    /**
22
     * Array of components, potentially with more components nested inside of those.
23
     *
24
     * @var ComponentInterface[]
25
     */
26
    protected array $components;
27

28
    /**
29
     * Components w/ nesting flattened out, indexed by the component key.
30
     *
31
     * @var ComponentInterface[]
32
     */
33
    protected array $flatComponents;
34

35
    protected ComponentRegistry $componentRegistry;
36

37
    protected FileComponentRegistry $fileComponentRegistry;
38

39
    protected ?ResourceRegistry $resourceRegistry;
40

41
    public function __construct(string $definitionJson, ?ResourceRegistry $resourceRegistry = null)
42
    {
43
        $this->componentRegistry = resolve(ComponentRegistry::class);
12✔
44
        $this->fileComponentRegistry = resolve(FileComponentRegistry::class);
12✔
45

46
        if (! isset($resourceRegistry)) {
12✔
47
            $this->resourceRegistry = resolve(ResourceRegistry::class);
12✔
48
        } else {
49
            $this->resourceRegistry = $resourceRegistry;
×
50
        }
51

52
        $this->setDefinition($definitionJson);
12✔
53
    }
54

55
    /**
56
     * Get the nested components.
57
     *
58
     * @return ComponentInterface[]
59
     */
60
    public function components(): array
61
    {
62
        return $this->components;
×
63
    }
64

65
    /**
66
     * Get a flat array of key: components back.
67
     *
68
     * @return ComponentInterface[]
69
     */
70
    public function flatComponents(): array
71
    {
72
        return $this->flatComponents;
12✔
73
    }
74

75
    /**
76
     * Runs validations & transformations, returning a ValidatedForm object.
77
     */
78
    public function validate(string $submissionJson): ValidatedForm
79
    {
80
        return new ValidatedForm($this->components, json_decode($submissionJson, true));
×
81
    }
82

83
    protected function setDefinition(string $json): void
84
    {
85
        $json = json_decode($json, true);
12✔
86
        if (! Arr::has($json, 'components')) {
12✔
87
            throw new InvalidDefinitionError('Expected path missing', 'components');
×
88
        }
89

90
        $this->components = $this->processComponentDefinition($json);
12✔
91
        $this->flatComponents = $this->flattenComponents($this->components);
12✔
92
    }
93

94
    /**
95
     * Recursive function to deserialize all of the components into Component objects.
96
     */
97
    protected function processComponentDefinition(array $componentJson, $path = ''): array
98
    {
99
        if (! Arr::has($componentJson, 'components')) {
12✔
100
            return [];
12✔
101
        }
102

103
        $components = [];
12✔
104
        foreach ($componentJson['components'] as $definition) {
12✔
105
            if (! Arr::has($definition, ['key', 'type'])) {
12✔
106
                $path .= '.components';
×
107
                throw new InvalidDefinitionError('Unable to find required component props "key" & "type"', $path);
×
108
            }
109

110
            $class = $this->componentRegistry->get($definition['type']);
12✔
111

112
            // Some components (columns + tables) don't keep children in 'components' like they ought to
113
            if (is_subclass_of($class, CustomSubcomponentDeserialization::class)) {
12✔
114
                $children = $this->getCustomChildren($class, $definition, $path);
9✔
115
            } else {
116
                $children = $this->processComponentDefinition($definition, $path.'.'.$definition['key'].'.components');
12✔
117
            }
118

119
            $component = new $class(
12✔
120
                $definition['key'],
12✔
121
                Arr::get($definition, 'label'),
12✔
122
                Arr::get($definition, 'errorLabel'),
12✔
123
                $children,
12✔
124
                Arr::get($definition, 'validate', []),
12✔
125
                Arr::get($definition, 'multiple', false),
12✔
126
                Arr::get($definition, 'conditional'),
12✔
127
                Arr::get($definition, 'customConditional'),
12✔
128
                Arr::get($definition, 'case', 'mixed'),
12✔
129
                Arr::get($definition, 'calculateValue'),
12✔
130
                Arr::get($definition, 'defaultValue'),
12✔
131
                Arr::except($definition, ['key', 'label', 'components', 'validate', 'type', 'input', 'tableView', 'multiple', 'conditional', 'customConditional', 'calculateValue', 'case', 'errorLabel', 'defaultValue']),
12✔
132
            );
12✔
133

134
            if (is_subclass_of($component, UploadInterface::class)) {
12✔
135
                $storageDriver = $this->fileComponentRegistry->get($component->getStorageType());
×
136
                $component->setStorageDriver(resolve($storageDriver));
×
137
            }
138

139
//            Because component is instantiated above, its constructor can't call methods that use resourceRegistry
140
            if (is_subclass_of($component, ResourceValues::class)) {
12✔
141
                $component->setResourceRegistry($this->resourceRegistry);
6✔
142
            }
143

144
            $components[] = $component;
12✔
145
        }
146

147
        return $components;
12✔
148
    }
149

150
    /**
151
     * @param string $class
152
     * @param array $definition
153
     * @param string $basePath
154
     * @return BaseComponent[]
155
     * @throws InvalidDefinitionError
156
     */
157
    private function getCustomChildren(string $class, array $definition, string $basePath): array
158
    {
159
        $paths = $class::pathsToChildren($definition);
9✔
160

161
        $children = collect();
9✔
162
        foreach ($paths as $path) {
9✔
163
            $children = $children->concat($this->processComponentDefinition(Arr::get($definition, $path), $basePath.''.$path));
9✔
164
        }
165

166
        return $children->all();
9✔
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