Completed
Push — master ( 3ef1ae...4ba2eb )
by
unknown
17:01
created

ArrayBrowser   A

Complexity

Total Complexity 37

Size/Duplication

Total Lines 177
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 73
dl 0
loc 177
rs 9.44
c 0
b 0
f 0
wmc 37

4 Methods

Rating   Name   Duplication   Size   Complexity  
C getSearchKeys() 0 32 14
A __construct() 0 4 1
B depthKeys() 0 23 7
F tree() 0 35 15
1
<?php
2
declare(strict_types = 1);
3
4
namespace TYPO3\CMS\Backend\View;
5
6
/*
7
 * This file is part of the TYPO3 CMS project.
8
 *
9
 * It is free software; you can redistribute it and/or modify it under
10
 * the terms of the GNU General Public License, either version 2
11
 * of the License, or any later version.
12
 *
13
 * For the full copyright and license information, please read the
14
 * LICENSE.txt file that was distributed with this source code.
15
 *
16
 * The TYPO3 project - inspiring people to share!
17
 */
18
19
use TYPO3\CMS\Backend\Routing\Route;
20
use TYPO3\CMS\Backend\Routing\UriBuilder;
21
use TYPO3\CMS\Core\Utility\GeneralUtility;
22
23
/**
24
 * Class for displaying an array as a tree which can collapse / expand.
25
 *
26
 * See the extension 'lowlevel' / config (Backend module 'Tools > Configuration')
27
 * @internal just a helper class for internal usage.
28
 */
