1<?php
2
3declare(strict_types=1);
4
5/*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18namespace TYPO3\CMS\Backend\Form\Behavior;
19
20use TYPO3\CMS\Core\Utility\GeneralUtility;
21
22trait OnFieldChangeTrait
23{
24    /**
25     * @param array<string, string|OnFieldChangeInterface> $items `fieldChangeFunc` items
26     * @return array<int, array>
27     */
28    protected function getOnFieldChangeItems(array $items): array
29    {
30        if (empty($items)) {
31            return [];
32        }
33        return array_map(
34            static function (OnFieldChangeInterface $item) {
35                return $item->toArray();
36            },
37            // omitting array keys
38            array_values($items)
39        );
40    }
41
42    /**
43     * @param string $event target client event, either `change` or `click`
44     * @param array<string, string|OnFieldChangeInterface> $items `fieldChangeFunc` items
45     * @return array<string, string> HTML attrs, not encoded - consumers MUST encode with `htmlspecialchars`
46     */
47    protected function getOnFieldChangeAttrs(string $event, array $items): array
48    {
49        if (empty($items)) {
50            return [];
51        }
52        if ($this->validateOnFieldChange($items)) {
53            $onFieldChangeItems = $this->getOnFieldChangeItems($items);
54            $attrs = [
55                'data-formengine-field-change-event' => $event,
56                'data-formengine-field-change-items' => GeneralUtility::jsonEncodeForHtmlAttribute($onFieldChangeItems, false),
57            ];
58        } else {
59            $attrs = [
60                'on' . $event => implode(';', $items),
61            ];
62        }
63        return $attrs;
64    }
65
66    /**
67     * @param array<string, string|OnFieldChangeInterface> $items `fieldChangeFunc` items
68     * @param bool $deprecate whether to trigger deprecations
69     * @return bool whether all items implement `OnFieldChangeInterface`
70     */
71    protected function validateOnFieldChange(array $items, bool $deprecate = true): bool
72    {
73        $result = true;
74        // all items are processed, to log all possible deprecated usages
75        foreach ($items as $name => $item) {
76            if ($item instanceof OnFieldChangeInterface) {
77                continue;
78            }
79            $result = false;
80            if (!$deprecate) {
81                continue;
82            }
83            trigger_error(
84                sprintf('Using scalar `fieldChangeFunc` for `%s` is deprecated and will be removed in TYPO3 v12.0. Use `OnFieldChangeInterface` instead.', $name),
85                E_USER_DEPRECATED
86            );
87        }
88        return $result;
89    }
90
91    /**
92     * Forwards URL query params for `LinkBrowserController`
93     * @param array<string, string|OnFieldChangeInterface> $items `fieldChangeFunc` items
94     * @return array<string, string> relevant URL query params for `LinkBrowserController`
95     */
96    protected function forwardOnFieldChangeQueryParams(array $items): array
97    {
98        if ($this->validateOnFieldChange($items, false)) {
99            $type = 'items';
100            $func = $this->getOnFieldChangeItems($items);
101        } else {
102            $type = 'raw';
103            $func = $items;
104        }
105        return [
106            'fieldChangeFunc' => $func,
107            'fieldChangeFuncType' => $type,
108            'fieldChangeFuncHash' => GeneralUtility::hmac(serialize($func), 'backend-link-browser'),
109        ];
110    }
111}
112