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

mimmi20 / laminasviewrenderer-bootstrap-form / 12571289709

01 Jan 2025 01:52PM UTC coverage: 97.361% (+0.05%) from 97.314%
12571289709

push

github

web-flow
Merge pull request #324 from mimmi20/updates

update dependencies

3 of 3 new or added lines in 3 files covered. (100.0%)

1 existing line in 1 file now uncovered.

2177 of 2236 relevant lines covered (97.36%)

25.54 hits per line

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

81.22
/src/FormCollection.php
1
<?php
2

3
/**
4
 * This file is part of the mimmi20/laminasviewrenderer-bootstrap-form package.
5
 *
6
 * Copyright (c) 2021-2025, Thomas Mueller <mimmi20@live.de>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11

12
declare(strict_types = 1);
13

14
namespace Mimmi20\LaminasView\BootstrapForm;
15

16
use Laminas\Form\Element\Collection as CollectionElement;
17
use Laminas\Form\ElementInterface;
18
use Laminas\Form\Exception\DomainException;
19
use Laminas\Form\Exception\InvalidArgumentException;
20
use Laminas\Form\FieldsetInterface;
21
use Laminas\Form\FormInterface;
22
use Laminas\Form\LabelAwareInterface;
23
use Laminas\Form\View\Helper\FormCollection as BaseFormCollection;
24
use Laminas\View\Exception\RuntimeException;
25
use Laminas\View\Helper\HelperInterface;
26
use Override;
27
use stdClass;
28

29
use function array_key_exists;
30
use function array_merge;
31
use function array_unique;
32
use function assert;
33
use function explode;
34
use function get_debug_type;
35
use function implode;
36
use function is_array;
37
use function is_string;
38
use function sprintf;
39
use function trim;
40

41
use const PHP_EOL;
42

43
final class FormCollection extends BaseFormCollection implements FormCollectionInterface
44
{
45
    use FormTrait;
46
    use HtmlHelperTrait;
47

48
    /**
49
     * Render a collection by iterating through all fieldsets and elements
50
     *
51
     * @throws DomainException
52
     * @throws RuntimeException
53
     * @throws InvalidArgumentException
54
     */
55
    #[Override]
22✔
56
    public function render(ElementInterface $element): string