29
class ArrayBrowser
30
{
31
    /**
32
     * @var bool
33
     */
34
    public $expAll = false;
35
36
    /**
37
     * If set, the variable keys are not linked.
38
     *
39
     * @var array
40
     */
41
    public $depthKeys = [];
42
43
    /**
44
     * Array defining which keys to expand. Typically set from outside from some session
45
     * variable - otherwise the array will collapse.
46
     *
47
     * @var array
48
     */
49
    public $searchKeys = [];
50
51
    /**
52
     * If set, the values are truncated with "..." appended if longer than a certain
53
     * length.
54
     *
55
     * @var int
56
     */
57
    public $regexMode = 0;
58
59
    /**
60
     * If set, search for string with regex, otherwise stristr()
61
     *
62
     * @var bool
63
     */
64
    public $searchKeysToo = true;
65
66
    /**
67
     * @var UriBuilder
68
     */
69
    protected $uriBuilder;
70
71
    /**
72
     * If null then there are no links set.
73
     *
74
     * @var Route|null
75
     */
76
    protected $route;
77
78
    public function __construct(Route $route = null)
79
    {
80
        $this->route = $route;
81
        $this->uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
82
    }
83
84
    /**
85
     * Set var name here if you want links to the variable name.
86
     *
87
     * Make browsable tree
88
     * Before calling this function you may want to set some of the internal vars like
89
     * depthKeys and regexMode.
90
     *
91
     * @param array $array The array to display
92
     * @param string $positionKey Key-position id. Build up during recursive calls - [key1].[key2].[key3] - and so on.
93
     * @return string HTML for the tree
94
     */
95
    public function tree($array, $positionKey)
96
    {
97
        $output = '<ul class="list-tree text-monospace">';
98
        if ($positionKey) {
99
            $positionKey .= '.';
100
        }
101
        foreach ($array as $key => $value) {
102
            $depth = $positionKey . $key;
103
            if (is_object($value) && !$value instanceof \Traversable) {
104
                $value = (array)$value;
105
            }
106
            $isArray = is_iterable($value);
107
            $isResult = (bool)$this->searchKeys[$depth];
108
            $isExpanded = $isArray && (!empty($this->depthKeys[$depth]) || $this->expAll);
109
            $output .= '<li' . ($isResult ? ' class="active"' : '') . '>';
110
            $output .= '<span class="list-tree-group">';
111
            if ($isArray && !$this->expAll && $this->route) {
112
                $goto = 'a' . substr(md5($depth), 0, 6);
113
                $output .= '<a class="list-tree-control' . ($isExpanded ? ' list-tree-control-open' : ' list-tree-control-closed') . '" id="' . $goto . '" href="' . htmlspecialchars((string)$this->uriBuilder->buildUriFromRoute($this->route->getOption('_identifier'), ['node' => [rawurldecode($depth) => $isExpanded ? 0 : 1]]) . '#' . $goto) . '"><i class="fa"></i></a> ';
114
            }
115
            $output .= '<span class="list-tree-label">' . htmlspecialchars($key) . '</span>';
116
            if (!$isArray) {
117
                $output .= ' = <span class="list-tree-value">' . htmlspecialchars($value) . '</span>';
118
            }
119
            $output .= '</span>';
120
            if ($isExpanded) {
121
                $output .= $this->tree(
122
                    $value,
123
                    $depth
124
                );
125
            }
126
            $output .= '</li>';
127
        }
128
        $output .= '</ul>';
129
        return $output;
130
    }
131
132
    /**
133
     * Creates an array with "depthKeys" which will expand the array to show the search results
134
     *
135
     * @param array $keyArr The array to search for the value
136
     * @param string $depth_in Depth string - blank for first call (will build up during recursive calling creating
137
     *                         an id of the position: [key1].[key2].[key3]
138
     * @param string $searchString The string to search for
139
     * @param array $keyArray Key array, for first call pass empty array
140
     * @return array
141
     */
142
    public function getSearchKeys($keyArr, $depth_in, $searchString, $keyArray)
143
    {
144
        if ($depth_in) {
145
            $depth_in .= '.';
146
        }
147
        foreach ($keyArr as $key => $value) {
148
            $depth = $depth_in . $key;
149
            $deeper = is_array($keyArr[$key]);
150
            if ($this->regexMode) {
151
                if (
152
                    is_scalar($keyArr[$key]) && preg_match('/' . $searchString . '/', $keyArr[$key])
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: (is_scalar($keyArr[$key]...archString . '/', $key), Probably Intended Meaning: is_scalar($keyArr[$key])...rchString . '/', $key))
Loading history...
153
                    || $this->searchKeysToo && preg_match('/' . $searchString . '/', $key)
154
                ) {
155
                    $this->searchKeys[$depth] = 1;
156
                }
157
            } else {
158
                if (
159
                    is_scalar($keyArr[$key]) && stripos($keyArr[$key], $searchString) !== false
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: (is_scalar($keyArr[$key]...searchString) !== false, Probably Intended Meaning: is_scalar($keyArr[$key])...earchString) !== false)
Loading history...
160
                    || $this->searchKeysToo && stripos($key, $searchString) !== false
161
                ) {
162
                    $this->searchKeys[$depth] = 1;
163
                }
164
            }
165
            if ($deeper) {
166
                $cS = count($this->searchKeys);
167
                $keyArray = $this->getSearchKeys($keyArr[$key], $depth, $searchString, $keyArray);
168
                if ($cS != count($this->searchKeys)) {
169
                    $keyArray[$depth] = 1;
170
                }
171
            }
172
        }
173
        return $keyArray;
174
    }
175
176
    /**
177
     * Function modifying the depthKey array
178
     *
179
     * @param array $arr Array with instructions to open/close nodes.
180
     * @param array $settings Input depth_key array
181
     * @return array Output depth_key array with entries added/removed based on $arr
182
     */
183
    public function depthKeys($arr, $settings)
184
    {
185
        $tsbrArray = [];
186
        foreach ($arr as $theK => $theV) {
187
            $theKeyParts = explode('.', (string)$theK);
188
            $depth = '';
189
            $c = count($theKeyParts);
190
            $a = 0;
191
            foreach ($theKeyParts as $p) {
192
                $a++;
193
                $depth .= ($depth ? '.' : '') . $p;
194
                $tsbrArray[$depth] = $c == $a ? $theV : 1;
195
            }
196
        }
197
        // Modify settings
198
        foreach ($tsbrArray as $theK => $theV) {
199
            if ($theV) {
200
                $settings[$theK] = 1;
201
            } else {
202
                unset($settings[$theK]);
203
            }
204
        }
205
        return $settings;
206
    }
207
}
208