ForeignKeyConstraint.php 11 KB

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