DomainNegotiator.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. <?php
  2. namespace Drupal\domain;
  3. use Drupal\Core\Config\ConfigFactoryInterface;
  4. use Drupal\Core\Entity\EntityTypeManagerInterface;
  5. use Drupal\Core\Extension\ModuleHandlerInterface;
  6. use Symfony\Component\HttpFoundation\RequestStack;
  7. /**
  8. * {@inheritdoc}
  9. */
  10. class DomainNegotiator implements DomainNegotiatorInterface {
  11. /**
  12. * Defines record matching types when dealing with request alteration.
  13. *
  14. * @see hook_domain_request_alter().
  15. */
  16. const DOMAIN_MATCH_NONE = 0;
  17. const DOMAIN_MATCH_EXACT = 1;
  18. const DOMAIN_MATCH_ALIAS = 2;
  19. /**
  20. * The HTTP_HOST value of the request.
  21. *
  22. * @var string
  23. */
  24. protected $httpHost;
  25. /**
  26. * The domain record returned by the lookup request.
  27. *
  28. * @var \Drupal\domain\DomainInterface
  29. */
  30. protected $domain;
  31. /**
  32. * The domain storage class.
  33. *
  34. * @var \Drupal\domain\DomainStorageInterface
  35. */
  36. protected $domainStorage;
  37. /**
  38. * The entity type manager.
  39. *
  40. * @var \Drupal\Core\Entity\EntityTypeManagerInterface
  41. */
  42. protected $entityTypeManager;
  43. /**
  44. * The request stack object.
  45. *
  46. * @var \Symfony\Component\HttpFoundation\RequestStack
  47. */
  48. protected $requestStack;
  49. /**
  50. * The module handler.
  51. *
  52. * @var \Drupal\Core\Extension\ModuleHandlerInterface
  53. */
  54. protected $moduleHandler;
  55. /**
  56. * The config factory.
  57. *
  58. * @var \Drupal\Core\Config\ConfigFactoryInterface
  59. */
  60. protected $configFactory;
  61. /**
  62. * Constructs a DomainNegotiator object.
  63. *
  64. * @param \Symfony\Component\HttpFoundation\RequestStack $requestStack
  65. * The request stack object.
  66. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
  67. * The module handler.
  68. * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
  69. * The entity type manager.
  70. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
  71. * The config factory.
  72. */
  73. public function __construct(RequestStack $requestStack, ModuleHandlerInterface $module_handler, EntityTypeManagerInterface $entity_type_manager, ConfigFactoryInterface $config_factory) {
  74. $this->requestStack = $requestStack;
  75. $this->moduleHandler = $module_handler;
  76. $this->entityTypeManager = $entity_type_manager;
  77. $this->domainStorage = $this->entityTypeManager->getStorage('domain');
  78. $this->configFactory = $config_factory;
  79. }
  80. /**
  81. * {@inheritdoc}
  82. */
  83. public function setRequestDomain($httpHost, $reset = FALSE) {
  84. // @TODO: Investigate caching methods.
  85. $this->setHttpHost($httpHost);
  86. // Try to load a direct match.
  87. if ($domain = $this->domainStorage->loadByHostname($httpHost)) {
  88. // If the load worked, set an exact match flag for the hook.
  89. $domain->setMatchType(self::DOMAIN_MATCH_EXACT);
  90. }
  91. // If a straight load fails, create a base domain for checking. This data
  92. // is required for hook_domain_request_alter().
  93. else {
  94. $values = ['hostname' => $httpHost];
  95. /** @var \Drupal\domain\DomainInterface $domain */
  96. $domain = $this->domainStorage->create($values);
  97. $domain->setMatchType(self::DOMAIN_MATCH_NONE);
  98. }
  99. // Make sure all modules are loaded and can alter the found domains.
  100. // See https://www.drupal.org/node/2896434#comment-12267208.
  101. $this->moduleHandler->reload();
  102. foreach ($this->moduleHandler->getImplementations('domain_request_alter') as $module) {
  103. $this->moduleHandler->load($module);
  104. }
  105. // Now check with modules (like Domain Alias) that register alternate
  106. // lookup systems with the main module.
  107. $this->moduleHandler->alter('domain_request', $domain);
  108. // We must have registered a valid id, else the request made no match.
  109. if (!empty($domain->id())) {
  110. $this->setActiveDomain($domain);
  111. }
  112. // Fallback to default domain if no match.
  113. elseif ($domain = $this->domainStorage->loadDefaultDomain()) {
  114. $this->moduleHandler->alter('domain_request', $domain);
  115. $domain->setMatchType(self::DOMAIN_MATCH_NONE);
  116. if (!empty($domain->id())) {
  117. $this->setActiveDomain($domain);
  118. }
  119. }
  120. }
  121. /**
  122. * {@inheritdoc}
  123. */
  124. public function setActiveDomain(DomainInterface $domain) {
  125. // @TODO: caching
  126. $this->domain = $domain;
  127. }
  128. /**
  129. * Determine the active domain.
  130. */
  131. protected function negotiateActiveDomain() {
  132. $httpHost = $this->negotiateActiveHostname();
  133. $this->setRequestDomain($httpHost);
  134. return $this->domain;
  135. }
  136. /**
  137. * {@inheritdoc}
  138. */
  139. public function getActiveDomain($reset = FALSE) {
  140. if ($reset) {
  141. $this->negotiateActiveDomain();
  142. }
  143. return $this->domain;
  144. }
  145. /**
  146. * {@inheritdoc}
  147. */
  148. public function getActiveId() {
  149. return $this->domain->id();
  150. }
  151. /**
  152. * {@inheritdoc}
  153. */
  154. public function negotiateActiveHostname() {
  155. if ($request = $this->requestStack->getCurrentRequest()) {
  156. $httpHost = $request->getHttpHost();
  157. }
  158. else {
  159. $httpHost = $_SERVER['HTTP_HOST'];
  160. }
  161. $hostname = !empty($httpHost) ? $httpHost : 'localhost';
  162. return $this->domainStorage->prepareHostname($hostname);
  163. }
  164. /**
  165. * {@inheritdoc}
  166. */
  167. public function setHttpHost($httpHost) {
  168. $this->httpHost = $httpHost;
  169. }
  170. /**
  171. * {@inheritdoc}
  172. */
  173. public function getHttpHost() {
  174. return $this->httpHost;
  175. }
  176. /**
  177. * {@inheritdoc}
  178. */
  179. public function isRegisteredDomain($hostname) {
  180. // Direct hostname match always passes.
  181. if ($domain = $this->domainStorage->loadByHostname($hostname)) {
  182. return TRUE;
  183. }
  184. // Check for registered alias matches.
  185. $values = ['hostname' => $hostname];
  186. /** @var \Drupal\domain\DomainInterface $domain */
  187. $domain = $this->domainStorage->create($values);
  188. $domain->setMatchType(self::DOMAIN_MATCH_NONE);
  189. // Now check with modules (like Domain Alias) that register alternate
  190. // lookup systems with the main module.
  191. $this->moduleHandler->alter('domain_request', $domain);
  192. // We must have registered a valid id, else the request made no match.
  193. if (!empty($domain->id())) {
  194. return TRUE;
  195. }
  196. return FALSE;
  197. }
  198. }