ObjectTree   B
last analyzed

Complexity

Total Complexity 43

Size/Duplication

Total Lines 281
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 90
dl 0
loc 281
rs 8.96
c 2
b 0
f 0
wmc 43

11 Methods

Rating   Name   Duplication   Size   Complexity  
A myGetParentForums() 0 14 4
A getParentForums() 0 21 5
A makeSelBox() 0 20 3
B makeTreeItems() 0 16 7
A makeArrayTree() 0 9 2
A _makeSelBoxOptions() 0 14 6
A makeTree() 0 6 1
A getAllChildObject() 0 12 5
A makeObjectTree() 0 9 2
A __construct() 0 5 1
B getAllChildArray() 0 19 7

How to fix   Complexity   

Complex Class

Complex classes like ObjectTree often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ObjectTree, and based on these observations, apply Extract Interface, too.

1
<?php declare(strict_types=1);
2
3
namespace XoopsModules\Newbb;
4
5
/*
6
 * You may not change or alter any portion of this comment or credits
7
 * of supporting developers from this source code or any supporting source code
8
 * which is considered copyrighted (c) material of the original comment or credit authors.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
 */
14
15
/**
16
 * @copyright    XOOPS Project (https://xoops.org)/
17
 * @license      GNU GPL 2.0 or later (https://www.gnu.org/licenses/gpl-2.0.html)
18
 * @author       phppp (D.J., [email protected])
19
 * @author       XOOPS Development Team
20
 */
