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

FluidTYPO3 / flux / 12930122773

23 Jan 2025 01:22PM UTC coverage: 92.829% (-0.07%) from 92.901%
12930122773

Pull #2209

github

web-flow
Merge 83c833b70 into cf49f7a79
Pull Request #2209: [WIP] Compatibility with TYPO3 v13

86 of 112 new or added lines in 31 files covered. (76.79%)

5 existing lines in 3 files now uncovered.

7055 of 7600 relevant lines covered (92.83%)

65.02 hits per line

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

63.55
/Classes/Utility/MiscellaneousUtility.php
1
<?php
2
declare(strict_types=1);
3
namespace FluidTYPO3\Flux\Utility;
4

5
/*
6
 * This file is part of the FluidTYPO3/Flux project under GPLv2 or later.
7
 *
8
 * For the full copyright and license information, please read the
9
 * LICENSE.md file that was distributed with this source code.
10
 */
11

12
use DOMElement;
13
use DOMNode;
14
use DOMNodeList;
15
use FluidTYPO3\Flux\Enum\FormOption;
16
use FluidTYPO3\Flux\Form;
17
use TYPO3\CMS\Core\Imaging\Icon;
18
use TYPO3\CMS\Core\Imaging\IconProvider\BitmapIconProvider;
19
use TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider;
20
use TYPO3\CMS\Core\Imaging\IconRegistry;
21
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
22
use TYPO3\CMS\Core\Utility\GeneralUtility;
23