57
    {
58
        if (!$element instanceof FieldsetInterface) {
22✔
59
            throw new InvalidArgumentException(
1✔
60
                sprintf(
1✔
61
                    '%s requires that the element is of type %s, but was %s',
1✔
62
                    __METHOD__,
1✔
63
                    FieldsetInterface::class,
1✔
64
                    get_debug_type($element),
1✔
65
                ),
1✔
66
            );
1✔
67
        }
68

69
        $markup         = '';
21✔
70
        $templateMarkup = '';
21✔
71
        $indent         = $this->getIndent();
21✔
72
        $baseIndent     = $indent;
21✔
73
        $asCard         = $element->getOption('as-card');
21✔
74

75
        if ($this->shouldWrap && $asCard) {
21✔
76
            $indent .= $this->getWhitespace(8);
4✔
77
        }
78

79
        if ($element instanceof CollectionElement && $element->shouldCreateTemplate()) {
21✔
80
            $templateMarkup = $this->renderTemplate($element, $indent);
×
81
        }
82

83
        $form     = $element->getOption('form');
21✔
84
        $layout   = $element->getOption('layout');
21✔
85
        $floating = $element->getOption('floating');
21✔
86

87
        try {
88
            $elementHelper = $this->getElementHelper();
21✔
89
        } catch (\RuntimeException $e) {
×
90
            throw new RuntimeException($e->getMessage(), 0, $e);
×
91
        }
92

93
        $fieldsetHelper = $this->getFieldsetHelper();
21✔
94

95
        foreach ($element->getIterator() as $elementOrFieldset) {
21✔
96
            assert($elementOrFieldset instanceof ElementInterface);
18✔
97

98
            $elementOrFieldset->setOption('was-validated', $element->getOption('was-validated'));
18✔
99

100
            if ($form !== null && !$elementOrFieldset->getOption('form')) {
18✔
101
                $elementOrFieldset->setOption('form', $form);
18✔
102
            }
103

104
            if ($layout !== null && !$elementOrFieldset->getOption('layout')) {
18✔
105
                $elementOrFieldset->setOption('layout', $layout);
18✔
106
            }
107

108
            if ($floating) {
18✔
109
                $elementOrFieldset->setOption('floating', true);
1✔
110
            }
111

112
            if (
113
                $element->getOption('show-required-mark')
18✔
114
                && $element->getOption('field-required-mark')
18✔
115
            ) {
116
                $elementOrFieldset->setOption('show-required-mark', true);
11✔
117
                $elementOrFieldset->setOption(
11✔
118
                    'field-required-mark',
11✔
119
                    $element->getOption('field-required-mark'),
11✔
120
                );
11✔
121
            }
122

123
            if ($elementOrFieldset instanceof FieldsetInterface) {
18✔
124
                if ($fieldsetHelper instanceof FormIndentInterface) {
1✔
125
                    $fieldsetHelper->setIndent($indent . $this->getWhitespace(4));
1✔
126
                }
127

128
                if ($fieldsetHelper instanceof BaseFormCollection) {
1✔
129
                    $fieldsetHelper->setShouldWrap($this->shouldWrap());
1✔
130

131
                    $markup .= $fieldsetHelper->render($elementOrFieldset) . PHP_EOL;
1✔
132
                }
133
            } else {
134
                $elementOrFieldset->setOption('fieldset', $element);
18✔
135

136
                if ($elementHelper instanceof FormIndentInterface) {
18✔
137
                    $elementHelper->setIndent($indent . $this->getWhitespace(4));
18✔
138
                }
139

140
                if ($elementHelper instanceof FormRenderInterface) {
18✔
141
                    $markup .= $elementHelper->render($elementOrFieldset) . PHP_EOL;
18✔
142
                }
143
            }
144
        }
145

146
        if (!$this->shouldWrap) {
21✔
147
            return $markup . $templateMarkup;
×
148
        }
149

150
        // Every collection is wrapped by a fieldset if needed
151
        $attributes = $element->getAttributes();
21✔
152

153
        if (!$this->getDoctypeHelper()->isHtml5()) {
21✔
154
            unset(
21✔
155
                $attributes['name'],
21✔
156
                $attributes['disabled'],
21✔
157
                $attributes['form'],
21✔
158
            );
21✔
159
        }
160

161
        $label      = $element->getLabel() ?? '';
21✔
162
        $legend     = '';
21✔
163
        $htmlHelper = $this->getHtmlHelper();
21✔
164

165
        if ($label !== '') {
21✔
166
            $label = $this->translateLabel($label);
21✔
167
            $label = $this->escapeLabel($element, $label);
21✔
168

169
            assert(is_string($label));
21✔
170

171
            if (
172
                $label !== '' && !$element->hasAttribute('id')
21✔
173
                || ($element instanceof LabelAwareInterface && $element->getLabelOption('always_wrap'))
21✔
174
            ) {
175
                $label = '<span>' . $label . '</span>';
21✔
176
            }
177

178
            $labelClasses    = [];
21✔
179
            $labelAttributes = $element->getOption('label_attributes') ?? [];
21✔
180

181
            assert(is_array($labelAttributes));
21✔
182

183
            if (array_key_exists('class', $labelAttributes)) {
21✔
184
                $labelClasses = explode(' ', (string) $labelAttributes['class']);
21✔
185
            }
186

187
            $labelAttributes['class'] = trim(implode(' ', array_unique($labelClasses)));
21✔
188

189
            if ($asCard) {
21✔
190
                $labelAttributes = $this->mergeFormAttributes(
4✔
191
                    $element,
4✔
192
                    'col_attributes',
4✔
193
                    ['card-title'],
4✔
194
                    $labelAttributes,
4✔
195
                );
4✔
196
            }
197

198
            $legend = PHP_EOL . $indent . $this->getWhitespace(4) . $htmlHelper->render(
21✔
199
                'legend',
21✔
200
                $labelAttributes,
21✔
201
                $label,
21✔
202
            );
21✔
203
        }
204

205
        if ($asCard) {
21✔
206
            $classes = ['card-body'];
4✔
207

208
            if (array_key_exists('class', $attributes) && is_string($attributes['class'])) {
4✔
209
                $classes = array_merge(
4✔
210
                    $classes,
4✔
211
                    explode(' ', $attributes['class']),
4✔
212
                );
4✔
213
            }
214

215
            $attributes['class'] = trim(implode(' ', array_unique($classes)));
4✔
216
        }
217

218
        $markup = $baseIndent . $htmlHelper->render(
21✔
219
            'fieldset',
21✔
220
            $attributes,
21✔
221
            $legend . PHP_EOL . $markup . $templateMarkup . $indent,
21✔
222
        );
21✔
223

224
        if ($asCard) {
21✔
225
            $markup = PHP_EOL . $baseIndent . $this->getWhitespace(4) . $htmlHelper->render(
4✔
226
                'div',
4✔
227
                $this->mergeAttributes($element, 'card_attributes', ['card']),
4✔
228
                PHP_EOL . $baseIndent . $this->getWhitespace(
4✔
229
                    4,
4✔
230
                ) . $markup . PHP_EOL . $baseIndent . $this->getWhitespace(
4✔
231
                    4,
4✔
232
                ),
4✔
233
            );
4✔
234

235
            $markup = $baseIndent . $htmlHelper->render(
4✔
236
                'div',
4✔
237
                $this->mergeAttributes($element, 'col_attributes', []),
4✔
238
                $markup . PHP_EOL . $baseIndent,
4✔
239
            );
4✔
240
        }
241

242
        return $markup;
21✔
243
    }
244

245
    /**
246
     * Only render a template
247
     *
248
     * @throws DomainException
249
     * @throws RuntimeException
250
     */
251
    #[Override]
×
252
    public function renderTemplate(CollectionElement $collection, string $indent = ''): string