21
require_once $GLOBALS['xoops']->path('class/tree.php');
22
23
if (!\class_exists('ObjectTree')) {
24
    /**
25
     * Class ObjectTree
26
     */
27
    class ObjectTree extends \XoopsObjectTree
28
    {
29
        /**
30
         * Constructor
31
         *
32
         * @param array       $objectArr Array of {@link XoopsObject}s
33
         * @param string|null $myId      field name of object ID
34
         * @param string|null $parentId  field name of parent object ID
35
         * @param string|null $rootId    field name of root object ID
36
         */
37
        public function __construct(array $objectArr, $myId = null, $parentId = null, $rootId = null)
38
        {
39
            $myId     ??= 'forum_id';
40
            $parentId ??= 'parent_forum';
41
            parent::__construct($objectArr, $myId, $parentId, $rootId);
42
        }
43
44
        /**
45
         * Make options for a select box from
46
         *
47
         * @param int        $key           ID of the object to display as the root of select options
48
         * @param array      $ret           (reference to a string when called from outside) Result from previous recursions
49
         * @param string     $prefix_orig   String to indent items at deeper levels
50
         * @param string     $prefix_curr   String to indent the current item
51
         * @param array|null $tags
52
         * @internal  param string $fieldName Name of the member variable from the
53
         *                                  node objects that should be used as the title for the options.
54
         * @internal  param string $selected Value to display as selected
55
         * @access    private
56
         */
57
        private function makeTreeItems(int $key, array &$ret, string $prefix_orig, string $prefix_curr = '', array $tags = null): void
58
        {
59
            if ($key > 0) {
60
                if (\count((array) $tags) > 0) {
61
                    foreach ($tags as $tag) {
62
                        $ret[$key][$tag] = $this->tree[$key]['obj']->getVar($tag);
63
                    }
64
                } else {
65
                    $ret[$key]['forum_name'] = $this->tree[$key]['obj']->getVar('forum_name');
66
                }
67
                $ret[$key]['prefix'] = $prefix_curr;
68
                $prefix_curr         .= $prefix_orig;
69
            }
70
            if (isset($this->tree[$key]['child']) && !empty($this->tree[$key]['child'])) {
71
                foreach ($this->tree[$key]['child'] as $childkey) {
72
                    $this->makeTreeItems($childkey, $ret, $prefix_orig, $prefix_curr, $tags);
73
                }
74
            }
75
        }
76
77
        /**
78
         * Make a select box with options from the tree
79
         *
80
         * @param string     $prefix           String to indent deeper levels
81
         * @param int        $key              ID of the object to display as the root of select options
82
         * @param array|null $tags
83
         * @return array  HTML select box
84
         * @internal param string $name Name of the select box
85
         * @internal param string $fieldName Name of the member variable from the
86
         *                                 node objects that should be used as the title for the options.
87
         * @internal param string $selected Value to display as selected
88
         * @internal param bool $addEmptyOption Set TRUE to add an empty option with value "0" at the top of the hierarchy
89
         */
90
        public function &makeTree(string $prefix = '-', int $key = 0, array $tags = null): array
91
        {
92
            $ret = [];
93
            $this->makeTreeItems($key, $ret, $prefix, '', $tags);
94
95
            return $ret;
96
        }
97
98
        /**
99
         * Make options for a select box from
100
         *
101
         * @param string $fieldName     Name of the member variable from the
102
         *                              node objects that should be used as the title for the options.
103
         * @param string $selected      Value to display as selected
104
         * @param int    $key           ID of the object to display as the root of select options
105
         * @param string $ret           (reference to a string when called from outside) Result from previous recursions
106
         * @param string $prefix_orig   String to indent items at deeper levels
107
         * @param string $prefix_curr   String to indent the current item
108
         * @access    private
109
         */
110
        public function _makeSelBoxOptions(string $fieldName, string $selected, int $key, string &$ret, string $prefix_orig, string $prefix_curr = ''): void
111
        {
112
            if ($key > 0) {
113
                $value = $this->tree[$key]['obj']->getVar($this->myId);
114
                $ret   .= '<option value=\'' . $value . '\'';
115
                if ($value == $selected) {
116
                    $ret .= ' selected="selected"';
117
                }
118
                $ret         .= '>' . $prefix_curr . $this->tree[$key]['obj']->getVar($fieldName) . '</option>';
119
                $prefix_curr .= $prefix_orig;
120
            }
121
            if (isset($this->tree[$key]['child']) && !empty($this->tree[$key]['child'])) {
122
                foreach ($this->tree[$key]['child'] as $childkey) {
123
                    $this->_makeSelBoxOptions($fieldName, $selected, $childkey, $ret, $prefix_orig, $prefix_curr);
124
                }
125
            }
126
        }
127
128
        /**
129
         * Make a select box with options from the tree
130
         *
131
         * @param string $name             Name of the select box
132
         * @param string $fieldName        Name of the member variable from the
133
         *                                 node objects that should be used as the title for the options.
134
         * @param string $prefix           String to indent deeper levels
135
         * @param string $selected         Value to display as selected
136
         * @param bool   $addEmptyOption   Set TRUE to add an empty option with value "0" at the top of the hierarchy
137
         * @param int    $key              ID of the object to display as the root of select options
138
         * @param string $extra
139
         * @return string  HTML select box
140
         *
141
         * @deprecated since 2.5.9, please use makeSelectElement()
142
         */
143
        public function makeSelBox(
144
            $name,
145
            $fieldName,
146
            $prefix = '-',
147
            $selected = '',
148
            $addEmptyOption = false,
149
            $key = 0,
150
            $extra = ''
151
        ): string { //makeSelBox($name, $prefix = '-', $selected = '', $EmptyOption = false, $key = 0)
152
            $trace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 1);
153
            \trigger_error("makeSelBox() is deprecated since 2.5.9, please use makeSelectElement(), accessed from {$trace[0]['file']} line {$trace[0]['line']},");
154
155
            $ret = '<select name=' . $name . '>';
156
            if (!empty($addEmptyOption)) {
157
                $ret .= '<option value="0">' . (\is_string($addEmptyOption) ? $addEmptyOption : '') . '</option>';
0 ignored issues
show
introduced by
The condition is_string($addEmptyOption) is always false.
Loading history...
158
            }
159
            $this->_makeSelBoxOptions('forum_name', $selected, $key, $ret, $prefix);
160
            $ret .= '</select>';
161
162
            return $ret;
163
        }
164
165
        /**
166
         * Make a tree for the array of a given category
167
         *
168
         * @param string $key   top key of the tree
169
         * @param array  $ret   the tree
170
         * @param int    $depth level of subcategories
171
         * @internal param array $tags fields to be used
172
         */
173
        public function getAllChildObject(string $key, array &$ret, int $depth = 0): void
174
        {
175
            if (0 == --$depth) {
176
                return;
177
            }
178
179
            if (isset($this->tree[$key]['child'])) {
180
                foreach ($this->tree[$key]['child'] as $childkey) {
181
                    if (isset($this->tree[$childkey]['obj'])) {
182
                        $ret['child'][$childkey] = $this->tree[$childkey]['obj'];
183
                    }
184
                    $this->getAllChildObject($childkey, $ret['child'][$childkey], $depth);
185
                }
186
            }
187
        }
188
189
        /**
190
         * Make a tree for the array
191
         *
192
         * @param int|string $key   top key of the tree
193
         * @param int        $depth level of subcategories
194
         * @return array
195
         * @internal param array $tags fields to be used
196
         */
197
        public function &makeObjectTree($key = 0, int $depth = 0): array
198
        {
199
            $ret = [];
200
            if ($depth > 0) {
201
                ++$depth;
202
            }
203
            $this->getAllChildObject($key, $ret, $depth);
204
205
            return $ret;
206
        }
207
208
        /**
209
         * Make a tree for the array of a given category
210
         *
211
         * @param string $key   top key of the tree
212
         * @param array  $ret   the tree
213
         * @param array  $tags  fields to be used
214
         * @param int    $depth level of subcategories
215
         */
216
        public function getAllChildArray(string $key, array &$ret, array $tags = [], int $depth = 0): void
217
        {
218
            if (0 == --$depth) {
219
                return;
220
            }
221
222
            if (isset($this->tree[$key]['child'])) {
223
                foreach ($this->tree[$key]['child'] as $childkey) {
224
                    if (isset($this->tree[$childkey]['obj'])) {
225
                        if (\count($tags) > 0) {
226
                            foreach ($tags as $tag) {
227
                                $ret['child'][$childkey][$tag] = $this->tree[$childkey]['obj']->getVar($tag);
228
                            }
229
                        } else {
230
                            $ret['child'][$childkey]['forum_name'] = $this->tree[$childkey]['obj']->getVar('forum_name');
231
                        }
232
                    }
233
234
                    $this->getAllChildArray($childkey, $ret['child'][$childkey], $tags, $depth);
235
                }
236
            }
237
        }
238
239
        /**
240
         * Make a tree for the array
241
         *
242
         * @param int|string $key   top key of the tree
243
         * @param array|null $tags  fields to be used
244
         * @param int        $depth level of subcategories
245
         * @return array
246
         */
247
        public function &makeArrayTree($key = 0, array $tags = null, int $depth = 0): array
248
        {
249
            $ret = [];
250
            if ($depth > 0) {
251
                ++$depth;
252
            }
253
            $this->getAllChildArray($key, $ret, $tags, $depth);
0 ignored issues
show
Bug introduced by
It seems like $tags can also be of type null; however, parameter $tags of XoopsModules\Newbb\ObjectTree::getAllChildArray() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

253
            $this->getAllChildArray($key, $ret, /** @scrutinizer ignore-type */ $tags, $depth);
Loading history...
254
255
            return $ret;
256
        }
257
258
        /**#@+
259
         * get all parent forums
260
         *
261
         * @param int $key     ID of the child object
262
         * @param array  $ret     (empty when called from outside) Result from previous recursions
263
         * @param int    $uplevel (empty when called from outside) level of recursion
264
         * @return array  Array of parent nodes.
265
         */
266
        public function &myGetParentForums(int $key, array $ret = [], int $uplevel = 0): array
267
        {
268
            if (isset($this->tree[$key]['parent'], $this->tree[$this->tree[$key]['parent']]['obj'])) {
269
                $ret[$uplevel] = $this->tree[$this->tree[$key]['parent']]['obj'];
270
                if ($this->tree[$key]['parent'] !== $key) {
271
                    //$parents = $this->getParentForums($this->tree[$key]['parent'], $ret, $uplevel+1);
272
                    $parents = $this->getParentForums($this->tree[$key]['parent']);
273
                    foreach (\array_keys($parents) as $newkey) {
274
                        $ret[$newkey] = $parents[$newkey];
275
                    }
276
                }
277
            }
278
279
            return $ret;
280
        }
281
282
        /**
283
         * @param int|string $key
284
         * @param bool   $reverse
285
         * @return array
286
         */
287
        public function &getParentForums($key, bool $reverse = true): array
288
        {
289
            $ret  = [];
290
            $pids = [];
291
            if (isset($this->tree[$key]['parent'], $this->tree[$this->tree[$key]['parent']]['obj'])) {
292
                $pids[]  = $this->tree[$this->tree[$key]['parent']]['obj']->getVar($this->myId);
293
                $parents = $this->myGetParentForums($this->tree[$key]['parent'], $ret);
294
                foreach (\array_keys($parents) as $newkey) {
295
                    if (!\is_object($newkey)) {
296
                        continue;
297
                    }
298
                    $ret[] = $parents[$newkey]->getVar($this->myId);
299
                }
300
            }
301
            if ($reverse) {
302
                $pids = \array_reverse($ret) + $pids;
303
            } else {
304
                $pids += $ret;
305
            }
306
307
            return $pids;
308
        }
309
        /**#@-*/
310
    }
311
}
312