1: <?php
2: /*
3: You may not change or alter any portion of this comment or credits
4: of supporting developers from this source code or any supporting source code
5: which is considered copyrighted (c) material of the original comment or credit authors.
6:
7: This program is distributed in the hope that it will be useful,
8: but WITHOUT ANY WARRANTY; without even the implied warranty of
9: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10: */
11:
12: /**
13: * XOOPS tree class
14: *
15: * @copyright XOOPS Project (http://xoops.org)
16: * @license GNU GPL 2 or later (http://www.gnu.org/licenses/gpl-2.0.html)
17: * @package class
18: * @since 2.0.0
19: * @author Kazumi Ono (http://www.myweb.ne.jp/, http://jp.xoops.org/)
20: * @version $Id$
21: */
22:
23: /**
24: * A tree structures with {@link XoopsObject}s as nodes
25: *
26: * @package kernel
27: * @subpackage core
28: * @author Kazumi Ono <onokazu@xoops.org>
29: */
30: class XoopsObjectTree
31: {
32: /**
33: * @var string
34: */
35: private $_parentId;
36:
37: /**
38: * @var string
39: */
40: private $_myId;
41:
42: /**
43: * @var null|string
44: */
45: private $_rootId = null;
46:
47: /**
48: * @var array
49: */
50: private $_tree = array();
51:
52: /**
53: * @var array
54: */
55: private $_objects;
56:
57: /**
58: * Constructor
59: *
60: * @param array $objectArr Array of {@link XoopsObject}s
61: * @param string $myId field name of object ID
62: * @param string $parentId field name of parent object ID
63: * @param string $rootId field name of root object ID
64: */
65: public function __construct(&$objectArr, $myId, $parentId, $rootId = null)
66: {
67: $this->_objects = $objectArr;
68: $this->_myId = $myId;
69: $this->_parentId = $parentId;
70: if (isset($rootId)) {
71: $this->_rootId = $rootId;
72: }
73: $this->_initialize();
74: }
75:
76: /**
77: * Initialize the object
78: *
79: * @access private
80: */
81: private function _initialize()
82: {
83: /* @var $object XoopsObject */
84: foreach ($this->_objects as $object) {
85: $key1 = $object->getVar($this->_myId);
86: $this->_tree[$key1]['obj'] = $object;
87: $key2 = $object->getVar($this->_parentId);
88: $this->_tree[$key1]['parent'] = $key2;
89: $this->_tree[$key2]['child'][] = $key1;
90: if (isset($this->_rootId)) {
91: $this->_tree[$key1]['root'] = $object->getVar($this->_rootId);
92: }
93: }
94: }
95:
96: /**
97: * Get the tree
98: *
99: * @return array Associative array comprising the tree
100: */
101: public function getTree()
102: {
103: return $this->_tree;
104: }
105:
106: /**
107: * returns an object from the tree specified by its id
108: *
109: * @param string $key ID of the object to retrieve
110: * @return object Object within the tree
111: */
112: public function getByKey($key)
113: {
114: return $this->_tree[$key]['obj'];
115: }
116:
117: /**
118: * returns an array of all the first child object of an object specified by its id
119: *
120: * @param string $key ID of the parent object
121: * @return array Array of children of the parent
122: */
123: public function getFirstChild($key)
124: {
125: $ret = array();
126: if (isset($this->_tree[$key]['child'])) {
127: foreach ($this->_tree[$key]['child'] as $childkey) {
128: $ret[$childkey] = $this->_tree[$childkey]['obj'];
129: }
130: }
131: return $ret;
132: }
133:
134: /**
135: * returns an array of all child objects of an object specified by its id
136: *
137: * @param string $key ID of the parent
138: * @param array $ret (Empty when called from client) Array of children from previous recursions.
139: * @return array Array of child nodes.
140: */
141: public function getAllChild($key, $ret = array())
142: {
143: if (isset($this->_tree[$key]['child'])) {
144: foreach ($this->_tree[$key]['child'] as $childkey) {
145: $ret[$childkey] = $this->_tree[$childkey]['obj'];
146: $children = $this->getAllChild($childkey, $ret);
147: foreach (array_keys($children) as $newkey) {
148: $ret[$newkey] = $children[$newkey];
149: }
150: }
151: }
152: return $ret;
153: }
154:
155: /**
156: * returns an array of all parent objects.
157: * the key of returned array represents how many levels up from the specified object
158: *
159: * @param string $key ID of the child object
160: * @param array $ret (empty when called from outside) Result from previous recursions
161: * @param int $uplevel (empty when called from outside) level of recursion
162: * @return array Array of parent nodes.
163: */
164: public function getAllParent($key, $ret = array(), $uplevel = 1)
165: {
166: if (isset($this->_tree[$key]['parent']) && isset($this->_tree[$this->_tree[$key]['parent']]['obj'])) {
167: $ret[$uplevel] = $this->_tree[$this->_tree[$key]['parent']]['obj'];
168: $parents = $this->getAllParent($this->_tree[$key]['parent'], $ret, $uplevel + 1);
169: foreach (array_keys($parents) as $newkey) {
170: $ret[$newkey] = $parents[$newkey];
171: }
172: }
173: return $ret;
174: }
175:
176: /**
177: * Make options for a select box from
178: *
179: * @param string $fieldName Name of the member variable from the
180: * node objects that should be used as the title for the options.
181: * @param string $selected Value to display as selected
182: * @param int $key ID of the object to display as the root of select options
183: * @param string $ret (reference to a string when called from outside) Result from previous recursions
184: * @param string $prefix_orig String to indent items at deeper levels
185: * @param string $prefix_curr String to indent the current item
186: *
187: * @return void
188: */
189: private function _makeSelBoxOptions($fieldName, $selected, $key, &$ret, $prefix_orig, $prefix_curr = '')
190: {
191: if ($key > 0) {
192: /* @var $object XoopsObject */
193: $object = $this->_tree[$key]['obj'];
194: $value = $object->getVar($this->_myId);
195: $ret .= '<option value="' . $value . '"';
196: if ($value == $selected) {
197: $ret .= ' selected="selected"';
198: }
199: $ret .= '>' . $prefix_curr . $object->getVar($fieldName) . '</option>';
200: $prefix_curr .= $prefix_orig;
201: }
202: if (isset($this->_tree[$key]['child']) && !empty($this->_tree[$key]['child'])) {
203: foreach ($this->_tree[$key]['child'] as $childkey) {
204: $this->_makeSelBoxOptions($fieldName, $selected, $childkey, $ret, $prefix_orig, $prefix_curr);
205: }
206: }
207: }
208:
209: /**
210: * Make a select box with options from the tree
211: *
212: * @param string $fieldName Name of the member variable from the
213: * node objects that should be used as the title for the options.
214: * @param string $prefix String to indent deeper levels
215: * @param string $selected Value to display as selected
216: * @param bool $addEmptyOption Set TRUE to add an empty option with value "0" at the top of the hierarchy
217: * @param integer $key ID of the object to display as the root of select options
218: * @param string $extra
219: * @param string $name
220: * @return string HTML select box
221: */
222: public function makeSelBox($name, $fieldName, $prefix = '-', $selected = '', $addEmptyOption = false, $key = 0, $extra = '')
223: {
224: $ret = '<select name="' . $name . '" id="' . $name . '" ' . $extra . '>';
225: if (false != $addEmptyOption) {
226: $ret .= '<option value="0"></option>';
227: }
228: $this->_makeSelBoxOptions($fieldName, $selected, $key, $ret, $prefix);
229: return $ret . '</select>';
230: }
231:
232: /**
233: * Make options for a array
234: *
235: * @param string $fieldName Name of the member variable from the
236: * node objects that should be used as the column.
237: * @param string $prefix String to indent deeper levels
238: * @param integer $key ID of the object to display as the root of the array
239: * @return array
240: */
241: public function makeArrayTree( $fieldName, $prefix = '-', $key = 0) {
242: $ret = array();
243: $this->_makeArrayTreeOptions( $fieldName, $key, $ret, $prefix );
244: return $ret;
245: }
246:
247: /**
248: * Make a array with options from the tree
249: *
250: * @param string $fieldName Name of the member variable from the
251: * node objects that should be used as the column.
252: * @param integer $key ID of the object to display as the root of the array
253: * @param string $prefix_orig String to indent deeper levels (origin)
254: * @param string $prefix_curr String to indent deeper levels (current)
255: *
256: * @return void
257: */
258: public function _makeArrayTreeOptions( $fieldName, $key, &$ret, $prefix_orig, $prefix_curr = '' ) {
259: if ( $key > 0 ) {
260: $value = $this->_tree[$key]['obj']->getVar( $this->_myId );
261: $ret[$value] = $prefix_curr . $this->_tree[$key]['obj']->getVar( $fieldName );
262: $prefix_curr .= $prefix_orig;
263:
264: }
265: if ( isset( $this->_tree[$key]['child'] ) && !empty( $this->_tree[$key]['child'] ) ) {
266: foreach ( $this->_tree[$key]['child'] as $childkey ) {
267: $this->_makeArrayTreeOptions( $fieldName, $childkey, $ret, $prefix_orig, $prefix_curr );
268: }
269: }
270: }
271: }
272: