PageRenderTime 26ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/generator/lib/model/ForeignKey.php

https://github.com/1989gaurav/Propel
PHP | 683 lines | 375 code | 76 blank | 232 comment | 32 complexity | 2da55db6bc1bf2b7f877e8c669aa95b5 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__) . '/XMLElement.php';
  10. /**
  11. * A Class for information about foreign keys of a table.
  12. *
  13. * @author Hans Lellelid <hans@xmpl.org>
  14. * @author Fedor <fedor.karpelevitch@home.com>
  15. * @author Daniel Rall <dlr@finemaltcoding.com>
  16. * @author Ulf Hermann <ulfhermann@kulturserver.de>
  17. * @version $Revision$
  18. * @package propel.generator.model
  19. */
  20. class ForeignKey extends XMLElement
  21. {
  22. protected $foreignTableCommonName;
  23. protected $foreignSchemaName;
  24. protected $name;
  25. protected $phpName;
  26. protected $refPhpName;
  27. protected $defaultJoin;
  28. protected $onUpdate = '';
  29. protected $onDelete = '';
  30. protected $parentTable;
  31. protected $localColumns = array();
  32. protected $foreignColumns = array();
  33. /**
  34. * Whether to skip generation of SQL for this foreign key.
  35. *
  36. * @var boolean
  37. */
  38. protected $skipSql = false;
  39. // the uppercase equivalent of the onDelete/onUpdate values in the dtd
  40. const NONE = ""; // No "ON [ DELETE | UPDATE]" behaviour specified.
  41. const NOACTION = "NO ACTION";
  42. const CASCADE = "CASCADE";
  43. const RESTRICT = "RESTRICT";
  44. const SETDEFAULT = "SET DEFAULT";
  45. const SETNULL = "SET NULL";
  46. /**
  47. * Constructs a new ForeignKey object.
  48. *
  49. * @param string $name
  50. */
  51. public function __construct($name=null)
  52. {
  53. $this->name = $name;
  54. }
  55. /**
  56. * Sets up the ForeignKey object based on the attributes that were passed to loadFromXML().
  57. * @see parent::loadFromXML()
  58. */
  59. protected function setupObject()
  60. {
  61. $this->foreignTableCommonName = $this->getTable()->getDatabase()->getTablePrefix() . $this->getAttribute("foreignTable");
  62. $this->foreignSchemaName = $this->getAttribute("foreignSchema");
  63. if (!$this->foreignSchemaName) {
  64. if ($this->getTable()->getSchema()) {
  65. $this->foreignSchemaName = $this->getTable()->getSchema();
  66. }
  67. }
  68. $this->name = $this->getAttribute("name");
  69. $this->phpName = $this->getAttribute("phpName");
  70. $this->refPhpName = $this->getAttribute("refPhpName");
  71. $this->defaultJoin = $this->getAttribute('defaultJoin');
  72. $this->onUpdate = $this->normalizeFKey($this->getAttribute("onUpdate"));
  73. $this->onDelete = $this->normalizeFKey($this->getAttribute("onDelete"));
  74. $this->skipSql = $this->booleanValue($this->getAttribute("skipSql"));
  75. }
  76. /**
  77. * normalizes the input of onDelete, onUpdate attributes
  78. */
  79. public function normalizeFKey($attrib)
  80. {
  81. if ($attrib === null || strtoupper($attrib) == "NONE") {
  82. $attrib = self::NONE;
  83. }
  84. $attrib = strtoupper($attrib);
  85. if ($attrib == "SETNULL") {
  86. $attrib = self::SETNULL;
  87. }
  88. return $attrib;
  89. }
  90. /**
  91. * returns whether or not the onUpdate attribute is set
  92. */
  93. public function hasOnUpdate()
  94. {
  95. return ($this->onUpdate !== self::NONE);
  96. }
  97. /**
  98. * returns whether or not the onDelete attribute is set
  99. */
  100. public function hasOnDelete()
  101. {
  102. return ($this->onDelete !== self::NONE);
  103. }
  104. /**
  105. * returns the onUpdate attribute
  106. * @return string
  107. */
  108. public function getOnUpdate()
  109. {
  110. return $this->onUpdate;
  111. }
  112. /**
  113. * Returns the onDelete attribute
  114. * @return string
  115. */
  116. public function getOnDelete()
  117. {
  118. return $this->onDelete;
  119. }
  120. /**
  121. * sets the onDelete attribute
  122. */
  123. public function setOnDelete($value)
  124. {
  125. $this->onDelete = $this->normalizeFKey($value);
  126. }
  127. /**
  128. * sets the onUpdate attribute
  129. */
  130. public function setOnUpdate($value)
  131. {
  132. $this->onUpdate = $this->normalizeFKey($value);
  133. }
  134. /**
  135. * Returns the name attribute.
  136. */
  137. public function getName()
  138. {
  139. return $this->name;
  140. }
  141. /**
  142. * Sets the name attribute.
  143. */
  144. public function setName($name)
  145. {
  146. $this->name = $name;
  147. }
  148. /**
  149. * Gets the phpName for this foreign key (if any).
  150. * @return string
  151. */
  152. public function getPhpName()
  153. {
  154. return $this->phpName;
  155. }
  156. /**
  157. * Sets a phpName to use for this foreign key.
  158. * @param string $name
  159. */
  160. public function setPhpName($name)
  161. {
  162. $this->phpName = $name;
  163. }
  164. /**
  165. * Gets the refPhpName for this foreign key (if any).
  166. * @return string
  167. */
  168. public function getRefPhpName()
  169. {
  170. return $this->refPhpName;
  171. }
  172. /**
  173. * Sets a refPhpName to use for this foreign key.
  174. * @param string $name
  175. */
  176. public function setRefPhpName($name)
  177. {
  178. $this->refPhpName = $name;
  179. }
  180. /**
  181. * Gets the defaultJoin for this foreign key (if any).
  182. * @return string
  183. */
  184. public function getDefaultJoin()
  185. {
  186. return $this->defaultJoin;
  187. }
  188. /**
  189. * Sets a defaultJoin to use for this foreign key.
  190. * @param string $name
  191. */
  192. public function setDefaultJoin($defaultJoin)
  193. {
  194. $this->defaultJoin = $defaultJoin;
  195. }
  196. /**
  197. * Get the foreignTableName of the FK
  198. * @return string foreign table qualified name
  199. */
  200. public function getForeignTableName()
  201. {
  202. if ($this->foreignSchemaName && $this->getTable()->getDatabase()->getPlatform()->supportsSchemas()) {
  203. return $this->foreignSchemaName . '.' . $this->foreignTableCommonName;
  204. } else {
  205. return $this->foreignTableCommonName;
  206. }
  207. }
  208. /**
  209. * Get the foreign table name without schema
  210. * @return string foreign table common name
  211. */
  212. public function getForeignTableCommonName()
  213. {
  214. return $this->foreignTableCommonName;
  215. }
  216. /**
  217. * Set the foreignTableCommonName of the FK
  218. */
  219. public function setForeignTableCommonName($tableName)
  220. {
  221. $this->foreignTableCommonName = $tableName;
  222. }
  223. /**
  224. * Gets the resolved foreign Table model object.
  225. * @return Table
  226. */
  227. public function getForeignTable()
  228. {
  229. return $this->getTable()->getDatabase()->getTable($this->getForeignTableName());
  230. }
  231. /**
  232. * Get the foreignSchemaName of the FK
  233. */
  234. public function getForeignSchemaName()
  235. {
  236. return $this->foreignSchemaName;
  237. }
  238. /**
  239. * Set the foreignSchemaName of the FK
  240. */
  241. public function setForeignSchemaName($schemaName)
  242. {
  243. $this->foreignSchemaName = $schemaName;
  244. }
  245. /**
  246. * Set the parent Table of the foreign key
  247. */
  248. public function setTable(Table $parent)
  249. {
  250. $this->parentTable = $parent;
  251. }
  252. /**
  253. * Get the parent Table of the foreign key
  254. */
  255. public function getTable()
  256. {
  257. return $this->parentTable;
  258. }
  259. /**
  260. * Returns the Name of the table the foreign key is in
  261. */
  262. public function getTableName()
  263. {
  264. return $this->parentTable->getName();
  265. }
  266. /**
  267. * Returns the Name of the schema the foreign key is in
  268. */
  269. public function getSchemaName()
  270. {
  271. return $this->parentTable->getSchema();
  272. }
  273. /**
  274. * Adds a new reference entry to the foreign key.
  275. */
  276. public function addReference($p1, $p2 = null)
  277. {
  278. if (is_array($p1)) {
  279. $this->addReference(@$p1["local"], @$p1["foreign"]);
  280. } else {
  281. if ($p1 instanceof Column) {
  282. $p1 = $p1->getName();
  283. }
  284. if ($p2 instanceof Column) {
  285. $p2 = $p2->getName();
  286. }
  287. $this->localColumns[] = $p1;
  288. $this->foreignColumns[] = $p2;
  289. }
  290. }
  291. /**
  292. * Clear the references of this foreign key
  293. */
  294. public function clearReferences()
  295. {
  296. $this->localColumns[] = array();
  297. $this->foreignColumns[] = array();
  298. }
  299. /**
  300. * Return a comma delimited string of local column names
  301. * @deprecated because Column::makeList() is deprecated; use the array-returning getLocalColumns() instead.
  302. */
  303. public function getLocalColumnNames()
  304. {
  305. return Column::makeList($this->getLocalColumns(), $this->getTable()->getDatabase()->getPlatform());
  306. }
  307. /**
  308. * Return a comma delimited string of foreign column names
  309. * @deprecated because Column::makeList() is deprecated; use the array-returning getForeignColumns() instead.
  310. */
  311. public function getForeignColumnNames()
  312. {
  313. return Column::makeList($this->getForeignColumns(), $this->getTable()->getDatabase()->getPlatform());
  314. }
  315. /**
  316. * Return an array of local column names.
  317. * @return array string[]
  318. */
  319. public function getLocalColumns()
  320. {
  321. return $this->localColumns;
  322. }
  323. /**
  324. * Return an array of local column objects.
  325. * @return array Column[]
  326. */
  327. public function getLocalColumnObjects()
  328. {
  329. $columns = array();
  330. $localTable = $this->getTable();
  331. foreach ($this->localColumns as $columnName) {
  332. $columns []= $localTable->getColumn($columnName);
  333. }
  334. return $columns;
  335. }
  336. /**
  337. * Return a local column name.
  338. * @return string
  339. */
  340. public function getLocalColumnName($index = 0)
  341. {
  342. return $this->localColumns[$index];
  343. }
  344. /**
  345. * Return a local column object.
  346. * @return Column
  347. */
  348. public function getLocalColumn($index = 0)
  349. {
  350. return $this->getTable()->getColumn($this->getLocalColumnName($index));
  351. }
  352. /**
  353. * Utility method to get local column to foreign column
  354. * mapping for this foreign key.
  355. */
  356. public function getLocalForeignMapping()
  357. {
  358. $h = array();
  359. for ($i=0, $size=count($this->localColumns); $i < $size; $i++) {
  360. $h[$this->localColumns[$i]] = $this->foreignColumns[$i];
  361. }
  362. return $h;
  363. }
  364. /**
  365. * Utility method to get local column to foreign column
  366. * mapping for this foreign key.
  367. */
  368. public function getForeignLocalMapping()
  369. {
  370. $h = array();
  371. for ($i=0, $size=count($this->localColumns); $i < $size; $i++) {
  372. $h[$this->foreignColumns[$i]] = $this->localColumns[$i];
  373. }
  374. return $h;
  375. }
  376. /**
  377. * Utility method to get local and foreign column objects
  378. * mapping for this foreign key.
  379. */
  380. public function getColumnObjectsMapping()
  381. {
  382. $mapping = array();
  383. $localTable = $this->getTable();
  384. $foreignTable = $this->getForeignTable();
  385. for ($i=0, $size=count($this->localColumns); $i < $size; $i++) {
  386. $mapping[]= array(
  387. 'local' => $localTable->getColumn($this->localColumns[$i]),
  388. 'foreign' => $foreignTable->getColumn($this->foreignColumns[$i]),
  389. );
  390. }
  391. return $mapping;
  392. }
  393. /**
  394. * Get the foreign column mapped to specified local column.
  395. * @return string Column name.
  396. */
  397. public function getMappedForeignColumn($local)
  398. {
  399. $m = $this->getLocalForeignMapping();
  400. if (isset($m[$local])) {
  401. return $m[$local];
  402. }
  403. return null;
  404. }
  405. /**
  406. * Get the local column mapped to specified foreign column.
  407. * @return string Column name.
  408. */
  409. public function getMappedLocalColumn($foreign)
  410. {
  411. $m = $this->getForeignLocalMapping();
  412. if (isset($m[$foreign])) {
  413. return $m[$foreign];
  414. }
  415. return null;
  416. }
  417. /**
  418. * Return an array of foreign column names.
  419. * @return array string[]
  420. */
  421. public function getForeignColumns()
  422. {
  423. return $this->foreignColumns;
  424. }
  425. /**
  426. * Return an array of foreign column objects.
  427. * @return array Column[]
  428. */
  429. public function getForeignColumnObjects()
  430. {
  431. $columns = array();
  432. $foreignTable = $this->getForeignTable();
  433. foreach ($this->foreignColumns as $columnName) {
  434. $columns []= $foreignTable->getColumn($columnName);
  435. }
  436. return $columns;
  437. }
  438. /**
  439. * Return a foreign column name.
  440. * @return string
  441. */
  442. public function getForeignColumnName($index = 0)
  443. {
  444. return $this->foreignColumns[$index];
  445. }
  446. /**
  447. * Return a foreign column object.
  448. * @return Column
  449. */
  450. public function getForeignColumn($index = 0)
  451. {
  452. return $this->getForeignTable()->getColumn($this->getForeignColumnName($index));
  453. }
  454. /**
  455. * Whether this foreign key uses a required column, or a list of required columns.
  456. *
  457. * @return boolean
  458. */
  459. public function isLocalColumnsRequired()
  460. {
  461. foreach ($this->getLocalColumns() as $columnName) {
  462. if (!$this->getTable()->getColumn($columnName)->isNotNull()) {
  463. return false;
  464. }
  465. }
  466. return true;
  467. }
  468. /**
  469. * Whether this foreign key is also the primary key of the foreign table.
  470. *
  471. * @return boolean
  472. */
  473. public function isForeignPrimaryKey()
  474. {
  475. $lfmap = $this->getLocalForeignMapping();
  476. $foreignTable = $this->getForeignTable();
  477. $foreignPKCols = array();
  478. foreach ($foreignTable->getPrimaryKey() as $fPKCol) {
  479. $foreignPKCols[] = $fPKCol->getName();
  480. }
  481. $foreignCols = array ();
  482. foreach ($this->getLocalColumns() as $colName) {
  483. $foreignCols[] = $foreignTable->getColumn($lfmap[$colName])->getName();
  484. }
  485. return ((count($foreignPKCols) === count($foreignCols)) &&
  486. !array_diff($foreignPKCols, $foreignCols));
  487. }
  488. /**
  489. * Whether this foreign key relies on more than one column binding
  490. *
  491. * @return Boolean
  492. */
  493. public function isComposite()
  494. {
  495. return count($this->getLocalColumns()) > 1;
  496. }
  497. /**
  498. * Whether this foreign key is also the primary key of the local table.
  499. *
  500. * @return boolean
  501. */
  502. public function isLocalPrimaryKey()
  503. {
  504. $localCols = $this->getLocalColumns();
  505. $localPKColumnObjs = $this->getTable()->getPrimaryKey();
  506. $localPKCols = array();
  507. foreach ($localPKColumnObjs as $lPKCol) {
  508. $localPKCols[] = $lPKCol->getName();
  509. }
  510. return ((count($localPKCols) === count($localCols)) &&
  511. !array_diff($localPKCols, $localCols));
  512. }
  513. /**
  514. * Set whether this foreign key should have its creation sql generated.
  515. * @param boolean $v Value to assign to skipSql.
  516. */
  517. public function setSkipSql($v)
  518. {
  519. $this->skipSql = $v;
  520. }
  521. /**
  522. * Skip generating sql for this foreign key.
  523. * @return boolean Value of skipSql.
  524. */
  525. public function isSkipSql()
  526. {
  527. return $this->skipSql;
  528. }
  529. /**
  530. * Whether this foreign key is matched by an invertes foreign key (on foreign table).
  531. *
  532. * This is to prevent duplicate columns being generated for a 1:1 relationship that is represented
  533. * by foreign keys on both tables. I don't know if that's good practice ... but hell, why not
  534. * support it.
  535. *
  536. * @param ForeignKey $fk
  537. * @return boolean
  538. * @link http://propel.phpdb.org/trac/ticket/549
  539. */
  540. public function isMatchedByInverseFK()
  541. {
  542. return (bool) $this->getInverseFK();
  543. }
  544. public function getInverseFK()
  545. {
  546. $foreignTable = $this->getForeignTable();
  547. $map = $this->getForeignLocalMapping();
  548. foreach ($foreignTable->getForeignKeys() as $refFK) {
  549. $fkMap = $refFK->getLocalForeignMapping();
  550. if ( ($refFK->getTableName() == $this->getTableName()) && ($map == $fkMap) ) { // compares keys and values, but doesn't care about order, included check to make sure it's the same table (fixes #679)
  551. return $refFK;
  552. }
  553. }
  554. }
  555. /**
  556. * Get the other foreign keys starting on the same table
  557. * Used in many-to-many relationships
  558. *
  559. * @return ForeignKey
  560. */
  561. public function getOtherFks()
  562. {
  563. $fks = array();
  564. foreach ($this->getTable()->getForeignKeys() as $fk) {
  565. if ($fk !== $this) {
  566. $fks[]= $fk;
  567. }
  568. }
  569. return $fks;
  570. }
  571. /**
  572. * @see XMLElement::appendXml(DOMNode)
  573. */
  574. public function appendXml(DOMNode $node)
  575. {
  576. $doc = ($node instanceof DOMDocument) ? $node : $node->ownerDocument;
  577. $fkNode = $node->appendChild($doc->createElement('foreign-key'));
  578. $fkNode->setAttribute('foreignTable', $this->getForeignTableCommonName());
  579. if ($schema = $this->getForeignSchemaName()) {
  580. $fkNode->setAttribute('foreignSchema', $schema);
  581. }
  582. $fkNode->setAttribute('name', $this->getName());
  583. if ($this->getPhpName()) {
  584. $fkNode->setAttribute('phpName', $this->getPhpName());
  585. }
  586. if ($this->getRefPhpName()) {
  587. $fkNode->setAttribute('refPhpName', $this->getRefPhpName());
  588. }
  589. if ($this->getDefaultJoin()) {
  590. $fkNode->setAttribute('defaultJoin', $this->getDefaultJoin());
  591. }
  592. if ($this->getOnDelete()) {
  593. $fkNode->setAttribute('onDelete', $this->getOnDelete());
  594. }
  595. if ($this->getOnUpdate()) {
  596. $fkNode->setAttribute('onUpdate', $this->getOnUpdate());
  597. }
  598. for ($i=0, $size=count($this->localColumns); $i < $size; $i++) {
  599. $refNode = $fkNode->appendChild($doc->createElement('reference'));
  600. $refNode->setAttribute('local', $this->localColumns[$i]);
  601. $refNode->setAttribute('foreign', $this->foreignColumns[$i]);
  602. }
  603. foreach ($this->vendorInfos as $vi) {
  604. $vi->appendXml($fkNode);
  605. }
  606. }
  607. }