PageRenderTime 23ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/generator/lib/builder/om/PHP5NodePeerBuilder.php

https://github.com/1989gaurav/Propel
PHP | 751 lines | 398 code | 109 blank | 244 comment | 30 complexity | 962c3c547494bb22ee8d772f8cbc1348 MD5 | raw file
  1. <?php
  2. /**
  3. * This file is part of the Propel package.
  4. * For the full copyright and license information, please view the LICENSE
  5. * file that was distributed with this source code.
  6. *
  7. * @license MIT License
  8. */
  9. require_once dirname(__FILE__) . '/PeerBuilder.php';
  10. /**
  11. * Generates a PHP5 tree node Peer class for user object model (OM).
  12. *
  13. * This class produces the base tree node object class (e.g. BaseMyTable) which contains all
  14. * the custom-built accessor and setter methods.
  15. *
  16. * @author Hans Lellelid <hans@xmpl.org>
  17. * @package propel.generator.builder.om
  18. */
  19. class PHP5NodePeerBuilder extends PeerBuilder
  20. {
  21. /**
  22. * Gets the package for the [base] object classes.
  23. * @return string
  24. */
  25. public function getPackage()
  26. {
  27. return parent::getPackage() . ".om";
  28. }
  29. /**
  30. * Returns the name of the current class being built.
  31. * @return string
  32. */
  33. public function getUnprefixedClassname()
  34. {
  35. return $this->getBuildProperty('basePrefix') . $this->getStubNodePeerBuilder()->getUnprefixedClassname();
  36. }
  37. /**
  38. * Adds the include() statements for files that this class depends on or utilizes.
  39. * @param string &$script The script will be modified in this method.
  40. */
  41. protected function addIncludes(&$script)
  42. {
  43. } // addIncludes()
  44. /**
  45. * Adds class phpdoc comment and openning of class.
  46. * @param string &$script The script will be modified in this method.
  47. */
  48. protected function addClassOpen(&$script)
  49. {
  50. $table = $this->getTable();
  51. $tableName = $table->getName();
  52. $tableDesc = $table->getDescription();
  53. $script .= "
  54. /**
  55. * Base static class for performing query operations on the tree contained by the '$tableName' table.
  56. *
  57. * $tableDesc
  58. *";
  59. if ($this->getBuildProperty('addTimeStamp')) {
  60. $now = strftime('%c');
  61. $script .= "
  62. * This class was autogenerated by Propel " . $this->getBuildProperty('version') . " on:
  63. *
  64. * $now
  65. *";
  66. }
  67. $script .= "
  68. * @package propel.generator.".$this->getPackage()."
  69. */
  70. abstract class ".$this->getClassname()." {
  71. ";
  72. }
  73. /**
  74. * Specifies the methods that are added as part of the basic OM class.
  75. * This can be overridden by subclasses that wish to add more methods.
  76. * @see ObjectBuilder::addClassBody()
  77. */
  78. protected function addClassBody(&$script)
  79. {
  80. $table = $this->getTable();
  81. // FIXME
  82. // - Probably the build needs to be customized for supporting
  83. // tables that are "aliases". -- definitely a fringe usecase, though.
  84. $this->addConstants($script);
  85. $this->addIsCodeBase($script);
  86. $this->addRetrieveMethods($script);
  87. $this->addCreateNewRootNode($script);
  88. $this->addInsertNewRootNode($script);
  89. $this->addMoveNodeSubTree($script);
  90. $this->addDeleteNodeSubTree($script);
  91. $this->addBuildFamilyCriteria($script);
  92. $this->addBuildTree($script);
  93. $this->addPopulateNodes($script);
  94. }
  95. /**
  96. * Closes class.
  97. * @param string &$script The script will be modified in this method.
  98. */
  99. protected function addClassClose(&$script)
  100. {
  101. $script .= "
  102. } // " . $this->getClassname() . "
  103. ";
  104. }
  105. protected function addConstants(&$script)
  106. {
  107. $table = $this->getTable();
  108. $npath_colname = '';
  109. $npath_phpname = '';
  110. $npath_len = 0;
  111. $npath_sep = '';
  112. foreach ($table->getColumns() as $col) {
  113. if ($col->isNodeKey()) {
  114. $npath_colname = $table->getName() . '.' . strtoupper($col->getName());
  115. $npath_phpname = $col->getPhpName();
  116. $npath_len = $col->getSize();
  117. $npath_sep = $col->getNodeKeySep();
  118. break;
  119. }
  120. }
  121. $script .= "
  122. const NPATH_COLNAME = '$npath_colname';
  123. const NPATH_PHPNAME = '$npath_phpname';
  124. const NPATH_SEP = '$npath_sep';
  125. const NPATH_LEN = $npath_len;
  126. ";
  127. }
  128. protected function addIsCodeBase(&$script)
  129. {
  130. $peerClassname = $this->getStubPeerBuilder()->getClassname();
  131. $nodePeerClassname = $this->getStubNodePeerBuilder()->getClassname();
  132. $script .= "
  133. /**
  134. * Temp function for CodeBase hacks that will go away.
  135. */
  136. public static function isCodeBase(\$con = null)
  137. {
  138. if (\$con === null)
  139. \$con = Propel::getConnection($peerClassname::DATABASE_NAME);
  140. return (get_class(\$con) == 'ODBCConnection' &&
  141. get_class(\$con->getAdapter()) == 'CodeBaseAdapter');
  142. }
  143. ";
  144. }
  145. protected function addCreateNewRootNode(&$script)
  146. {
  147. $peerClassname = $this->getStubPeerBuilder()->getClassname();
  148. $objectClassname = $this->getStubObjectBuilder()->getClassname();
  149. $nodePeerClassname = $this->getStubNodePeerBuilder()->getClassname();
  150. $nodeObjectClassname = $this->getStubNodeBuilder()->getClassname();
  151. $script .= "
  152. /**
  153. * Create a new Node at the top of tree. This method will destroy any
  154. * existing root node (along with its children).
  155. *
  156. * Use at your own risk!
  157. *
  158. * @param $objectClassname Object wrapped by new node.
  159. * @param PropelPDO Connection to use.
  160. * @return $nodeObjectClassname
  161. * @throws PropelException
  162. */
  163. public static function createNewRootNode(\$obj, PropelPDO \$con = null)
  164. {
  165. if (\$con === null)
  166. \$con = Propel::getConnection($peerClassname::DATABASE_NAME, Propel::CONNECTION_WRITE);
  167. \$con->beginTransaction();
  168. try {
  169. self::deleteNodeSubTree('1', \$con);
  170. \$setNodePath = 'set' . self::NPATH_PHPNAME;
  171. \$obj->\$setNodePath('1');
  172. \$obj->save(\$con);
  173. \$con->commit();
  174. } catch (PropelException \$e) {
  175. \$con->rollBack();
  176. throw \$e;
  177. }
  178. return new $nodeObjectClassname(\$obj);
  179. }
  180. ";
  181. }
  182. protected function addInsertNewRootNode(&$script)
  183. {
  184. $peerClassname = $this->getStubPeerBuilder()->getClassname();
  185. $objectClassname = $this->getStubObjectBuilder()->getClassname();
  186. $nodePeerClassname = $this->getStubNodePeerBuilder()->getClassname();
  187. $nodeObjectClassname = $this->getStubNodeBuilder()->getClassname();
  188. $script .= "
  189. /**
  190. * Inserts a new Node at the top of tree. Any existing root node (along with
  191. * its children) will be made a child of the new root node. This is a
  192. * safer alternative to createNewRootNode().
  193. *
  194. * @param $objectClassname Object wrapped by new node.
  195. * @param PropelPDO Connection to use.
  196. * @return $nodeObjectClassname
  197. * @throws PropelException
  198. */
  199. public static function insertNewRootNode(\$obj, PropelPDO \$con = null)
  200. {
  201. if (\$con === null)
  202. \$con = Propel::getConnection($peerClassname::DATABASE_NAME, Propel::CONNECTION_WRITE);
  203. \$con->beginTransaction();
  204. try {
  205. // Move root tree to an invalid node path.
  206. $nodePeerClassname::moveNodeSubTree('1', '0', \$con);
  207. \$setNodePath = 'set' . self::NPATH_PHPNAME;
  208. // Insert the new root node.
  209. \$obj->\$setNodePath('1');
  210. \$obj->save(\$con);
  211. // Move the old root tree as a child of the new root.
  212. $nodePeerClassname::moveNodeSubTree('0', '1' . self::NPATH_SEP . '1', \$con);
  213. \$con->commit();
  214. } catch (PropelException \$e) {
  215. \$con->rollBack();
  216. throw \$e;
  217. }
  218. return new $nodeObjectClassname(\$obj);
  219. }
  220. ";
  221. }
  222. /**
  223. * Adds the methods for retrieving nodes.
  224. */
  225. protected function addRetrieveMethods(&$script)
  226. {
  227. $this->addRetrieveNodes($script);
  228. $this->addRetrieveNodeByPK($script);
  229. $this->addRetrieveNodeByNP($script);
  230. $this->addRetrieveRootNode($script);
  231. }
  232. protected function addRetrieveNodes(&$script)
  233. {
  234. $peerClassname = $this->getStubPeerBuilder()->getClassname();
  235. $nodePeerClassname = $this->getStubNodePeerBuilder()->getClassname();
  236. $script .= "
  237. /**
  238. * Retrieves an array of tree nodes based on specified criteria. Optionally
  239. * includes all parent and/or child nodes of the matching nodes.
  240. *
  241. * @param Criteria Criteria to use.
  242. * @param boolean True if ancestors should also be retrieved.
  243. * @param boolean True if descendants should also be retrieved.
  244. * @param PropelPDO Connection to use.
  245. * @return array Array of root nodes.
  246. */
  247. public static function retrieveNodes(\$criteria, \$ancestors = false, \$descendants = false, PropelPDO \$con = null)
  248. {
  249. \$criteria = $nodePeerClassname::buildFamilyCriteria(\$criteria, \$ancestors, \$descendants);
  250. \$stmt = ".$this->getStubPeerBuilder()->getClassname()."::doSelectStmt(\$criteria, \$con);
  251. return self::populateNodes(\$stmt, \$criteria);
  252. }
  253. ";
  254. }
  255. protected function addRetrieveNodeByPK(&$script)
  256. {
  257. $peerClassname = $this->getStubPeerBuilder()->getClassname();
  258. $objectClassname = $this->getStubObjectBuilder()->getClassname();
  259. $nodePeerClassname = $this->getStubNodePeerBuilder()->getClassname();
  260. $nodeObjectClassname = $this->getStubNodeBuilder()->getClassname();
  261. $script .= "
  262. /**
  263. * Retrieves a tree node based on a primary key. Optionally includes all
  264. * parent and/or child nodes of the matching node.
  265. *
  266. * @param mixed $objectClassname primary key (array for composite keys)
  267. * @param boolean True if ancestors should also be retrieved.
  268. * @param boolean True if descendants should also be retrieved.
  269. * @param PropelPDO Connection to use.
  270. * @return $nodeObjectClassname
  271. */
  272. public static function retrieveNodeByPK(\$pk, \$ancestors = false, \$descendants = false, PropelPDO \$con = null)
  273. {
  274. throw new PropelException('retrieveNodeByPK() not implemented yet.');
  275. }
  276. ";
  277. }
  278. protected function addRetrieveNodeByNP(&$script)
  279. {
  280. $peerClassname = $this->getStubPeerBuilder()->getClassname();
  281. $objectClassname = $this->getStubObjectBuilder()->getClassname();
  282. $nodePeerClassname = $this->getStubNodePeerBuilder()->getClassname();
  283. $nodeObjectClassname = $this->getStubNodeBuilder()->getClassname();
  284. $script .= "
  285. /**
  286. * Retrieves a tree node based on a node path. Optionally includes all
  287. * parent and/or child nodes of the matching node.
  288. *
  289. * @param string Node path to retrieve.
  290. * @param boolean True if ancestors should also be retrieved.
  291. * @param boolean True if descendants should also be retrieved.
  292. * @param PropelPDO Connection to use.
  293. * @return $objectClassname
  294. */
  295. public static function retrieveNodeByNP(\$np, \$ancestors = false, \$descendants = false, PropelPDO \$con = null)
  296. {
  297. \$criteria = new Criteria($peerClassname::DATABASE_NAME);
  298. \$criteria->add(self::NPATH_COLNAME, \$np, Criteria::EQUAL);
  299. \$criteria = self::buildFamilyCriteria(\$criteria, \$ancestors, \$descendants);
  300. \$stmt = $peerClassname::doSelectStmt(\$criteria, \$con);
  301. \$nodes = self::populateNodes(\$stmt, \$criteria);
  302. return (count(\$nodes) == 1 ? \$nodes[0] : null);
  303. }
  304. ";
  305. }
  306. protected function addRetrieveRootNode(&$script)
  307. {
  308. $script .= "
  309. /**
  310. * Retrieves the root node.
  311. *
  312. * @param string Node path to retrieve.
  313. * @param boolean True if descendants should also be retrieved.
  314. * @param PropelPDO Connection to use.
  315. * @return ".$this->getStubNodeBuilder()->getClassname()."
  316. */
  317. public static function retrieveRootNode(\$descendants = false, PropelPDO \$con = null)
  318. {
  319. return self::retrieveNodeByNP('1', false, \$descendants, \$con);
  320. }
  321. ";
  322. }
  323. protected function addMoveNodeSubTree(&$script)
  324. {
  325. $peerClassname = $this->getStubPeerBuilder()->getClassname();
  326. $objectClassname = $this->getStubObjectBuilder()->getClassname();
  327. $nodePeerClassname = $this->getStubNodePeerBuilder()->getClassname();
  328. $nodeObjectClassname = $this->getStubNodeBuilder()->getClassname();
  329. $script .= "
  330. /**
  331. * Moves the node subtree at srcpath to the dstpath. This method is intended
  332. * for internal use by the BaseNode object. Note that it does not check for
  333. * preexisting nodes at the dstpath. It also does not update the node path
  334. * of any Node objects that might currently be in memory.
  335. *
  336. * Use at your own risk!
  337. *
  338. * @param string Source node path to move (root of the src subtree).
  339. * @param string Destination node path to move to (root of the dst subtree).
  340. * @param PropelPDO Connection to use.
  341. * @return void
  342. * @throws PropelException
  343. * @todo This is currently broken for simulated 'onCascadeDelete's.
  344. * @todo Need to abstract the SQL better. The CONCAT sql function doesn't
  345. * seem to be standardized (i.e. mssql), so maybe it needs to be moved
  346. * to DBAdapter.
  347. */
  348. public static function moveNodeSubTree(\$srcPath, \$dstPath, PropelPDO \$con = null)
  349. {
  350. if (substr(\$dstPath, 0, strlen(\$srcPath)) == \$srcPath)
  351. throw new PropelException('Cannot move a node subtree within itself.');
  352. if (\$con === null)
  353. \$con = Propel::getConnection($peerClassname::DATABASE_NAME, Propel::CONNECTION_WRITE);
  354. /**
  355. * Example:
  356. * UPDATE table
  357. * SET npath = CONCAT('1.3', SUBSTRING(npath, 6, 74))
  358. * WHERE npath = '1.2.2' OR npath LIKE '1.2.2.%'
  359. */
  360. \$npath = $nodePeerClassname::NPATH_COLNAME;
  361. //the following dot isn`t mean`t a nodeKeySeperator
  362. \$setcol = substr(\$npath, strrpos(\$npath, '.')+1);
  363. \$setcollen = $nodePeerClassname::NPATH_LEN;
  364. \$db = Propel::getDb($peerClassname::DATABASE_NAME);
  365. // <hack>
  366. if ($nodePeerClassname::isCodeBase(\$con))
  367. {
  368. // This is a hack to get CodeBase working. It will eventually be removed.
  369. // It is a workaround for the following CodeBase bug:
  370. // -Prepared statement parameters cannot be embedded in SQL functions (i.e. CONCAT)
  371. \$sql = \"UPDATE \" . $peerClassname::TABLE_NAME . \" \" .
  372. \"SET \$setcol=\" . \$db->concatString(\"'\$dstPath'\", \$db->subString(\$npath, strlen(\$srcPath)+1, \$setcollen)) . \" \" .
  373. \"WHERE \$npath = '\$srcPath' OR \$npath LIKE '\" . \$srcPath . $nodePeerClassname::NPATH_SEP . \"%'\";
  374. \$con->executeUpdate(\$sql);
  375. }
  376. else
  377. {
  378. // </hack>
  379. \$sql = \"UPDATE \" . $peerClassname::TABLE_NAME . \" \" .
  380. \"SET \$setcol=\" . \$db->concatString('?', \$db->subString(\$npath, '?', '?')) . \" \" .
  381. \"WHERE \$npath = ? OR \$npath LIKE ?\";
  382. \$stmt = \$con->prepare(\$sql);
  383. \$stmt->bindValue(1, \$dstPath); // string
  384. \$srcPathPlus1 = strlen(\$srcPath)+1;
  385. \$stmt->bindValue(2, \$srcPathPlus1); // int
  386. \$stmt->bindValue(3, \$setcollen);// int
  387. \$stmt->bindValue(4, \$srcPath);// string
  388. \$srcPathWC = \$srcPath . $nodePeerClassname::NPATH_SEP . '%';
  389. \$stmt->bindValue(5, \$srcPathWC); // string
  390. \$stmt->execute();
  391. // <hack>
  392. }
  393. }
  394. ";
  395. }
  396. protected function addDeleteNodeSubTree(&$script)
  397. {
  398. $peerClassname = $this->getStubPeerBuilder()->getClassname();
  399. $objectClassname = $this->getStubObjectBuilder()->getClassname();
  400. $nodePeerClassname = $this->getStubNodePeerBuilder()->getClassname();
  401. $nodeObjectClassname = $this->getStubNodeBuilder()->getClassname();
  402. $script .= "
  403. /**
  404. * Deletes the node subtree at the specified node path from the database.
  405. *
  406. * @param string Node path to delete
  407. * @param PropelPDO Connection to use.
  408. * @return void
  409. * @throws PropelException
  410. * @todo This is currently broken for simulated 'onCascadeDelete's.
  411. */
  412. public static function deleteNodeSubTree(\$nodePath, PropelPDO \$con = null)
  413. {
  414. if (\$con === null)
  415. \$con = Propel::getConnection($peerClassname::DATABASE_NAME, Propel::CONNECTION_WRITE);
  416. /**
  417. * DELETE FROM table
  418. * WHERE npath = '1.2.2' OR npath LIKE '1.2.2.%'
  419. */
  420. \$criteria = new Criteria($peerClassname::DATABASE_NAME);
  421. \$criteria->add($nodePeerClassname::NPATH_COLNAME, \$nodePath, Criteria::EQUAL);
  422. \$criteria->addOr($nodePeerClassname::NPATH_COLNAME, \$nodePath . self::NPATH_SEP . '%', Criteria::LIKE);
  423. {$this->basePeerClassname}::doDelete(\$criteria, \$con);
  424. }
  425. ";
  426. }
  427. protected function addBuildFamilyCriteria(&$script)
  428. {
  429. $peerClassname = $this->getStubPeerBuilder()->getClassname();
  430. $objectClassname = $this->getStubObjectBuilder()->getClassname();
  431. $nodePeerClassname = $this->getStubNodePeerBuilder()->getClassname();
  432. $nodeObjectClassname = $this->getStubNodeBuilder()->getClassname();
  433. $script .= "
  434. /**
  435. * Builds the criteria needed to retrieve node ancestors and/or descendants.
  436. *
  437. * @param Criteria Criteria to start with
  438. * @param boolean True if ancestors should be retrieved.
  439. * @param boolean True if descendants should be retrieved.
  440. * @return Criteria
  441. */
  442. public static function buildFamilyCriteria(\$criteria, \$ancestors = false, \$descendants = false)
  443. {
  444. /*
  445. Example SQL to retrieve nodepath '1.2.3' with both ancestors and descendants:
  446. SELECT L.NPATH, L.LABEL, test.NPATH, UCASE(L.NPATH)
  447. FROM test L, test
  448. WHERE test.NPATH='1.2.3' AND
  449. (L.NPATH=SUBSTRING(test.NPATH, 1, LENGTH(L.NPATH)) OR
  450. test.NPATH=SUBSTRING(L.NPATH, 1, LENGTH(test.NPATH)))
  451. ORDER BY UCASE(L.NPATH) ASC
  452. */
  453. if (\$criteria === null)
  454. \$criteria = new Criteria($peerClassname::DATABASE_NAME);
  455. if (!\$criteria->getSelectColumns())
  456. $peerClassname::addSelectColumns(\$criteria);
  457. \$db = Propel::getDb(\$criteria->getDbName());
  458. if ((\$ancestors || \$descendants) && \$criteria->size())
  459. {
  460. // If we are retrieving ancestors/descendants, we need to do a
  461. // self-join to locate them. The exception to this is if no search
  462. // criteria is specified. In this case we're retrieving all nodes
  463. // anyway, so there is no need to do a self-join.
  464. // The left-side of the self-join will contain the columns we'll
  465. // use to build node objects (target node records along with their
  466. // ancestors and/or descendants). The right-side of the join will
  467. // contain the target node records specified by the initial criteria.
  468. // These are used to match the appropriate ancestor/descendant on
  469. // the left.
  470. // Specify an alias for the left-side table to use.
  471. \$criteria->addAlias('L', $peerClassname::TABLE_NAME);
  472. // Make sure we have select columns to begin with.
  473. if (!\$criteria->getSelectColumns())
  474. $peerClassname::addSelectColumns(\$criteria);
  475. // Replace any existing columns for the right-side table with the
  476. // left-side alias.
  477. \$selectColumns = \$criteria->getSelectColumns();
  478. \$criteria->clearSelectColumns();
  479. foreach (\$selectColumns as \$colName)
  480. \$criteria->addSelectColumn(str_replace($peerClassname::TABLE_NAME, 'L', \$colName));
  481. \$a = null;
  482. \$d = null;
  483. \$npathL = $peerClassname::alias('L', $nodePeerClassname::NPATH_COLNAME);
  484. \$npathR = $nodePeerClassname::NPATH_COLNAME;
  485. \$npath_len = $nodePeerClassname::NPATH_LEN;
  486. if (\$ancestors)
  487. {
  488. // For ancestors, match left-side node paths which are contained
  489. // by right-side node paths.
  490. \$a = \$criteria->getNewCriterion(\$npathL,
  491. \"\$npathL=\" . \$db->subString(\$npathR, 1, \$db->strLength(\$npathL), \$npath_len),
  492. Criteria::CUSTOM);
  493. }
  494. if (\$descendants)
  495. {
  496. // For descendants, match left-side node paths which contain
  497. // right-side node paths.
  498. \$d = \$criteria->getNewCriterion(\$npathR,
  499. \"\$npathR=\" . \$db->subString(\$npathL, 1, \$db->strLength(\$npathR), \$npath_len),
  500. Criteria::CUSTOM);
  501. }
  502. if (\$a)
  503. {
  504. if (\$d) \$a->addOr(\$d);
  505. \$criteria->addAnd(\$a);
  506. }
  507. else if (\$d)
  508. {
  509. \$criteria->addAnd(\$d);
  510. }
  511. // Add the target node path column. This is used by populateNodes().
  512. \$criteria->addSelectColumn(\$npathR);
  513. // Sort by node path to speed up tree construction in populateNodes()
  514. \$criteria->addAsColumn('npathlen', \$db->strLength(\$npathL));
  515. \$criteria->addAscendingOrderByColumn('npathlen');
  516. \$criteria->addAscendingOrderByColumn(\$npathL);
  517. }
  518. else
  519. {
  520. // Add the target node path column. This is used by populateNodes().
  521. \$criteria->addSelectColumn($nodePeerClassname::NPATH_COLNAME);
  522. // Sort by node path to speed up tree construction in populateNodes()
  523. \$criteria->addAsColumn('npathlen', \$db->strLength($nodePeerClassname::NPATH_COLNAME));
  524. \$criteria->addAscendingOrderByColumn('npathlen');
  525. \$criteria->addAscendingOrderByColumn($nodePeerClassname::NPATH_COLNAME);
  526. }
  527. return \$criteria;
  528. }
  529. ";
  530. }
  531. protected function addBuildTree(&$script)
  532. {
  533. $peerClassname = $this->getStubPeerBuilder()->getClassname();
  534. $objectClassname = $this->getStubObjectBuilder()->getClassname();
  535. $nodePeerClassname = $this->getStubNodePeerBuilder()->getClassname();
  536. $nodeObjectClassname = $this->getStubNodeBuilder()->getClassname();
  537. $script .= "
  538. /**
  539. * This method reconstructs as much of the tree structure as possible from
  540. * the given array of objects. Depending on how you execute your query, it
  541. * is possible for the ResultSet to contain multiple tree fragments (i.e.
  542. * subtrees). The array returned by this method will contain one entry
  543. * for each subtree root node it finds. The remaining subtree nodes are
  544. * accessible from the $nodeObjectClassname methods of the
  545. * subtree root nodes.
  546. *
  547. * @param array Array of $nodeObjectClassname objects
  548. * @return array Array of $nodeObjectClassname objects
  549. */
  550. public static function buildTree(\$nodes)
  551. {
  552. // Subtree root nodes to return
  553. \$rootNodes = array();
  554. // Build the tree relations
  555. foreach (\$nodes as \$node)
  556. {
  557. \$sep = strrpos(\$node->getNodePath(), $nodePeerClassname::NPATH_SEP);
  558. \$parentPath = (\$sep !== false ? substr(\$node->getNodePath(), 0, \$sep) : '');
  559. \$parentNode = null;
  560. // Scan other nodes for parent.
  561. foreach (\$nodes as \$pnode)
  562. {
  563. if (\$pnode->getNodePath() === \$parentPath)
  564. {
  565. \$parentNode = \$pnode;
  566. break;
  567. }
  568. }
  569. // If parent was found, attach as child, otherwise its a subtree root
  570. if (\$parentNode)
  571. \$parentNode->attachChildNode(\$node);
  572. else
  573. \$rootNodes[] = \$node;
  574. }
  575. return \$rootNodes;
  576. }
  577. ";
  578. }
  579. protected function addPopulateNodes(&$script)
  580. {
  581. $table = $this->getTable();
  582. $peerClassname = $this->getStubPeerBuilder()->getClassname();
  583. $objectClassname = $this->getStubObjectBuilder()->getClassname();
  584. $nodePeerClassname = $this->getStubNodePeerBuilder()->getClassname();
  585. $nodeObjectClassname = $this->getStubNodeBuilder()->getClassname();
  586. $script .= "
  587. /**
  588. * Populates the $objectClassname objects from the
  589. * specified ResultSet, wraps them in $nodeObjectClassname
  590. * objects and build the appropriate node relationships.
  591. * The array returned by this method will only include the initial targets
  592. * of the query, even if ancestors/descendants were also requested.
  593. * The ancestors/descendants will be cached in memory and are accessible via
  594. * the getNode() methods.
  595. *
  596. * @param PDOStatement \$stmt Executed PDOStatement
  597. * @param Criteria
  598. * @return array Array of $nodeObjectClassname objects.
  599. */
  600. public static function populateNodes(PDOStatement \$stmt, \$criteria)
  601. {
  602. \$nodes = array();
  603. \$targets = array();
  604. \$targetfld = count(\$criteria->getSelectColumns());
  605. ";
  606. if (!$table->getChildrenColumn()) {
  607. $script .= "
  608. // set the class once to avoid overhead in the loop
  609. \$cls = $peerClassname::getOMClass();
  610. \$cls = substr('.'.\$cls, strrpos('.'.\$cls, '.') + 1);
  611. ";
  612. }
  613. $script .= "
  614. // populate the object(s)
  615. foreach(\$stmt->fetchAll() AS \$row)
  616. {
  617. if (!isset(\$nodes[\$row[0]]))
  618. {
  619. ";
  620. if ($table->getChildrenColumn()) {
  621. $script .= "
  622. // class must be set each time from the record row
  623. \$cls = $peerClassname::getOMClass(\$row, 1);
  624. \$cls = substr('.'.\$cls, strrpos('.'.\$cls, '.') + 1);
  625. ";
  626. }
  627. $script .= "
  628. " . $this->buildObjectInstanceCreationCode('$obj', '$cls') . "
  629. \$obj->hydrate(\$row);
  630. \$nodes[\$row[0]] = new $nodeObjectClassname(\$obj);
  631. }
  632. \$node = \$nodes[\$row[0]];
  633. if (\$node->getNodePath() === \$row[\$targetfld])
  634. \$targets[\$node->getNodePath()] = \$node;
  635. }
  636. $nodePeerClassname::buildTree(\$nodes);
  637. return array_values(\$targets);
  638. }
  639. ";
  640. }
  641. } // PHP5NodePeerBuilder