PageRenderTime 38ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/Nette/Database/Reflection/DiscoveredReflection.php

https://github.com/stekycz/nette
PHP | 186 lines | 123 code | 43 blank | 20 comment | 23 complexity | 2bb4c40cbf7d647a0f474bebf3cb4a2f MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * This file is part of the Nette Framework (http://nette.org)
  4. *
  5. * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  6. *
  7. * For the full copyright and license information, please view
  8. * the file license.txt that was distributed with this source code.
  9. */
  10. namespace Nette\Database\Reflection;
  11. use Nette;
  12. /**
  13. * Reflection metadata class with discovery for a database.
  14. *
  15. * @author Jan Skrasek
  16. */
  17. class DiscoveredReflection extends Nette\Object implements Nette\Database\IReflection
  18. {
  19. /** @var Nette\Database\Connection */
  20. protected $connection;
  21. /** @var Nette\Caching\Cache */
  22. protected $cache;
  23. /** @var array */
  24. protected $structure = array();
  25. /** @var array */
  26. protected $loadedStructure;
  27. /**
  28. * Create autodiscovery structure.
  29. */
  30. public function __construct(Nette\Database\Connection $connection, Nette\Caching\IStorage $cacheStorage = NULL)
  31. {
  32. $this->connection = $connection;
  33. if ($cacheStorage) {
  34. $this->cache = new Nette\Caching\Cache($cacheStorage, 'Nette.Database.' . md5($connection->getDsn()));
  35. $this->structure = $this->loadedStructure = $this->cache->load('structure') ?: array();
  36. }
  37. }
  38. public function __destruct()
  39. {
  40. if ($this->cache && $this->structure !== $this->loadedStructure) {
  41. $this->cache->save('structure', $this->structure);
  42. }
  43. }
  44. public function getPrimary($table)
  45. {
  46. $primary = & $this->structure['primary'][strtolower($table)];
  47. if (isset($primary)) {
  48. return empty($primary) ? NULL : $primary;
  49. }
  50. $columns = $this->connection->getSupplementalDriver()->getColumns($table);
  51. $primary = array();
  52. foreach ($columns as $column) {
  53. if ($column['primary']) {
  54. $primary[] = $column['name'];
  55. }
  56. }
  57. if (count($primary) === 0) {
  58. return NULL;
  59. } elseif (count($primary) === 1) {
  60. $primary = reset($primary);
  61. }
  62. return $primary;
  63. }
  64. public function getHasManyReference($table, $key, $refresh = TRUE)
  65. {
  66. if (isset($this->structure['hasMany'][strtolower($table)])) {
  67. $candidates = $columnCandidates = array();
  68. foreach ($this->structure['hasMany'][strtolower($table)] as $targetPair) {
  69. list($targetColumn, $targetTable) = $targetPair;
  70. if (stripos($targetTable, $key) === FALSE) {
  71. continue;
  72. }
  73. $candidates[] = array($targetTable, $targetColumn);
  74. if (stripos($targetColumn, $table) !== FALSE) {
  75. $columnCandidates[] = $candidate = array($targetTable, $targetColumn);
  76. if (strtolower($targetTable) === strtolower($key)) {
  77. return $candidate;
  78. }
  79. }
  80. }
  81. if (count($columnCandidates) === 1) {
  82. return reset($columnCandidates);
  83. } elseif (count($candidates) === 1) {
  84. return reset($candidates);
  85. }
  86. foreach ($candidates as $candidate) {
  87. list($targetTable, $targetColumn) = $candidate;
  88. if (strtolower($targetTable) === strtolower($key)) {
  89. return $candidate;
  90. }
  91. }
  92. }
  93. if ($refresh) {
  94. $this->reloadAllForeignKeys();
  95. return $this->getHasManyReference($table, $key, FALSE);
  96. }
  97. if (empty($candidates)) {
  98. throw new MissingReferenceException("No reference found for \${$table}->related({$key}).");
  99. } else {
  100. throw new AmbiguousReferenceKeyException('Ambiguous joining column in related call.');
  101. }
  102. }
  103. public function getBelongsToReference($table, $key, $refresh = TRUE)
  104. {
  105. if (isset($this->structure['belongsTo'][strtolower($table)])) {
  106. foreach ($this->structure['belongsTo'][strtolower($table)] as $column => $targetTable) {
  107. if (stripos($column, $key) !== FALSE) {
  108. return array($targetTable, $column);
  109. }
  110. }
  111. }
  112. if ($refresh) {
  113. $this->reloadForeignKeys($table);
  114. return $this->getBelongsToReference($table, $key, FALSE);
  115. }
  116. throw new MissingReferenceException("No reference found for \${$table}->{$key}.");
  117. }
  118. protected function reloadAllForeignKeys()
  119. {
  120. foreach ($this->connection->getSupplementalDriver()->getTables() as $table) {
  121. if ($table['view'] == FALSE) {
  122. $this->reloadForeignKeys($table['name']);
  123. }
  124. }
  125. foreach ($this->structure['hasMany'] as & $table) {
  126. uksort($table, function($a, $b) {
  127. return strlen($a) - strlen($b);
  128. });
  129. }
  130. }
  131. protected function reloadForeignKeys($table)
  132. {
  133. foreach ($this->connection->getSupplementalDriver()->getForeignKeys($table) as $row) {
  134. $this->structure['belongsTo'][strtolower($table)][$row['local']] = $row['table'];
  135. $this->structure['hasMany'][strtolower($row['table'])][$row['local'] . $table] = array($row['local'], $table);
  136. }
  137. if (isset($this->structure['belongsTo'][$table])) {
  138. uksort($this->structure['belongsTo'][$table], function($a, $b) {
  139. return strlen($a) - strlen($b);
  140. });
  141. }
  142. }
  143. }