PageRenderTime 25ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/generator/lib/behavior/sortable/SortableBehaviorObjectBuilderModifier.php

https://github.com/1989gaurav/Propel
PHP | 636 lines | 413 code | 46 blank | 177 comment | 37 complexity | f868faa803eae2f047aa31e1e6ce0dad 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. /**
  10. * Behavior to add sortable columns and abilities
  11. *
  12. * @author François Zaninotto
  13. * @author heltem <heltem@o2php.com>
  14. * @package propel.generator.behavior.sortable
  15. */
  16. class SortableBehaviorObjectBuilderModifier
  17. {
  18. protected $behavior, $table, $builder, $objectClassname, $peerClassname;
  19. public function __construct($behavior)
  20. {
  21. $this->behavior = $behavior;
  22. $this->table = $behavior->getTable();
  23. }
  24. protected function getParameter($key)
  25. {
  26. return $this->behavior->getParameter($key);
  27. }
  28. protected function getColumnAttribute($name)
  29. {
  30. return strtolower($this->behavior->getColumnForParameter($name)->getName());
  31. }
  32. protected function getColumnPhpName($name)
  33. {
  34. return $this->behavior->getColumnForParameter($name)->getPhpName();
  35. }
  36. protected function setBuilder($builder)
  37. {
  38. $this->builder = $builder;
  39. $this->objectClassname = $builder->getStubObjectBuilder()->getClassname();
  40. $this->queryClassname = $builder->getStubQueryBuilder()->getClassname();
  41. $this->peerClassname = $builder->getStubPeerBuilder()->getClassname();
  42. }
  43. /**
  44. * Get the getter of the column of the behavior
  45. *
  46. * @return string The related getter, e.g. 'getRank'
  47. */
  48. protected function getColumnGetter($columnName = 'rank_column')
  49. {
  50. return 'get' . $this->behavior->getColumnForParameter($columnName)->getPhpName();
  51. }
  52. /**
  53. * Get the setter of the column of the behavior
  54. *
  55. * @return string The related setter, e.g. 'setRank'
  56. */
  57. protected function getColumnSetter($columnName = 'rank_column')
  58. {
  59. return 'set' . $this->behavior->getColumnForParameter($columnName)->getPhpName();
  60. }
  61. public function preSave($builder)
  62. {
  63. return "\$this->processSortableQueries(\$con);";
  64. }
  65. public function preInsert($builder)
  66. {
  67. $useScope = $this->behavior->useScope();
  68. $this->setBuilder($builder);
  69. return "if (!\$this->isColumnModified({$this->peerClassname}::RANK_COL)) {
  70. \$this->{$this->getColumnSetter()}({$this->queryClassname}::create()->getMaxRank(" . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con) + 1);
  71. }
  72. ";
  73. }
  74. public function preDelete($builder)
  75. {
  76. $useScope = $this->behavior->useScope();
  77. $this->setBuilder($builder);
  78. return "
  79. {$this->peerClassname}::shiftRank(-1, \$this->{$this->getColumnGetter()}() + 1, null, " . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con);
  80. {$this->peerClassname}::clearInstancePool();
  81. ";
  82. }
  83. public function objectAttributes($builder)
  84. {
  85. return "
  86. /**
  87. * Queries to be executed in the save transaction
  88. * @var array
  89. */
  90. protected \$sortableQueries = array();
  91. ";
  92. }
  93. public function objectMethods($builder)
  94. {
  95. $this->setBuilder($builder);
  96. $script = '';
  97. if ($this->getParameter('rank_column') != 'rank') {
  98. $this->addRankAccessors($script);
  99. }
  100. if ($this->behavior->useScope() &&
  101. $this->getParameter('scope_column') != 'scope_value') {
  102. $this->addScopeAccessors($script);
  103. }
  104. $this->addIsFirst($script);
  105. $this->addIsLast($script);
  106. $this->addGetNext($script);
  107. $this->addGetPrevious($script);
  108. $this->addInsertAtRank($script);
  109. $this->addInsertAtBottom($script);
  110. $this->addInsertAtTop($script);
  111. $this->addMoveToRank($script);
  112. $this->addSwapWith($script);
  113. $this->addMoveUp($script);
  114. $this->addMoveDown($script);
  115. $this->addMoveToTop($script);
  116. $this->addMoveToBottom($script);
  117. $this->addRemoveFromList($script);
  118. $this->addProcessSortableQueries($script);
  119. return $script;
  120. }
  121. /**
  122. * Get the wraps for getter/setter, if the rank column has not the default name
  123. *
  124. * @return string
  125. */
  126. protected function addRankAccessors(&$script)
  127. {
  128. $script .= "
  129. /**
  130. * Wrap the getter for rank value
  131. *
  132. * @return int
  133. */
  134. public function getRank()
  135. {
  136. return \$this->{$this->getColumnAttribute('rank_column')};
  137. }
  138. /**
  139. * Wrap the setter for rank value
  140. *
  141. * @param int
  142. * @return {$this->objectClassname}
  143. */
  144. public function setRank(\$v)
  145. {
  146. return \$this->{$this->getColumnSetter()}(\$v);
  147. }
  148. ";
  149. }
  150. /**
  151. * Get the wraps for getter/setter, if the scope column has not the default name
  152. *
  153. * @return string
  154. */
  155. protected function addScopeAccessors(&$script)
  156. {
  157. $script .= "
  158. /**
  159. * Wrap the getter for scope value
  160. *
  161. * @return int
  162. */
  163. public function getScopeValue()
  164. {
  165. return \$this->{$this->getColumnAttribute('scope_column')};
  166. }
  167. /**
  168. * Wrap the setter for scope value
  169. *
  170. * @param int
  171. * @return {$this->objectClassname}
  172. */
  173. public function setScopeValue(\$v)
  174. {
  175. return \$this->{$this->getColumnSetter('scope_column')}(\$v);
  176. }
  177. ";
  178. }
  179. protected function addIsFirst(&$script)
  180. {
  181. $script .= "
  182. /**
  183. * Check if the object is first in the list, i.e. if it has 1 for rank
  184. *
  185. * @return boolean
  186. */
  187. public function isFirst()
  188. {
  189. return \$this->{$this->getColumnGetter()}() == 1;
  190. }
  191. ";
  192. }
  193. protected function addIsLast(&$script)
  194. {
  195. $useScope = $this->behavior->useScope();
  196. $script .= "
  197. /**
  198. * Check if the object is last in the list, i.e. if its rank is the highest rank
  199. *
  200. * @param PropelPDO \$con optional connection
  201. *
  202. * @return boolean
  203. */
  204. public function isLast(PropelPDO \$con = null)
  205. {
  206. return \$this->{$this->getColumnGetter()}() == {$this->queryClassname}::create()->getMaxRank(" . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con);
  207. }
  208. ";
  209. }
  210. protected function addGetNext(&$script)
  211. {
  212. $useScope = $this->behavior->useScope();
  213. $script .= "
  214. /**
  215. * Get the next item in the list, i.e. the one for which rank is immediately higher
  216. *
  217. * @param PropelPDO \$con optional connection
  218. *
  219. * @return {$this->objectClassname}
  220. */
  221. public function getNext(PropelPDO \$con = null)
  222. {";
  223. if ($this->behavior->getParameter('rank_column') == 'rank' && $useScope) {
  224. $script .= "
  225. return {$this->queryClassname}::create()
  226. ->filterByRank(\$this->{$this->getColumnGetter()}() + 1)
  227. ->inList(\$this->{$this->getColumnGetter('scope_column')}())
  228. ->findOne(\$con);";
  229. } else {
  230. $script .= "
  231. return {$this->queryClassname}::create()->findOneByRank(\$this->{$this->getColumnGetter()}() + 1, " . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con);";
  232. }
  233. $script .= "
  234. }
  235. ";
  236. }
  237. protected function addGetPrevious(&$script)
  238. {
  239. $useScope = $this->behavior->useScope();
  240. $script .= "
  241. /**
  242. * Get the previous item in the list, i.e. the one for which rank is immediately lower
  243. *
  244. * @param PropelPDO \$con optional connection
  245. *
  246. * @return {$this->objectClassname}
  247. */
  248. public function getPrevious(PropelPDO \$con = null)
  249. {";
  250. if ($this->behavior->getParameter('rank_column') == 'rank' && $useScope) {
  251. $script .= "
  252. return {$this->queryClassname}::create()
  253. ->filterByRank(\$this->{$this->getColumnGetter()}() - 1)
  254. ->inList(\$this->{$this->getColumnGetter('scope_column')}())
  255. ->findOne(\$con);";
  256. } else {
  257. $script .= "
  258. return {$this->queryClassname}::create()->findOneByRank(\$this->{$this->getColumnGetter()}() - 1, " . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con);";
  259. }
  260. $script .= "
  261. }
  262. ";
  263. }
  264. protected function addInsertAtRank(&$script)
  265. {
  266. $useScope = $this->behavior->useScope();
  267. $peerClassname = $this->peerClassname;
  268. $script .= "
  269. /**
  270. * Insert at specified rank
  271. * The modifications are not persisted until the object is saved.
  272. *
  273. * @param integer \$rank rank value
  274. * @param PropelPDO \$con optional connection
  275. *
  276. * @return {$this->objectClassname} the current object
  277. *
  278. * @throws PropelException
  279. */
  280. public function insertAtRank(\$rank, PropelPDO \$con = null)
  281. {";
  282. if ($useScope) {
  283. $script .= "
  284. if (null === \$this->{$this->getColumnGetter('scope_column')}()) {
  285. throw new PropelException('The scope must be defined before inserting an object in a suite');
  286. }";
  287. }
  288. $script .= "
  289. \$maxRank = {$this->queryClassname}::create()->getMaxRank(" . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con);
  290. if (\$rank < 1 || \$rank > \$maxRank + 1) {
  291. throw new PropelException('Invalid rank ' . \$rank);
  292. }
  293. // move the object in the list, at the given rank
  294. \$this->{$this->getColumnSetter()}(\$rank);
  295. if (\$rank != \$maxRank + 1) {
  296. // Keep the list modification query for the save() transaction
  297. \$this->sortableQueries []= array(
  298. 'callable' => array('$peerClassname', 'shiftRank'),
  299. 'arguments' => array(1, \$rank, null, " . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}()" : '') . ")
  300. );
  301. }
  302. return \$this;
  303. }
  304. ";
  305. }
  306. protected function addInsertAtBottom(&$script)
  307. {
  308. $useScope = $this->behavior->useScope();
  309. $script .= "
  310. /**
  311. * Insert in the last rank
  312. * The modifications are not persisted until the object is saved.
  313. *
  314. * @param PropelPDO \$con optional connection
  315. *
  316. * @return {$this->objectClassname} the current object
  317. *
  318. * @throws PropelException
  319. */
  320. public function insertAtBottom(PropelPDO \$con = null)
  321. {";
  322. if ($useScope) {
  323. $script .= "
  324. if (null === \$this->{$this->getColumnGetter('scope_column')}()) {
  325. throw new PropelException('The scope must be defined before inserting an object in a suite');
  326. }";
  327. }
  328. $script .= "
  329. \$this->{$this->getColumnSetter()}({$this->queryClassname}::create()->getMaxRank(" . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con) + 1);
  330. return \$this;
  331. }
  332. ";
  333. }
  334. protected function addInsertAtTop(&$script)
  335. {
  336. $script .= "
  337. /**
  338. * Insert in the first rank
  339. * The modifications are not persisted until the object is saved.
  340. *
  341. * @return {$this->objectClassname} the current object
  342. */
  343. public function insertAtTop()
  344. {
  345. return \$this->insertAtRank(1);
  346. }
  347. ";
  348. }
  349. protected function addMoveToRank(&$script)
  350. {
  351. $useScope = $this->behavior->useScope();
  352. $peerClassname = $this->peerClassname;
  353. $script .= "
  354. /**
  355. * Move the object to a new rank, and shifts the rank
  356. * Of the objects inbetween the old and new rank accordingly
  357. *
  358. * @param integer \$newRank rank value
  359. * @param PropelPDO \$con optional connection
  360. *
  361. * @return {$this->objectClassname} the current object
  362. *
  363. * @throws PropelException
  364. */
  365. public function moveToRank(\$newRank, PropelPDO \$con = null)
  366. {
  367. if (\$this->isNew()) {
  368. throw new PropelException('New objects cannot be moved. Please use insertAtRank() instead');
  369. }
  370. if (\$con === null) {
  371. \$con = Propel::getConnection($peerClassname::DATABASE_NAME);
  372. }
  373. if (\$newRank < 1 || \$newRank > {$this->queryClassname}::create()->getMaxRank(" . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con)) {
  374. throw new PropelException('Invalid rank ' . \$newRank);
  375. }
  376. \$oldRank = \$this->{$this->getColumnGetter()}();
  377. if (\$oldRank == \$newRank) {
  378. return \$this;
  379. }
  380. \$con->beginTransaction();
  381. try {
  382. // shift the objects between the old and the new rank
  383. \$delta = (\$oldRank < \$newRank) ? -1 : 1;
  384. $peerClassname::shiftRank(\$delta, min(\$oldRank, \$newRank), max(\$oldRank, \$newRank), " . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con);
  385. // move the object to its new rank
  386. \$this->{$this->getColumnSetter()}(\$newRank);
  387. \$this->save(\$con);
  388. \$con->commit();
  389. return \$this;
  390. } catch (Exception \$e) {
  391. \$con->rollback();
  392. throw \$e;
  393. }
  394. }
  395. ";
  396. }
  397. protected function addSwapWith(&$script)
  398. {
  399. $script .= "
  400. /**
  401. * Exchange the rank of the object with the one passed as argument, and saves both objects
  402. *
  403. * @param {$this->objectClassname} \$object
  404. * @param PropelPDO \$con optional connection
  405. *
  406. * @return {$this->objectClassname} the current object
  407. *
  408. * @throws Exception if the database cannot execute the two updates
  409. */
  410. public function swapWith(\$object, PropelPDO \$con = null)
  411. {
  412. if (\$con === null) {
  413. \$con = Propel::getConnection({$this->peerClassname}::DATABASE_NAME);
  414. }
  415. \$con->beginTransaction();
  416. try {
  417. \$oldRank = \$this->{$this->getColumnGetter()}();
  418. \$newRank = \$object->{$this->getColumnGetter()}();
  419. \$this->{$this->getColumnSetter()}(\$newRank);
  420. \$this->save(\$con);
  421. \$object->{$this->getColumnSetter()}(\$oldRank);
  422. \$object->save(\$con);
  423. \$con->commit();
  424. return \$this;
  425. } catch (Exception \$e) {
  426. \$con->rollback();
  427. throw \$e;
  428. }
  429. }
  430. ";
  431. }
  432. protected function addMoveUp(&$script)
  433. {
  434. $script .= "
  435. /**
  436. * Move the object higher in the list, i.e. exchanges its rank with the one of the previous object
  437. *
  438. * @param PropelPDO \$con optional connection
  439. *
  440. * @return {$this->objectClassname} the current object
  441. */
  442. public function moveUp(PropelPDO \$con = null)
  443. {
  444. if (\$this->isFirst()) {
  445. return \$this;
  446. }
  447. if (\$con === null) {
  448. \$con = Propel::getConnection({$this->peerClassname}::DATABASE_NAME);
  449. }
  450. \$con->beginTransaction();
  451. try {
  452. \$prev = \$this->getPrevious(\$con);
  453. \$this->swapWith(\$prev, \$con);
  454. \$con->commit();
  455. return \$this;
  456. } catch (Exception \$e) {
  457. \$con->rollback();
  458. throw \$e;
  459. }
  460. }
  461. ";
  462. }
  463. protected function addMoveDown(&$script)
  464. {
  465. $script .= "
  466. /**
  467. * Move the object higher in the list, i.e. exchanges its rank with the one of the next object
  468. *
  469. * @param PropelPDO \$con optional connection
  470. *
  471. * @return {$this->objectClassname} the current object
  472. */
  473. public function moveDown(PropelPDO \$con = null)
  474. {
  475. if (\$this->isLast(\$con)) {
  476. return \$this;
  477. }
  478. if (\$con === null) {
  479. \$con = Propel::getConnection({$this->peerClassname}::DATABASE_NAME);
  480. }
  481. \$con->beginTransaction();
  482. try {
  483. \$next = \$this->getNext(\$con);
  484. \$this->swapWith(\$next, \$con);
  485. \$con->commit();
  486. return \$this;
  487. } catch (Exception \$e) {
  488. \$con->rollback();
  489. throw \$e;
  490. }
  491. }
  492. ";
  493. }
  494. protected function addMoveToTop(&$script)
  495. {
  496. $script .= "
  497. /**
  498. * Move the object to the top of the list
  499. *
  500. * @param PropelPDO \$con optional connection
  501. *
  502. * @return {$this->objectClassname} the current object
  503. */
  504. public function moveToTop(PropelPDO \$con = null)
  505. {
  506. if (\$this->isFirst()) {
  507. return \$this;
  508. }
  509. return \$this->moveToRank(1, \$con);
  510. }
  511. ";
  512. }
  513. protected function addMoveToBottom(&$script)
  514. {
  515. $useScope = $this->behavior->useScope();
  516. $script .= "
  517. /**
  518. * Move the object to the bottom of the list
  519. *
  520. * @param PropelPDO \$con optional connection
  521. *
  522. * @return integer the old object's rank
  523. */
  524. public function moveToBottom(PropelPDO \$con = null)
  525. {
  526. if (\$this->isLast(\$con)) {
  527. return false;
  528. }
  529. if (\$con === null) {
  530. \$con = Propel::getConnection({$this->peerClassname}::DATABASE_NAME);
  531. }
  532. \$con->beginTransaction();
  533. try {
  534. \$bottom = {$this->queryClassname}::create()->getMaxRank(" . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con);
  535. \$res = \$this->moveToRank(\$bottom, \$con);
  536. \$con->commit();
  537. return \$res;
  538. } catch (Exception \$e) {
  539. \$con->rollback();
  540. throw \$e;
  541. }
  542. }
  543. ";
  544. }
  545. protected function addRemoveFromList(&$script)
  546. {
  547. $useScope = $this->behavior->useScope();
  548. $peerClassname = $this->peerClassname;
  549. $script .= "
  550. /**
  551. * Removes the current object from the list.
  552. * The modifications are not persisted until the object is saved.
  553. *
  554. * @return {$this->objectClassname} the current object
  555. */
  556. public function removeFromList()
  557. {
  558. // Keep the list modification query for the save() transaction
  559. \$this->sortableQueries []= array(
  560. 'callable' => array('$peerClassname', 'shiftRank'),
  561. 'arguments' => array(-1, \$this->{$this->getColumnGetter()}() + 1, null" . ($useScope ? ", \$this->{$this->getColumnGetter('scope_column')}()" : '') . ")
  562. );
  563. // remove the object from the list
  564. \$this->{$this->getColumnSetter('rank_column')}(null);";
  565. if ($useScope) {
  566. $script .= "
  567. \$this->{$this->getColumnSetter('scope_column')}(null);";
  568. }
  569. $script .= "
  570. return \$this;
  571. }
  572. ";
  573. }
  574. protected function addProcessSortableQueries(&$script)
  575. {
  576. $script .= "
  577. /**
  578. * Execute queries that were saved to be run inside the save transaction
  579. */
  580. protected function processSortableQueries(\$con)
  581. {
  582. foreach (\$this->sortableQueries as \$query) {
  583. \$query['arguments'][]= \$con;
  584. call_user_func_array(\$query['callable'], \$query['arguments']);
  585. }
  586. \$this->sortableQueries = array();
  587. }
  588. ";
  589. }
  590. }