Completed
Pull Request — master (#600)
by Richard
18:11
created

ObjectTree::getTree()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
ccs 2
cts 2
cp 1
crap 1
1
<?php
2
3
namespace Xoops\Core;
4
5
use Xoops\Core\Kernel\XoopsObject;
6
use Xoops\Form\Select;
7
8
/*
9
 You may not change or alter any portion of this comment or credits
10
 of supporting developers from this source code or any supporting source code
11
 which is considered copyrighted (c) material of the original comment or credit authors.
12
13
 This program is distributed in the hope that it will be useful,
14
 but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
*/
17
18
/**
19
 * Tree structures with XoopsObjects as nodes
20
 *
21
 * @category  Xoops\Core
22
 * @package   ObjectTree
23
 * @author    Kazumi Ono <[email protected]>
24
 * @copyright 2000-2019 XOOPS Project (https://xoops.org)
25
 * @license   GNU GPL 2 or later (https://www.gnu.org/licenses/gpl-2.0.html)
26
 */
27
class ObjectTree
28
{
29
    /**
30
     * @var string
31
     */
32
    protected $parentId;
33
34
    /**
35
     * @var string
36
     */
37
    protected $myId;
38
39
    /**
40
     * @var null|string
41
     */
42
    protected $rootId;
43
44
    /**
45
     * @var array;
46
     */
47
    protected $tree = [];
48
49
    /**
50
     * @var array
51
     */
52
    protected $objects;
53
54
    /**
55
     * Constructor
56
     *
57
     * @param XoopsObject[] $objectArr array of XoopsObject that form the tree
58
     * @param string        $myId      field name of the ID for each object
59
     * @param string        $parentId  field name of the ID in each object of parent object
60
     * @param string|null   $rootId    optional field name of the root object ID,
61
     *                                 i.e. the top comment in a series of nested comments
62
     */
63 4
    public function __construct($objectArr, $myId, $parentId, $rootId = null)
64
    {
65 4
        $this->objects = $objectArr;
66 4
        $this->myId     = $myId;
67 4
        $this->parentId = $parentId;
68 4
        if (isset($rootId)) {
69 3
            $this->rootId = $rootId;
70
        }
71 4
        $this->initialize();
72 4
    }
73
74
    /**
75
     * Initialize the object
76
     *
77
     * @return void
78
     */
79 4
    protected function initialize(): void
80
    {
81 4
        foreach (array_keys($this->objects) as $i) {
82 4
            $key1                         = $this->objects[$i]->getVar($this->myId);
83 4
            $this->tree[$key1]['obj']     = $this->objects[$i];
84 4
            $key2                         = $this->objects[$i]->getVar($this->parentId);
85 4
            $this->tree[$key1]['parent']  = $key2;
86 4
            $this->tree[$key2]['child'][] = $key1;
87 4
            if (isset($this->rootId)) {
88 4
                $this->tree[$key1]['root'] = $this->objects[$i]->getVar($this->rootId);
89
            }
90
        }
91 4
    }
92
93
    /**
94
     * Get the tree
95
     *
96
     * @return array Associative array comprising the tree
97
     */
98 1
    public function getTree(): array
99
    {
100 1
        return $this->tree;
101
    }
102
103
    /**
104
     * returns an object from the tree specified by its id
105
     *
106
     * @param  string $key ID of the object to retrieve
107
     * @return XoopsObject Object within the tree
108
     */
109 2
    public function getByKey($key): XoopsObject
110
    {
111 2
        return $this->tree[$key]['obj'];
112
    }
113
114
    /**
115
     * returns an array of all the first child object of an object specified by its id
116
     *
117
     * @param  string $key ID of the parent object
118
     * @return array  Array of children of the parent
119
     */
120
    public function getFirstChild($key): array
121
    {
122
        $ret = [];
123
        if (isset($this->tree[$key]['child'])) {
124
            foreach ($this->tree[$key]['child'] as $childKey) {
125
                $ret[$childKey] = $this->tree[$childKey]['obj'];
126
            }
127
        }
128
        return $ret;
129
    }
130
131
    /**
132
     * returns an array of all child objects of an object specified by its id
133
     *
134
     * @param  string $key ID of the parent
135
     * @param  array  $ret (Empty when called from client) Array of children from previous recursions.
136
     * @return array  Array of child nodes.
137
     */
138
    public function getAllChild($key, $ret = []): array
139
    {
140
        if (isset($this->tree[$key]['child'])) {
141
            foreach ($this->tree[$key]['child'] as $childKey) {
142
                $ret[$childKey] = $this->tree[$childKey]['obj'];
143
                $children       = $this->getAllChild($childKey, $ret);
144
                foreach (array_keys($children) as $newKey) {
145
                    $ret[$newKey] = $children[$newKey];
146
                }
147
            }
148
        }
149
        return $ret;
150
    }
151
152
    /**
153
     * returns an array of all parent objects.
154
     * the key of returned array represents how many levels up from the specified object
155
     *
156
     * @param  int   $key     ID of the child object
157
     * @param  array $ret     (empty when called from outside) Result from previous recursions
158
     * @param  int   $upLevel (empty when called from outside) level of recursion
159
     * @return array Array of parent nodes.
160
     */
161 1
    public function getAllParent($key, $ret = [], $upLevel = 1): array
162
    {
163 1
        if (isset($this->tree[$key]['parent']) && isset($this->tree[$this->tree[$key]['parent']]['obj'])) {
164 1
            $ret[$upLevel] = $this->tree[$this->tree[$key]['parent']]['obj'];
165 1
            $parents       = $this->getAllParent($this->tree[$key]['parent'], $ret, $upLevel + 1);
166 1
            foreach (array_keys($parents) as $newKey) {
167 1
                $ret[$newKey] = $parents[$newKey];
168
            }
169
        }
170 1
        return $ret;
171
    }
172
173
    /**
174
     * Make a select box with options from the tree
175
     *
176
     * This replaces makeSelectElement(). The parameters follow the Select element first, followed
177
     * by the tree descriptions.
178
     *
179
     * The $extra parameter has been removed, as setExtra() is deprecated. Please use the Select
180
     * object's attributes to add any required script for event handlers such as 'onSelect'.
181
     *
182
     * @param  string $caption        optional caption for form element
183
     * @param  string $name           Name of the select box
184
     * @param  string $selected       Value to display as selected
185
     * @param  string $fieldName      Name of the member variable from the
186
     *                                node objects that should be used as the title for the options.
187
     * @param  string $prefix         String to indent deeper levels
188
     * @param  bool   $addEmptyOption Set TRUE to add an empty option with value "0" at the top of the hierarchy
189
     * @param  int    $key            ID of the object to display as the root of select options
190
     *
191
     * @return Select form element
192
     */
193
    public function makeSelect(
194
        string $caption,
195
        string $name,
196
        string $selected,
197
        string $fieldName,
198
        string $prefix = '-',
199
        bool $addEmptyOption = false,
200
        int $key = 0
201
    ): Select {
202
        $element = new Select($caption, $name, $selected);
203
204
        if (false !== $addEmptyOption) {
205
            $element->addOption('0', ' ');
206
        }
207
        $this->addSelectOptions($element, $fieldName, $key, $prefix);
208
209
        return $element;
210
    }
211
212
    /**
213
     * Make options for a select box from
214
     *
215
     * @param Select $element     form element to receive tree values as options
216
     * @param string $fieldName   Name of the member variable from the node objects that
217
     *                            should be used as the title for the options.
218
     * @param int    $key         ID of the object to display as the root of select options
219
     * @param string $prefix_orig String to indent items at deeper levels
220
     * @param string $prefix_curr String to indent the current item
221
     *
222
     * @return void
223
     */
224
    protected function addSelectOptions(
225
        Select $element,
226
        string $fieldName,
227
        int $key,
228
        string $prefix_orig,
229
        string $prefix_curr = ''
230
    ): void {
231
        if ($key > 0) {
232
            $value = $this->tree[$key]['obj']->getVar($this->myId);
233
            $name = $prefix_curr . $this->tree[$key]['obj']->getVar($fieldName);
234
            $element->addOption($value, $name);
235
            $prefix_curr .= $prefix_orig;
236
        }
237
        if (isset($this->tree[$key]['child']) && !empty($this->tree[$key]['child'])) {
238
            foreach ($this->tree[$key]['child'] as $childKey) {
239
                $this->addSelectOptions($element, $fieldName, $childKey, $prefix_orig, $prefix_curr);
240
            }
241
        }
242
    }
243
}
244