24
class MiscellaneousUtility
25
{
26
    private static array $allowedIconTypes = ['svg', 'png', 'gif'];
27

28
    /**
29
     * Returns the icon for a template
30
     * - checks and returns if manually set as option or
31
     * - checks and returns Icon if it exists by convention in
32
     *   EXT:$extensionKey/Resources/Public/Icons/$controllerName/$templateName.(png|gif)
33
     */
34
    public static function getIconForTemplate(Form $form): ?string
35
    {
36
        if (true === $form->hasOption(FormOption::ICON)) {
63✔
37
            $iconOptionValue = $form->getOption(FormOption::ICON);
7✔
38
            return is_scalar($iconOptionValue) ? (string) $iconOptionValue : null;
7✔
39
        }
40
        if (true === $form->hasOption(FormOption::TEMPLATE_FILE)) {
56✔
41
            $extensionKey = ExtensionNamingUtility::getExtensionKey((string) $form->getExtensionName());
7✔
42
            $fullTemplatePathAndName = $form->getOption(FormOption::TEMPLATE_FILE);
7✔
43
            $templatePathParts = is_scalar($fullTemplatePathAndName)
7✔
44
                ? explode('/', (string) $fullTemplatePathAndName)
7✔
45
                : [];
1✔
46
            if (empty($templatePathParts)) {
7✔
47
                return null;
×
48
            }
49
            $templateName = pathinfo(array_pop($templatePathParts), PATHINFO_FILENAME);
7✔
50
            $controllerName = array_pop($templatePathParts);
7✔
51
            $relativeIconFolder = 'Resources/Public/Icons/' . $controllerName . '/';
7✔
52
            $iconFolder = ExtensionManagementUtility::extPath(
7✔
53
                $extensionKey,
7✔
54
                $relativeIconFolder
7✔
55
            );
7✔
56
            $iconPathAndName = $iconFolder . $templateName;
7✔
57
            $filesInFolder = array();
7✔
58
            if (true === is_dir($iconFolder)) {
7✔
59
                if (true === defined('GLOB_BRACE')) {
×
60
                    $allowedExtensions = implode(',', self::$allowedIconTypes);
×
61
                    $iconMatchPattern = $iconPathAndName . '.{' . $allowedExtensions . '}';
×
62
                    $filesInFolder = glob($iconMatchPattern, GLOB_BRACE);
×
63
                } else {
64
                    foreach (self::$allowedIconTypes as $allowedIconType) {
×
65
                        $filesInFolder = array_merge(
×
66
                            $filesInFolder,
×
67
                            glob($iconPathAndName . '.' . $allowedIconType) ?: []
×
68
                        );
×
69
                    }
70
                }
71
            }
72
            $iconFile = (is_array($filesInFolder) && 0 < count($filesInFolder) ? reset($filesInFolder) : null);
7✔
73
            $iconRelPathAndFilename = $iconFile
7✔
74
                ? 'EXT:' . $extensionKey . '/' . $relativeIconFolder . pathinfo($iconFile, PATHINFO_BASENAME)
×
75
                : null;
7✔
76
            return $iconRelPathAndFilename;
7✔
77
        }
78
        return null;
49✔
79
    }
80

81
    public static function createIconIdentifier(string $originalFile): string
82
    {
NEW
83
        return 'icon-' . md5($originalFile);
×
84
    }
85

86
    /**
87
     * Returns a generated icon file into typo3temp/pics
88
     */
89
    public static function createIcon(string $originalFile, ?string $identifier = null): string
90
    {
91
        /** @var IconRegistry $iconRegistry */
92
        $iconRegistry = GeneralUtility::makeInstance(IconRegistry::class);
14✔
93
        if ($iconRegistry->isRegistered($originalFile)) {
14✔
94
            return $originalFile;
14✔
95
        }
96

97
        if (strpos($originalFile, 'EXT:') === 0 || $originalFile[0] !== '/') {
×
98
            $originalFile = GeneralUtility::getFileAbsFileName($originalFile);
×
99
        }
100

101
        $extension = pathinfo($originalFile, PATHINFO_EXTENSION);
×
102
        switch (strtolower($extension)) {
×
103
            case 'svg':
×
104
            case 'svgz':
×
105
                $iconProvider = SvgIconProvider::class;
×
106
                break;
×
107
            default:
108
                $iconProvider = BitmapIconProvider::class;
×
109
        }
110

NEW
111
        $iconIdentifier = $identifier ?? self::createIconIdentifier($originalFile);
×
112
        $iconRegistry->registerIcon(
×
113
            $iconIdentifier,
×
114
            $iconProvider,
×
115
            ['source' => $originalFile, 'size' => Icon::SIZE_DEFAULT]
×
116
        );
×
117
        return $iconIdentifier;
×
118
    }
119

120
    /**
121
     * Cleans flex form XML, removing any field nodes identified
122
     * in $removals and trimming the result to avoid empty containers.
123
     */
124
    public static function cleanFlexFormXml(string $xml, array $removals = []): string
125
    {
126
        $dom = new \DOMDocument();
42✔
127
        $dom->loadXML($xml);
42✔
128
        $dom->preserveWhiteSpace = false;
42✔
129
        $dom->formatOutput = true;
42✔
130
        $fieldNodesToRemove = [];
42✔
131
        foreach ($dom->getElementsByTagName('field') as $fieldNode) {
42✔
132
            /** @var DOMElement $fieldNode */
133
            if (true === in_array($fieldNode->getAttribute('index'), $removals)) {
28✔
134
                $fieldNodesToRemove[] = $fieldNode;
21✔
135
            }
136
        }
137

138
        foreach ($fieldNodesToRemove as $fieldNodeToRemove) {
42✔
139
            /** @var DOMNode $parent */
140
            $parent = $fieldNodeToRemove->parentNode;
21✔
141
            /** @var DOMElement $fieldNodeToRemove */
142
            $parent->removeChild($fieldNodeToRemove);
21✔
143
        }
144

145
        // Assign a hidden ID to all container-type nodes, making the value available in templates etc.
146
        foreach ($dom->getElementsByTagName('el') as $containerNode) {
42✔
147
            /** @var DOMElement $containerNode */
148
            $hasIdNode = false;
21✔
149
            if ($containerNode->attributes instanceof \DOMNamedNodeMap && 0 < count($containerNode->attributes)) {
21✔
150
                // skip <el> tags reserved for other purposes by attributes; only allow pure <el> tags.
151
                continue;
21✔
152
            }
153
            foreach ($containerNode->childNodes as $fieldNodeInContainer) {
7✔
154
                /** @var DOMNode $fieldNodeInContainer */
155
                if (false === $fieldNodeInContainer instanceof DOMElement) {
7✔
156
                    continue;
7✔
157
                }
158
                $isFieldNode = ('field' === $fieldNodeInContainer->tagName);
7✔
159
                $isIdField = ('id' === $fieldNodeInContainer->getAttribute('index'));
7✔
160
                if ($isFieldNode && $isIdField) {
7✔
161
                    $hasIdNode = true;
7✔
162
                    break;
7✔
163
                }
164
            }
165
            if (false === $hasIdNode) {
7✔
166
                $idNode = $dom->createElement('field');
×
167
                $idIndexAttribute = $dom->createAttribute('index');
×
168
                $idIndexAttribute->nodeValue = 'id';
×
169
                $idNode->appendChild($idIndexAttribute);
×
170
                $valueNode = $dom->createElement('value');
×
171
                $valueIndexAttribute = $dom->createAttribute('index');
×
172
                $valueIndexAttribute->nodeValue = 'vDEF';
×
173
                $valueNode->appendChild($valueIndexAttribute);
×
174
                $valueNode->nodeValue = sha1(uniqid('container_', true));
×
175
                $idNode->appendChild($valueNode);
×
176
                $containerNode->appendChild($idNode);
×
177
            }
178
        }
179
        // Remove all sheets that no longer contain any fields.
180
        $nodesToBeRemoved = [];
42✔
181
        foreach ($dom->getElementsByTagName('sheet') as $sheetNode) {
42✔
182
            if (0 === $sheetNode->getElementsByTagName('field')->length) {
28✔
183
                $nodesToBeRemoved[] = $sheetNode;
14✔
184
            }
185
        }
186

187
        foreach ($nodesToBeRemoved as $node) {
42✔
188
            /** @var DOMNode $parent */
189
            $parent = $node->parentNode;
14✔
190
            /** @var DOMElement $node */
191
            $parent->removeChild($node);
14✔
192
        }
193

194
        // Return empty string in case remaining flexform XML is all empty
195
        /** @var DOMNodeList $dataNodes */
196
        $dataNodes = $dom->getElementsByTagName('data');
42✔
197
        /** @var DOMElement $dataNode */
198
        $dataNode = $dataNodes->item(0);
42✔
199
        $elements = $dataNode->getElementsByTagName('sheet');
42✔
200
        if (0 === $elements->length) {
42✔
201
            return '';
21✔
202
        }
203
        $xml = (string) $dom->saveXML();
21✔
204
        // hack-like pruning of empty-named node inserted when removing objects from a previously populated Section
205
        $xml = (string) preg_replace('#<el index="el">\s*</el>#', '', $xml);
21✔
206
        $xml = (string) preg_replace('#<field index="[^"]*">\s*</field>#', '', $xml);
21✔
207
        return $xml;
21✔
208
    }
209
}
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