ForeignKeyConstraint.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. <?php
  2. namespace Doctrine\DBAL\Schema;
  3. use Doctrine\DBAL\Platforms\AbstractPlatform;
  4. use function array_keys;
  5. use function array_map;
  6. use function strrpos;
  7. use function strtolower;
  8. use function strtoupper;
  9. use function substr;
  10. /**
  11. * An abstraction class for a foreign key constraint.
  12. */
  13. class ForeignKeyConstraint extends AbstractAsset implements Constraint
  14. {
  15. /**
  16. * Instance of the referencing table the foreign key constraint is associated with.
  17. *
  18. * @var Table
  19. */
  20. protected $_localTable;
  21. /**
  22. * Asset identifier instances of the referencing table column names the foreign key constraint is associated with.
  23. * array($columnName => Identifier)
  24. *
  25. * @var Identifier[]
  26. */
  27. protected $_localColumnNames;
  28. /**
  29. * Table or asset identifier instance of the referenced table name the foreign key constraint is associated with.
  30. *
  31. * @var Table|Identifier
  32. */
  33. protected $_foreignTableName;
  34. /**
  35. * Asset identifier instances of the referenced table column names the foreign key constraint is associated with.
  36. * array($columnName => Identifier)
  37. *
  38. * @var Identifier[]
  39. */
  40. protected $_foreignColumnNames;
  41. /**
  42. * Options associated with the foreign key constraint.
  43. *
  44. * @var mixed[]
  45. */
  46. protected $_options;
  47. /**
  48. * Initializes the foreign key constraint.
  49. *
  50. * @param string[] $localColumnNames Names of the referencing table columns.
  51. * @param Table|string $foreignTableName Referenced table.
  52. * @param string[] $foreignColumnNames Names of the referenced table columns.
  53. * @param string|null $name Name of the foreign key constraint.
  54. * @param mixed[] $options Options associated with the foreign key constraint.
  55. */
  56. public function __construct(
  57. array $localColumnNames,
  58. $foreignTableName,
  59. array $foreignColumnNames,
  60. $name = null,
  61. array $options = []
  62. ) {
  63. if ($name !== null) {
  64. $this->_setName($name);
  65. }
  66. $this->_localColumnNames = $this->createIdentifierMap($localColumnNames);
  67. if ($foreignTableName instanceof Table) {
  68. $this->_foreignTableName = $foreignTableName;
  69. } else {
  70. $this->_foreignTableName = new Identifier($foreignTableName);
  71. }
  72. $this->_foreignColumnNames = $this->createIdentifierMap($foreignColumnNames);
  73. $this->_options = $options;
  74. }
  75. /**
  76. * @param string[] $names
  77. *
  78. * @return Identifier[]
  79. */
  80. private function createIdentifierMap(array $names): array
  81. {
  82. $identifiers = [];
  83. foreach ($names as $name) {
  84. $identifiers[$name] = new Identifier($name);
  85. }
  86. return $identifiers;
  87. }
  88. /**
  89. * Returns the name of the referencing table
  90. * the foreign key constraint is associated with.
  91. *
  92. * @deprecated Use the table that contains the foreign key as part of its {@see Table::$_fkConstraints} instead.
  93. *
  94. * @return string
  95. */
  96. public function getLocalTableName()
  97. {
  98. return $this->_localTable->getName();
  99. }
  100. /**
  101. * Sets the Table instance of the referencing table
  102. * the foreign key constraint is associated with.
  103. *
  104. * @deprecated Use the table that contains the foreign key as part of its {@see Table::$_fkConstraints} instead.
  105. *
  106. * @param Table $table Instance of the referencing table.
  107. *
  108. * @return void
  109. */
  110. public function setLocalTable(Table $table)
  111. {
  112. $this->_localTable = $table;
  113. }
  114. /**
  115. * @deprecated Use the table that contains the foreign key as part of its {@see Table::$_fkConstraints} instead.
  116. *
  117. * @return Table
  118. */
  119. public function getLocalTable()
  120. {
  121. return $this->_localTable;
  122. }
  123. /**
  124. * Returns the names of the referencing table columns
  125. * the foreign key constraint is associated with.
  126. *
  127. * @return string[]
  128. */
  129. public function getLocalColumns()
  130. {
  131. return array_keys($this->_localColumnNames);
  132. }
  133. /**
  134. * Returns the quoted representation of the referencing table column names
  135. * the foreign key constraint is associated with.
  136. *
  137. * But only if they were defined with one or the referencing table column name
  138. * is a keyword reserved by the platform.
  139. * Otherwise the plain unquoted value as inserted is returned.
  140. *
  141. * @param AbstractPlatform $platform The platform to use for quotation.
  142. *
  143. * @return string[]
  144. */
  145. public function getQuotedLocalColumns(AbstractPlatform $platform)
  146. {
  147. $columns = [];
  148. foreach ($this->_localColumnNames as $column) {
  149. $columns[] = $column->getQuotedName($platform);
  150. }
  151. return $columns;
  152. }
  153. /**
  154. * Returns unquoted representation of local table column names for comparison with other FK
  155. *
  156. * @return string[]
  157. */
  158. public function getUnquotedLocalColumns()
  159. {
  160. return array_map([$this, 'trimQuotes'], $this->getLocalColumns());
  161. }
  162. /**
  163. * Returns unquoted representation of foreign table column names for comparison with other FK
  164. *
  165. * @return string[]
  166. */
  167. public function getUnquotedForeignColumns()
  168. {
  169. return array_map([$this, 'trimQuotes'], $this->getForeignColumns());
  170. }
  171. /**
  172. * {@inheritdoc}
  173. *
  174. * @deprecated Use {@see getLocalColumns()} instead.
  175. *
  176. * @see getLocalColumns
  177. */
  178. public function getColumns()
  179. {
  180. return $this->getLocalColumns();
  181. }
  182. /**
  183. * Returns the quoted representation of the referencing table column names
  184. * the foreign key constraint is associated with.
  185. *
  186. * But only if they were defined with one or the referencing table column name
  187. * is a keyword reserved by the platform.
  188. * Otherwise the plain unquoted value as inserted is returned.
  189. *
  190. * @deprecated Use {@see getQuotedLocalColumns()} instead.
  191. *
  192. * @see getQuotedLocalColumns
  193. *
  194. * @param AbstractPlatform $platform The platform to use for quotation.
  195. *
  196. * @return string[]
  197. */
  198. public function getQuotedColumns(AbstractPlatform $platform)
  199. {
  200. return $this->getQuotedLocalColumns($platform);
  201. }
  202. /**
  203. * Returns the name of the referenced table
  204. * the foreign key constraint is associated with.
  205. *
  206. * @return string
  207. */
  208. public function getForeignTableName()
  209. {
  210. return $this->_foreignTableName->getName();
  211. }
  212. /**
  213. * Returns the non-schema qualified foreign table name.
  214. *
  215. * @return string
  216. */
  217. public function getUnqualifiedForeignTableName()
  218. {
  219. $name = $this->_foreignTableName->getName();
  220. $position = strrpos($name, '.');
  221. if ($position !== false) {
  222. $name = substr($name, $position + 1);
  223. }
  224. return strtolower($name);
  225. }
  226. /**
  227. * Returns the quoted representation of the referenced table name
  228. * the foreign key constraint is associated with.
  229. *
  230. * But only if it was defined with one or the referenced table name
  231. * is a keyword reserved by the platform.
  232. * Otherwise the plain unquoted value as inserted is returned.
  233. *
  234. * @param AbstractPlatform $platform The platform to use for quotation.
  235. *
  236. * @return string
  237. */
  238. public function getQuotedForeignTableName(AbstractPlatform $platform)
  239. {
  240. return $this->_foreignTableName->getQuotedName($platform);
  241. }
  242. /**
  243. * Returns the names of the referenced table columns
  244. * the foreign key constraint is associated with.
  245. *
  246. * @return string[]
  247. */
  248. public function getForeignColumns()
  249. {
  250. return array_keys($this->_foreignColumnNames);
  251. }
  252. /**
  253. * Returns the quoted representation of the referenced table column names
  254. * the foreign key constraint is associated with.
  255. *
  256. * But only if they were defined with one or the referenced table column name
  257. * is a keyword reserved by the platform.
  258. * Otherwise the plain unquoted value as inserted is returned.
  259. *
  260. * @param AbstractPlatform $platform The platform to use for quotation.
  261. *
  262. * @return string[]
  263. */
  264. public function getQuotedForeignColumns(AbstractPlatform $platform)
  265. {
  266. $columns = [];
  267. foreach ($this->_foreignColumnNames as $column) {
  268. $columns[] = $column->getQuotedName($platform);
  269. }
  270. return $columns;
  271. }
  272. /**
  273. * Returns whether or not a given option
  274. * is associated with the foreign key constraint.
  275. *
  276. * @param string $name Name of the option to check.
  277. *
  278. * @return bool
  279. */
  280. public function hasOption($name)
  281. {
  282. return isset($this->_options[$name]);
  283. }
  284. /**
  285. * Returns an option associated with the foreign key constraint.
  286. *
  287. * @param string $name Name of the option the foreign key constraint is associated with.
  288. *
  289. * @return mixed
  290. */
  291. public function getOption($name)
  292. {
  293. return $this->_options[$name];
  294. }
  295. /**
  296. * Returns the options associated with the foreign key constraint.
  297. *
  298. * @return mixed[]
  299. */
  300. public function getOptions()
  301. {
  302. return $this->_options;
  303. }
  304. /**
  305. * Returns the referential action for UPDATE operations
  306. * on the referenced table the foreign key constraint is associated with.
  307. *
  308. * @return string|null
  309. */
  310. public function onUpdate()
  311. {
  312. return $this->onEvent('onUpdate');
  313. }
  314. /**
  315. * Returns the referential action for DELETE operations
  316. * on the referenced table the foreign key constraint is associated with.
  317. *
  318. * @return string|null
  319. */
  320. public function onDelete()
  321. {
  322. return $this->onEvent('onDelete');
  323. }
  324. /**
  325. * Returns the referential action for a given database operation
  326. * on the referenced table the foreign key constraint is associated with.
  327. *
  328. * @param string $event Name of the database operation/event to return the referential action for.
  329. */
  330. private function onEvent($event): ?string
  331. {
  332. if (isset($this->_options[$event])) {
  333. $onEvent = strtoupper($this->_options[$event]);
  334. if ($onEvent !== 'NO ACTION' && $onEvent !== 'RESTRICT') {
  335. return $onEvent;
  336. }
  337. }
  338. return null;
  339. }
  340. /**
  341. * Checks whether this foreign key constraint intersects the given index columns.
  342. *
  343. * Returns `true` if at least one of this foreign key's local columns
  344. * matches one of the given index's columns, `false` otherwise.
  345. *
  346. * @param Index $index The index to be checked against.
  347. *
  348. * @return bool
  349. */
  350. public function intersectsIndexColumns(Index $index)
  351. {
  352. foreach ($index->getColumns() as $indexColumn) {
  353. foreach ($this->_localColumnNames as $localColumn) {
  354. if (strtolower($indexColumn) === strtolower($localColumn->getName())) {
  355. return true;
  356. }
  357. }
  358. }
  359. return false;
  360. }
  361. }