## Apache Zeta Components Manual :: File Source for db_parent_child.php

## Source for file db_parent_child.php

Documentation is available at db_parent_child.php

1. <?php
2. /**
3. * File containing the ezcTreeDbParentChild class.
4. *
5. * Licensed to the Apache Software Foundation (ASF) under one
6. * or more contributor license agreements. See the NOTICE file
7. * distributed with this work for additional information
8. * regarding copyright ownership. The ASF licenses this file
9. * to you under the Apache License, Version 2.0 (the
10. * "License"); you may not use this file except in compliance
11. * with the License. You may obtain a copy of the License at
12. *
13. * http://www.apache.org/licenses/LICENSE-2.0
14. *
15. * Unless required by applicable law or agreed to in writing,
16. * software distributed under the License is distributed on an
17. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18. * KIND, either express or implied. See the License for the
19. * specific language governing permissions and limitations
20. * under the License.
21. *
22. * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
23. * @version //autogentag//
24. * @filesource
25. * @package TreeDatabaseTiein
26. */
28. /**
29. * ezcTreeDbParentChild implements a tree backend which stores parent/child
30. * information in a simple table containing the node's ID and its parent's ID.
31. *
32. * The table that stores the index (configured using the $indexTableName argument
33. * of the {@link __construct} method) should contain at least two fields. The
34. * first one 'id' will contain the node's ID, the second one 'parent_id' the ID
35. * of the node's parent. Both fields should be of the same database field type.
36. * Supported field types are either integer or a string type.
37. * In order to use auto-generated IDs, the 'id' field needs to be an
38. * auto-incrementing integer field, by using either an auto-increment field, or
39. * a sequence.
40. *
41. * @property-read ezcTreeDbDataStore $store
42. * The data store that is used for retrieving/storing data.
43. * @property string $nodeClassName
44. * Which class is used as tree node - this class *must* inherit
45. * the ezcTreeNode class.
46. *
47. * @package TreeDatabaseTiein
48. * @version //autogentag//
49. * @mainclass
50. */
51. class ezcTreeDbParentChild extends ezcTreeDb
52. {
53. /**
54. * Creates a new ezcTreeDbParentChild object.
55. *
56. * The different arguments to the method configure which database
57. * connection ($dbh) is used to access the database and the $indexTableName
58. * argument which table is used to retrieve the relation data from. The
59. * $store argument configure which data store is used with this tree.
60. *
61. * It is up to the user to create the database table and make sure it is
62. * empty.
63. *
64. * @param ezcDbHandler $dbh
65. * @param string $indexTableName
66. * @param ezcTreeDbDataStore $store
67. */
68. public static function create ( ezcDbHandler $dbh, $indexTableName, ezcTreeDbDataStore $store )
69. {
70. return new ezcTreeDbParentChild ( $dbh, $indexTableName, $store );
71. }
73. /**
74. * Runs SQL to get all the children of the node with ID $nodeId as a PDO
75. * result set.
76. *
77. * @param string $nodeId
78. * @return PDOStatement
79. */
80. protected function fetchChildRecords ( $nodeId )
81. {
82. $db = $this-> dbh ;
83. $q = $db->createSelectQuery();
85. // SELECT id, parent_id
86. // FROM indexTable
87. // WHERE parent_id = $nodeId
88. $q->select( 'id, parent_id' )
89. ->from( $db->quoteIdentifier( $this-> indexTableName ) )
90. ->where( $q->expr->eq( 'parent_id', $q->bindValue( $nodeId ) ) );
92. $s = $q->prepare();
93. $s->execute();
94. return $s;
95. }
97. /**
98. * Adds the children nodes of the node with ID $nodeId to the
99. * ezcTreeNodeList $list.
100. *
101. * @param ezcTreeNodeList $list
102. * @param string $nodeId
103. */
104. private function addChildNodesDepthFirst( ezcTreeNodeList $list, $nodeId )
105. {
106. $className = $this-> properties ['nodeClassName'];
107. foreach ( $this-> fetchChildRecords ( $nodeId ) as $record )
108. {
109. $list->addNode( new $className( $this, $record['id'] ) );
110. $this->addChildNodesDepthFirst( $list, $record['id'] );
111. }
112. }
114. /**
115. * Returns all the children of the node with ID $nodeId.
116. *
117. * @param string $nodeId
118. * @return ezcTreeNodeList
119. */
120. public function fetchChildren ( $nodeId )
121. {
122. $className = $this-> properties ['nodeClassName'];
123. $list = new ezcTreeNodeList ;
124. foreach ( $this-> fetchChildRecords ( $nodeId ) as $record )
125. {
126. $list->addNode( new $className( $this, $record['id'] ) );
127. }
128. return $list;
129. }
131. /**
132. * Returns all the nodes in the path from the root node to the node with ID
133. * $nodeId, including those two nodes.
134. *
135. * @param string $nodeId
136. * @return ezcTreeNodeList
137. */
138. public function fetchPath ( $nodeId )
139. {
140. $className = $this-> properties ['nodeClassName'];
142. $nodes = array();
143. $nodes[] = new $className( $this, $nodeId );
145. $nodeId = $this-> getParentId ( $nodeId );
147. while ( $nodeId != null )
148. {
149. $nodes[] = new $className( $this, $nodeId );
150. $nodeId = $this-> getParentId ( $nodeId );
151. }
153. $list = new ezcTreeNodeList ;
154. foreach ( array_reverse ( $nodes ) as $node )
155. {
156. $list->addNode( $node );
157. }
158. return $list;
159. }
161. /**
162. * Returns the node with ID $nodeId and all its children, sorted according to
163. * the {@link http://en.wikipedia.org/wiki/Depth-first_search Depth-first sorting}
164. * algorithm.
165. *
166. * @param string $nodeId
167. * @return ezcTreeNodeList
168. */
169. public function fetchSubtreeDepthFirst ( $nodeId )
170. {
171. $className = $this-> properties ['nodeClassName'];
172. $list = new ezcTreeNodeList ;
173. $list->addNode( new $className( $this, $nodeId ) );
174. $this->addChildNodesDepthFirst( $list, $nodeId );
175. return $list;
176. }
178. /**
179. * Alias for fetchSubtreeDepthFirst().
180. *
181. * @param string $nodeId
182. * @return ezcTreeNodeList
183. */
184. public function fetchSubtree ( $nodeId )
185. {
186. return $this-> fetchSubtreeDepthFirst ( $nodeId );
187. }
189. /**
190. * Adds the children nodes of the node with ID $nodeId to the
191. * ezcTreeNodeList $list.
192. *
193. * @param ezcTreeNodeList $list
194. * @param string $nodeId
195. */
196. protected function addChildNodesBreadthFirst ( ezcTreeNodeList $list, $nodeId )
197. {
198. $className = $this-> properties ['nodeClassName'];
199. $childRecords = $this-> fetchChildRecords ( $nodeId )->fetchAll();
200. foreach ( $childRecords as $record )
201. {
202. $list->addNode( new $className( $this, $record['id'] ) );
203. }
204. foreach ( $childRecords as $record )
205. {
206. $this-> addChildNodesBreadthFirst ( $list, $record['id'] );
207. }
208. }
210. /**
211. * Returns the node with ID $nodeId and all its children, sorted according to
212. * the {@link http://en.wikipedia.org/wiki/Breadth-first_search Breadth-first sorting}
213. * algorithm.
214. *
215. * @param string $nodeId
216. * @return ezcTreeNodeList
217. */
218. public function fetchSubtreeBreadthFirst ( $nodeId )
219. {
220. $className = $this-> properties ['nodeClassName'];
221. $list = new ezcTreeNodeList ;
222. $list->addNode( new $className( $this, $nodeId ) );
223. $this-> addChildNodesBreadthFirst ( $list, $nodeId );
224. return $list;
225. }
227. /**
228. * Returns the number of direct children of the node with ID $nodeId.
229. *
230. * @param string $nodeId
231. * @return int
232. */
233. public function getChildCount ( $nodeId )
234. {
235. $db = $this-> dbh ;
236. $q = $db->createSelectQuery();
238. // SELECT count(id)
239. // FROM indexTable
240. // WHERE parent_id = $nodeId
241. $q->select( 'count(id)' )
242. ->from( $db->quoteIdentifier( $this-> indexTableName ) )
243. ->where( $q->expr->eq( 'parent_id', $q->bindValue( $nodeId ) ) );
245. $s = $q->prepare();
246. $s->execute();
247. return (int) $s->fetchColumn( 0 );
248. }
250. /**
251. * Adds the number of children with for the node with ID $nodeId nodes to
252. * $count, recursively.
253. *
254. * @param int $count
255. * @param string $nodeId
256. */
257. protected function countChildNodes ( &$count, $nodeId )
258. {
259. foreach ( $this-> fetchChildRecords ( $nodeId ) as $record )
260. {
261. $count++;
262. $this-> countChildNodes ( $count, $record['id'] );
263. }
264. }
266. /**
267. * Returns the number of children of the node with ID $nodeId, recursively.
268. *
269. * @param string $nodeId
270. * @return int
271. */
272. public function getChildCountRecursive ( $nodeId )
273. {
274. $count = 0;
275. $this-> countChildNodes ( $count, $nodeId );
276. return $count;
277. }
279. /**
280. * Returns the distance from the root node to the node with ID $nodeId.
281. *
282. * @param string $nodeId
283. * @return int
284. */
285. public function getPathLength ( $nodeId )
286. {
287. $nodeId = $this-> getParentId ( $nodeId );
288. $length = 0;
290. while ( $nodeId !== null )
291. {
292. $nodeId = $this-> getParentId ( $nodeId );
293. $length++;
294. }
295. return $length;
296. }
298. /**
299. * Returns whether the node with ID $nodeId has children.
300. *
301. * @param string $nodeId
302. * @return bool
303. */
304. public function hasChildNodes ( $nodeId )
305. {
306. return $this-> getChildCount ( $nodeId ) > 0;
307. }
309. /**
310. * Returns whether the node with ID $childId is a direct child of the node
311. * with ID $parentId.
312. *
313. * @param string $childId
314. * @param string $parentId
315. * @return bool
316. */
317. public function isChildOf ( $childId, $parentId )
318. {
319. $nodeId = $this-> getParentId ( $childId );
320. $parentId = (string) $parentId;
321. return $parentId === $nodeId;
322. }
324. /**
325. * Returns whether the node with ID $childId is a direct or indirect child
326. * of the node with ID $parentId.
327. *
328. * @param string $childId
329. * @param string $parentId
330. * @return bool
331. */
332. public function isDescendantOf ( $childId, $parentId )
333. {
334. $parentId = (string) $parentId;
335. $nodeId = $childId;
336. do
337. {
338. $nodeId = $this-> getParentId ( $nodeId );
339. if ( $parentId === $nodeId )
340. {
341. return true;
342. }
343. } while ( $nodeId !== null );
344. return false;
345. }
347. /**
348. * Returns whether the nodes with IDs $child1Id and $child2Id are siblings
349. * (ie, they share the same parent).
350. *
351. * @param string $child1Id
352. * @param string $child2Id
353. * @return bool
354. */
355. public function isSiblingOf ( $child1Id, $child2Id )
356. {
357. $nodeId1 = $this-> getParentId ( $child1Id );
358. $nodeId2 = $this-> getParentId ( $child2Id );
359. return $nodeId1 === $nodeId2 && (string) $child1Id !== (string) $child2Id;
360. }
362. /**
363. * Sets a new node as root node, this also wipes out the whole tree.
364. *
365. * @param ezcTreeNode $node
366. */
367. public function setRootNode ( ezcTreeNode $node )
368. {
369. $db = $this-> dbh ;
371. $q = $db->createDeleteQuery();
372. $q->deleteFrom( $db->quoteIdentifier( $this-> indexTableName ) );
373. $s = $q->prepare();
374. $s->execute();
375. $this->store->deleteDataForAllNodes();
377. $q = $db->createInsertQuery();
378. $q->insertInto( $db->quoteIdentifier( $this-> indexTableName ) )
379. ->set( 'parent_id', "null" )
380. ->set( 'id', $q->bindValue( $node->id ) );
381. $s = $q->prepare();
382. $s->execute();
384. $this->store->storeDataForNode( $node, $node->data );
385. }
387. /**
388. * Creates the query to insert an empty node into the database, so that the last-inserted ID can be obtained.
389. *
390. * @return ezcQueryInsert
391. */
392. protected function createAddEmptyNodeQuery ()
393. {
394. $db = $this-> dbh ;
396. $q = $db->createInsertQuery();
397. $q->insertInto( $db->quoteIdentifier( $this-> indexTableName ) )
398. ->set( 'parent_id', $q->bindValue( null ) );
400. return $q;
401. }
403. /**
404. * Adds the node $childNode as child of the node with ID $parentId.
405. *
406. * @param string $parentId
407. * @param ezcTreeNode $childNode
408. */
409. public function addChild ( $parentId, ezcTreeNode $childNode )
410. {
411. if ( $this-> inTransaction )
412. {
413. $this-> addTransactionItem ( new ezcTreeTransactionItem( ezcTreeTransactionItem::ADD, $childNode, null, $parentId ) );
414. return;
415. }
417. $q = $this-> createAddNodeQuery ( $childNode->id );
418. $q->set( 'parent_id', $q->bindValue( $parentId ) )
419. ->set( 'id', $q->bindValue( $childNode->id ) );
420. $s = $q->prepare();
421. $s->execute();
423. $this->store->storeDataForNode( $childNode, $childNode->data );
424. }
426. /**
427. * Deletes all nodes in the node list $list.
428. *
429. * @param ezcTreeNodeList $list
430. */
431. private function deleteNodes( ezcTreeNodeList $list )
432. {
433. $db = $this-> dbh ;
434. $q = $db->createDeleteQuery();
436. $nodeIdList = array();
437. foreach ( array_keys ( $list->nodes ) as $nodeId )
438. {
439. $nodeIdList[] = (string) $nodeId;
440. }
442. // DELETE FROM indexTable
443. // WHERE id in ( $list );
444. $q->deleteFrom( $db->quoteIdentifier( $this-> indexTableName ) );
445. $q->where( $q->expr->in( 'id', $nodeIdList ) );
446. $s = $q->prepare();
447. $s->execute();
448. }
450. /**
451. * Deletes the node with ID $nodeId from the tree, including all its children.
452. *
453. * @param string $nodeId
454. */
455. public function delete ( $nodeId )
456. {
457. if ( $this-> inTransaction )
458. {
459. $this-> addTransactionItem ( new ezcTreeTransactionItem( ezcTreeTransactionItem::DELETE, null, $nodeId ) );
460. return;
461. }
463. $nodeList = $this-> fetchSubtree ( $nodeId );
464. $this->deleteNodes( $nodeList );
465. $this->store->deleteDataForNodes( $nodeList );
466. }
468. /**
469. * Moves the node with ID $nodeId as child to the node with ID $targetParentId.
470. *
471. * @param string $nodeId
472. * @param string $targetParentId
473. */
474. public function move ( $nodeId, $targetParentId )
475. {
476. if ( $this-> inTransaction )
477. {
478. $this-> addTransactionItem ( new ezcTreeTransactionItem( ezcTreeTransactionItem::MOVE, null, $nodeId, $targetParentId ) );
479. return;
480. }
482. $db = $this-> dbh ;
483. $q = $db->createUpdateQuery();
485. $q->update( $db->quoteIdentifier( $this-> indexTableName ) )
486. ->set( 'parent_id', $q->bindValue( $targetParentId ) )
487. ->where( $q->expr->eq( 'id', $q->bindValue( $nodeId ) ) );
489. $s = $q->prepare();
490. $s->execute();
491. }
493. /**
494. * Fixates the transaction.
495. */
496. public function fixateTransaction ()
497. {
498. }
499. }
500. ?>

Documentation generated by phpDocumentor 1.4.3