253
    {
254
        $elementOrFieldset = $collection->getTemplateElement();
×
255

256
        if (!$elementOrFieldset instanceof ElementInterface) {
×
257
            return '';
×
258
        }
259

260
        $templateMarkup = '';
×
261

262
        if ($elementOrFieldset instanceof FieldsetInterface) {
×
263
            $fieldsetHelper = $this->getFieldsetHelper();
×
264
            assert($fieldsetHelper instanceof HelperInterface);
×
265

266
            if ($fieldsetHelper instanceof FormIndentInterface) {
×
267
                $fieldsetHelper->setIndent($indent . $this->getWhitespace(4));
×
268
            }
269

270
            if ($fieldsetHelper instanceof BaseFormCollection) {
×
271
                $fieldsetHelper->setShouldWrap($this->shouldWrap());
×
272

273
                $templateMarkup = $fieldsetHelper->render($elementOrFieldset) . PHP_EOL;
×
274
            }
275
        } else {
276
            try {
277
                $elementHelper = $this->getElementHelper();
×
278
            } catch (\RuntimeException $e) {
×
279
                throw new RuntimeException($e->getMessage(), 0, $e);
×
280
            }
281

282
            assert($elementHelper instanceof HelperInterface);
×
283

284
            if ($elementHelper instanceof FormIndentInterface) {
×
285
                $elementHelper->setIndent($indent . $this->getWhitespace(4));
×
286
            }
287

288
            if ($elementHelper instanceof FormRenderInterface) {
×
289
                $templateMarkup = $elementHelper->render($elementOrFieldset) . PHP_EOL;
×
290
            }
291
        }
292

293
        /** @var array<int|string, bool|float|int|iterable<int, string>|stdClass|string|null> $templateAttrbutes */
UNCOV
294
        $templateAttrbutes = $collection->getOption('template_attributes') ?? [];
×
295

296
        $htmlHelper = $this->getHtmlHelper();
×
297

298
        return $indent . $this->getWhitespace(4) . $htmlHelper->render(
×
299
            'template',
×
300
            $templateAttrbutes,
×
301
            $templateMarkup . $indent,
×
302
        ) . PHP_EOL;
×
303
    }
304

305
    /**
306
     * If set to true, collections are automatically wrapped around a fieldset
307
     *
308
     * @throws void
309
     */
310
    #[Override]
22✔
311
    public function setShouldWrap(bool $wrap): self
312
    {
313
        $this->shouldWrap = $wrap;
22✔
314

315
        return $this;
22✔
316
    }
317

318
    /**
319
     * Get wrapped
320
     *
321
     * @throws void
322
     */
323
    #[Override]
2✔
324
    public function shouldWrap(): bool
325
    {
326
        return $this->shouldWrap;
2✔
327
    }
328

329
    /**
330
     * @param array<int, string> $classes
331
     *
332
     * @return array<string, string>
333
     *
334
     * @throws void
335
     */
336
    private function mergeAttributes(ElementInterface $element, string $optionName, array $classes = []): array
4✔
337
    {
338
        $attributes = $element->getOption($optionName) ?? [];
4✔
339
        assert(is_array($attributes));
4✔
340

341
        if (array_key_exists('class', $attributes)) {
4✔
342
            $classes = array_merge($classes, explode(' ', (string) $attributes['class']));
×
343

344
            unset($attributes['class']);
×
345
        }
346

347
        if ($classes) {
4✔
348
            $attributes['class'] = implode(' ', array_unique($classes));
4✔
349
        }
350

351
        return $attributes;
4✔
352
    }
353

354
    /**
355
     * @param array<int, string>    $classes
356
     * @param array<string, string> $attributes
357
     *
358
     * @return array<string, string>
359
     *
360
     * @throws void
361
     */
362
    private function mergeFormAttributes(
4✔
363
        ElementInterface $element,
364
        string $optionName,
365
        array $classes = [],
366
        array $attributes = [],
367
    ): array {
368
        $form = $element->getOption('form');
4✔
369
        assert(
4✔
370
            $form instanceof FormInterface || $form === null,
4✔
371
            sprintf(
4✔
372
                '$form should be an Instance of %s or null, but was %s',
4✔
373
                FormInterface::class,
4✔
374
                get_debug_type($form),
4✔
375
            ),
4✔
376
        );
4✔
377

378
        if ($form !== null) {
4✔
379
            $formAttributes = $form->getOption($optionName) ?? [];
4✔
380

381
            assert(is_array($formAttributes));
4✔
382

383
            if (array_key_exists('class', $formAttributes)) {
4✔
384
                $classes = array_merge(explode(' ', (string) $formAttributes['class']), $classes);
4✔
385

386
                unset($formAttributes['class']);
4✔
387
            }
388

389
            $attributes = [...$formAttributes, ...$attributes];
4✔
390
        }
391

392
        if ($classes) {
4✔
393
            $attributes['class'] = implode(' ', array_unique($classes));
4✔
394
        }
395

396
        return $attributes;
4✔
397
    }
398
}
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

© 2025 Coveralls, Inc