PageRenderTime 46ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/generator/lib/behavior/versionable/VersionableBehaviorObjectBuilderModifier.php

https://github.com/1989gaurav/Propel
PHP | 514 lines | 377 code | 28 blank | 109 comment | 31 complexity | 84dd85c2e5619303c536ded7fb9c8957 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 versionable columns and abilities
  11. *
  12. * @author François Zaninotto
  13. * @package propel.generator.behavior.versionable
  14. */
  15. class VersionableBehaviorObjectBuilderModifier
  16. {
  17. protected $behavior, $table, $builder, $objectClassname, $peerClassname;
  18. public function __construct($behavior)
  19. {
  20. $this->behavior = $behavior;
  21. $this->table = $behavior->getTable();
  22. }
  23. protected function getParameter($key)
  24. {
  25. return $this->behavior->getParameter($key);
  26. }
  27. protected function getColumnAttribute($name = 'version_column')
  28. {
  29. return strtolower($this->behavior->getColumnForParameter($name)->getName());
  30. }
  31. protected function getColumnPhpName($name = 'version_column')
  32. {
  33. return $this->behavior->getColumnForParameter($name)->getPhpName();
  34. }
  35. protected function getVersionQueryClassName()
  36. {
  37. return $this->builder->getNewStubQueryBuilder($this->behavior->getVersionTable())->getClassname();
  38. }
  39. protected function getActiveRecordClassName()
  40. {
  41. return $this->builder->getStubObjectBuilder()->getClassname();
  42. }
  43. protected function setBuilder($builder)
  44. {
  45. $this->builder = $builder;
  46. $this->objectClassname = $builder->getStubObjectBuilder()->getClassname();
  47. $this->queryClassname = $builder->getStubQueryBuilder()->getClassname();
  48. $this->peerClassname = $builder->getStubPeerBuilder()->getClassname();
  49. }
  50. /**
  51. * Get the getter of the column of the behavior
  52. *
  53. * @return string The related getter, e.g. 'getVersion'
  54. */
  55. protected function getColumnGetter($name = 'version_column')
  56. {
  57. return 'get' . $this->getColumnPhpName($name);
  58. }
  59. /**
  60. * Get the setter of the column of the behavior
  61. *
  62. * @return string The related setter, e.g. 'setVersion'
  63. */
  64. protected function getColumnSetter($name = 'version_column')
  65. {
  66. return 'set' . $this->getColumnPhpName($name);
  67. }
  68. public function preSave($builder)
  69. {
  70. $script = "if (\$this->isVersioningNecessary()) {
  71. \$this->set{$this->getColumnPhpName()}(\$this->isNew() ? 1 : \$this->getLastVersionNumber(\$con) + 1);";
  72. if ($this->behavior->getParameter('log_created_at') == 'true') {
  73. $col = $this->behavior->getTable()->getColumn($this->getParameter('version_created_at_column'));
  74. $script .= "
  75. if (!\$this->isColumnModified({$this->builder->getColumnConstant($col)})) {
  76. \$this->{$this->getColumnSetter('version_created_at_column')}(time());
  77. }";
  78. }
  79. $script .= "
  80. \$createVersion = true; // for postSave hook
  81. }";
  82. return $script;
  83. }
  84. public function postSave($builder)
  85. {
  86. return "if (isset(\$createVersion)) {
  87. \$this->addVersion(\$con);
  88. }";
  89. }
  90. public function postDelete($builder)
  91. {
  92. $this->builder = $builder;
  93. if (!$builder->getPlatform()->supportsNativeDeleteTrigger() && !$builder->getBuildProperty('emulateForeignKeyConstraints')) {
  94. $script = "// emulate delete cascade
  95. {$this->getVersionQueryClassName()}::create()
  96. ->filterBy{$this->table->getPhpName()}(\$this)
  97. ->delete(\$con);";
  98. return $script;
  99. }
  100. }
  101. public function objectMethods($builder)
  102. {
  103. $this->setBuilder($builder);
  104. $script = '';
  105. if ($this->getParameter('version_column') != 'version') {
  106. $this->addVersionSetter($script);
  107. $this->addVersionGetter($script);
  108. }
  109. $this->addIsVersioningNecessary($script);
  110. $this->addAddVersion($script);
  111. $this->addToVersion($script);
  112. $this->addPopulateFromVersion($script);
  113. $this->addGetLastVersionNumber($script);
  114. $this->addIsLastVersion($script);
  115. $this->addGetOneVersion($script);
  116. $this->addGetAllVersions($script);
  117. $this->addCompareVersions($script);
  118. return $script;
  119. }
  120. protected function addVersionSetter(&$script)
  121. {
  122. $script .= "
  123. /**
  124. * Wrap the setter for version value
  125. *
  126. * @param string
  127. * @return " . $this->table->getPhpName() . "
  128. */
  129. public function setVersion(\$v)
  130. {
  131. return \$this->" . $this->getColumnSetter() . "(\$v);
  132. }
  133. ";
  134. }
  135. protected function addVersionGetter(&$script)
  136. {
  137. $script .= "
  138. /**
  139. * Wrap the getter for version value
  140. *
  141. * @return string
  142. */
  143. public function getVersion()
  144. {
  145. return \$this->" . $this->getColumnGetter() . "();
  146. }
  147. ";
  148. }
  149. protected function addIsVersioningNecessary(&$script)
  150. {
  151. $peerClass = $this->builder->getStubPeerBuilder()->getClassname();
  152. $script .= "
  153. /**
  154. * Checks whether the current state must be recorded as a version
  155. *
  156. * @return boolean
  157. */
  158. public function isVersioningNecessary(\$con = null)
  159. {
  160. if (\$this->alreadyInSave) {
  161. return false;
  162. }
  163. if ({$peerClass}::isVersioningEnabled() && (\$this->isNew() || \$this->isModified())) {
  164. return true;
  165. }";
  166. foreach ($this->behavior->getVersionableFks() as $fk) {
  167. $fkGetter = $this->builder->getFKPhpNameAffix($fk, $plural = false);
  168. $script .= "
  169. if (\$this->get{$fkGetter}(\$con)->isVersioningNecessary(\$con)) {
  170. return true;
  171. }
  172. ";
  173. }
  174. foreach ($this->behavior->getVersionableReferrers() as $fk) {
  175. $fkGetter = $this->builder->getRefFKPhpNameAffix($fk, $plural = true);
  176. $script .= "
  177. foreach (\$this->get{$fkGetter}(null, \$con) as \$relatedObject) {
  178. if (\$relatedObject->isVersioningNecessary(\$con)) {
  179. return true;
  180. }
  181. }
  182. ";
  183. }
  184. $script .= "
  185. return false;
  186. }
  187. ";
  188. }
  189. protected function addAddVersion(&$script)
  190. {
  191. $versionTable = $this->behavior->getVersionTable();
  192. $versionARClassname = $this->builder->getNewStubObjectBuilder($versionTable)->getClassname();
  193. $script .= "
  194. /**
  195. * Creates a version of the current object and saves it.
  196. *
  197. * @param PropelPDO \$con the connection to use
  198. *
  199. * @return {$versionARClassname} A version object
  200. */
  201. public function addVersion(\$con = null)
  202. {
  203. \$version = new {$versionARClassname}();";
  204. foreach ($this->table->getColumns() as $col) {
  205. $script .= "
  206. \$version->set" . $col->getPhpName() . "(\$this->get" . $col->getPhpName() . "());";
  207. }
  208. $script .= "
  209. \$version->set{$this->table->getPhpName()}(\$this);";
  210. foreach ($this->behavior->getVersionableFks() as $fk) {
  211. $fkGetter = $this->builder->getFKPhpNameAffix($fk, $plural = false);
  212. $fkVersionColumnName = $fk->getLocalColumnName() . '_version';
  213. $fkVersionColumnPhpName = $versionTable->getColumn($fkVersionColumnName)->getPhpName();
  214. $script .= "
  215. if ((\$related = \$this->get{$fkGetter}(\$con)) && \$related->getVersion()) {
  216. \$version->set{$fkVersionColumnPhpName}(\$related->getVersion());
  217. }";
  218. }
  219. foreach ($this->behavior->getVersionableReferrers() as $fk) {
  220. $fkGetter = $this->builder->getRefFKPhpNameAffix($fk, $plural = true);
  221. $idsColumn = $this->behavior->getReferrerIdsColumn($fk);
  222. $versionsColumn = $this->behavior->getReferrerVersionsColumn($fk);
  223. $script .= "
  224. if (\$relateds = \$this->get{$fkGetter}(\$con)->toKeyValue('{$fk->getForeignColumn()->getPhpName()}', 'Version')) {
  225. \$version->set{$idsColumn->getPhpName()}(array_keys(\$relateds));
  226. \$version->set{$versionsColumn->getPhpName()}(array_values(\$relateds));
  227. }";
  228. }
  229. $script .= "
  230. \$version->save(\$con);
  231. return \$version;
  232. }
  233. ";
  234. }
  235. protected function addToVersion(&$script)
  236. {
  237. $ARclassName = $this->getActiveRecordClassName();
  238. $script .= "
  239. /**
  240. * Sets the properties of the curent object to the value they had at a specific version
  241. *
  242. * @param integer \$versionNumber The version number to read
  243. * @param PropelPDO \$con the connection to use
  244. *
  245. * @return {$ARclassName} The current object (for fluent API support)
  246. */
  247. public function toVersion(\$versionNumber, \$con = null)
  248. {
  249. \$version = \$this->getOneVersion(\$versionNumber, \$con);
  250. if (!\$version) {
  251. throw new PropelException(sprintf('No {$ARclassName} object found with version %d', \$version));
  252. }
  253. \$this->populateFromVersion(\$version, \$con);
  254. return \$this;
  255. }
  256. ";
  257. }
  258. protected function addPopulateFromVersion(&$script)
  259. {
  260. $ARclassName = $this->getActiveRecordClassName();
  261. $versionTable = $this->behavior->getVersionTable();
  262. $versionARClassname = $this->builder->getNewStubObjectBuilder($versionTable)->getClassname();
  263. $script .= "
  264. /**
  265. * Sets the properties of the curent object to the value they had at a specific version
  266. *
  267. * @param {$versionARClassname} \$version The version object to use
  268. * @param PropelPDO \$con the connection to use
  269. *
  270. * @return {$ARclassName} The current object (for fluent API support)
  271. */
  272. public function populateFromVersion(\$version, \$con = null)
  273. {";
  274. foreach ($this->table->getColumns() as $col) {
  275. $script .= "
  276. \$this->set" . $col->getPhpName() . "(\$version->get" . $col->getPhpName() . "());";
  277. }
  278. foreach ($this->behavior->getVersionableFks() as $fk) {
  279. $foreignTable = $fk->getForeignTable();
  280. $foreignVersionTable = $fk->getForeignTable()->getBehavior('versionable')->getVersionTable();
  281. $relatedClassname = $this->builder->getNewStubObjectBuilder($foreignTable)->getClassname();
  282. $relatedVersionQueryClassname = $this->builder->getNewStubQueryBuilder($foreignVersionTable)->getClassname();
  283. $fkColumnName = $fk->getLocalColumnName();
  284. $fkColumnPhpName = $fk->getLocalColumn()->getPhpName();
  285. $fkVersionColumnPhpName = $versionTable->getColumn($fkColumnName . '_version')->getPhpName();
  286. $fkPhpname = $this->builder->getFKPhpNameAffix($fk, $plural = false);
  287. // FIXME: breaks lazy-loading
  288. $script .= "
  289. if (\$fkValue = \$version->get{$fkColumnPhpName}()) {
  290. \$related = new {$relatedClassname}();
  291. \$relatedVersion = {$relatedVersionQueryClassname}::create()
  292. ->filterBy{$fk->getForeignColumn()->getPhpName()}(\$fkValue)
  293. ->filterByVersion(\$version->get{$fkVersionColumnPhpName}())
  294. ->findOne(\$con);
  295. \$related->populateFromVersion(\$relatedVersion, \$con);
  296. \$related->setNew(false);
  297. \$this->set{$fkPhpname}(\$related);
  298. }";
  299. }
  300. foreach ($this->behavior->getVersionableReferrers() as $fk) {
  301. $fkPhpNames = $this->builder->getRefFKPhpNameAffix($fk, $plural = true);
  302. $fkPhpName = $this->builder->getRefFKPhpNameAffix($fk, $plural = false);
  303. $foreignTable = $fk->getTable();
  304. $foreignBehavior = $foreignTable->getBehavior('versionable');
  305. $foreignVersionTable = $foreignBehavior->getVersionTable();
  306. $fkColumnIds = $this->behavior->getReferrerIdsColumn($fk);
  307. $fkColumnVersions = $this->behavior->getReferrerVersionsColumn($fk);
  308. $relatedVersionQueryClassname = $this->builder->getNewStubQueryBuilder($foreignVersionTable)->getClassname();
  309. $relatedClassname = $this->builder->getNewStubObjectBuilder($foreignTable)->getClassname();
  310. $script .= "
  311. if (\$fkValues = \$version->get{$fkColumnIds->getPhpName()}()) {
  312. \$this->clear{$fkPhpNames}();
  313. \$fkVersions = \$version->get{$fkColumnVersions->getPhpName()}();
  314. \$query = {$relatedVersionQueryClassname}::create();
  315. foreach (\$fkValues as \$key => \$value) {
  316. \$c1 = \$query->getNewCriterion({$this->builder->getColumnConstant($fkColumnIds)}, \$value);
  317. \$c2 = \$query->getNewCriterion({$this->builder->getColumnConstant($fkColumnVersions)}, \$fkVersions[\$key]);
  318. \$c1->addAnd(\$c2);
  319. \$query->addOr(\$c1);
  320. }
  321. foreach (\$query->find(\$con) as \$relatedVersion) {
  322. \$related = new {$relatedClassname}();
  323. \$related->populateFromVersion(\$relatedVersion, \$con);
  324. \$related->setNew(false);
  325. \$this->add{$fkPhpName}(\$related);
  326. }
  327. }";
  328. }
  329. $script .= "
  330. return \$this;
  331. }
  332. ";
  333. }
  334. protected function addGetLastVersionNumber(&$script)
  335. {
  336. $script .= "
  337. /**
  338. * Gets the latest persisted version number for the current object
  339. *
  340. * @param PropelPDO \$con the connection to use
  341. *
  342. * @return integer
  343. */
  344. public function getLastVersionNumber(\$con = null)
  345. {
  346. \$v = {$this->getVersionQueryClassName()}::create()
  347. ->filterBy{$this->table->getPhpName()}(\$this)
  348. ->orderBy{$this->getColumnPhpName()}('desc')
  349. ->findOne(\$con);
  350. if (!\$v) {
  351. return 0;
  352. }
  353. return \$v->get{$this->getColumnPhpName()}();
  354. }
  355. ";
  356. }
  357. protected function addIsLastVersion(&$script)
  358. {
  359. $script .= "
  360. /**
  361. * Checks whether the current object is the latest one
  362. *
  363. * @param PropelPDO \$con the connection to use
  364. *
  365. * @return Boolean
  366. */
  367. public function isLastVersion(\$con = null)
  368. {
  369. return \$this->getLastVersionNumber(\$con) == \$this->getVersion();
  370. }
  371. ";
  372. }
  373. protected function addGetOneVersion(&$script)
  374. {
  375. $versionARClassname = $this->builder->getNewStubObjectBuilder($this->behavior->getVersionTable())->getClassname();
  376. $script .= "
  377. /**
  378. * Retrieves a version object for this entity and a version number
  379. *
  380. * @param integer \$versionNumber The version number to read
  381. * @param PropelPDO \$con the connection to use
  382. *
  383. * @return {$versionARClassname} A version object
  384. */
  385. public function getOneVersion(\$versionNumber, \$con = null)
  386. {
  387. return {$this->getVersionQueryClassName()}::create()
  388. ->filterBy{$this->table->getPhpName()}(\$this)
  389. ->filterBy{$this->getColumnPhpName()}(\$versionNumber)
  390. ->findOne(\$con);
  391. }
  392. ";
  393. }
  394. protected function addGetAllVersions(&$script)
  395. {
  396. $versionTable = $this->behavior->getVersionTable();
  397. $versionARClassname = $this->builder->getNewStubObjectBuilder($versionTable)->getClassname();
  398. $versionForeignColumn = $versionTable->getColumn($this->behavior->getParameter('version_column'));
  399. $fks = $versionTable->getForeignKeysReferencingTable($this->table->getName());
  400. $relCol = $this->builder->getRefFKPhpNameAffix($fks[0], $plural = true);
  401. $script .= "
  402. /**
  403. * Gets all the versions of this object, in incremental order
  404. *
  405. * @param PropelPDO \$con the connection to use
  406. *
  407. * @return PropelObjectCollection A list of {$versionARClassname} objects
  408. */
  409. public function getAllVersions(\$con = null)
  410. {
  411. \$criteria = new Criteria();
  412. \$criteria->addAscendingOrderByColumn({$this->builder->getColumnConstant($versionForeignColumn)});
  413. return \$this->get{$relCol}(\$criteria, \$con);
  414. }
  415. ";
  416. }
  417. protected function addCompareVersions(&$script)
  418. {
  419. $versionTable = $this->behavior->getVersionTable();
  420. $versionARClassname = $this->builder->getNewStubObjectBuilder($versionTable)->getClassname();
  421. $versionForeignColumn = $versionTable->getColumn($this->behavior->getParameter('version_column'));
  422. $fks = $versionTable->getForeignKeysReferencingTable($this->table->getName());
  423. $relCol = $this->builder->getRefFKPhpNameAffix($fks[0], $plural = true);
  424. $script .= "
  425. /**
  426. * Gets all the versions of this object, in incremental order.
  427. * <code>
  428. * print_r(\$book->compare(1, 2));
  429. * => array(
  430. * '1' => array('Title' => 'Book title at version 1'),
  431. * '2' => array('Title' => 'Book title at version 2')
  432. * );
  433. * </code>
  434. *
  435. * @param integer \$fromVersionNumber
  436. * @param integer \$toVersionNumber
  437. * @param string \$keys Main key used for the result diff (versions|columns)
  438. * @param PropelPDO \$con the connection to use
  439. *
  440. * @return array A list of differences
  441. */
  442. public function compareVersions(\$fromVersionNumber, \$toVersionNumber, \$keys = 'columns', \$con = null)
  443. {
  444. \$fromVersion = \$this->getOneVersion(\$fromVersionNumber, \$con)->toArray();
  445. \$toVersion = \$this->getOneVersion(\$toVersionNumber, \$con)->toArray();
  446. \$ignoredColumns = array(
  447. '{$this->getColumnPhpName()}',";
  448. if ($this->behavior->getParameter('log_created_at') == 'true') {
  449. $script .= "
  450. 'VersionCreatedAt',";
  451. }
  452. if ($this->behavior->getParameter('log_created_by') == 'true') {
  453. $script .= "
  454. 'VersionCreatedBy',";
  455. }
  456. if ($this->behavior->getParameter('log_comment') == 'true') {
  457. $script .= "
  458. 'VersionComment',";
  459. }
  460. $script .= "
  461. );
  462. \$diff = array();
  463. foreach (\$fromVersion as \$key => \$value) {
  464. if (in_array(\$key, \$ignoredColumns)) {
  465. continue;
  466. }
  467. if (\$toVersion[\$key] != \$value) {
  468. switch (\$keys) {
  469. case 'versions':
  470. \$diff[\$fromVersionNumber][\$key] = \$value;
  471. \$diff[\$toVersionNumber][\$key] = \$toVersion[\$key];
  472. break;
  473. default:
  474. \$diff[\$key] = array(
  475. \$fromVersionNumber => \$value,
  476. \$toVersionNumber => \$toVersion[\$key],
  477. );
  478. break;
  479. }
  480. }
  481. }
  482. return \$diff;
  483. }
  484. ";
  485. }
  486. }