DomainNegotiator.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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|null
  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->configFactory = $config_factory;
  78. }
  79. /**
  80. * {@inheritdoc}
  81. */
  82. public function setRequestDomain($httpHost, $reset = FALSE) {
  83. // @TODO: Investigate caching methods.
  84. $this->setHttpHost($httpHost);
  85. // Try to load a direct match.
  86. if ($domain = $this->domainStorage()->loadByHostname($httpHost)) {
  87. // If the load worked, set an exact match flag for the hook.
  88. $domain->setMatchType(self::DOMAIN_MATCH_EXACT);
  89. }
  90. // If a straight load fails, create a base domain for checking. This data
  91. // is required for hook_domain_request_alter().
  92. else {
  93. $values = ['hostname' => $httpHost];
  94. /** @var \Drupal\domain\DomainInterface $domain */
  95. $domain = $this->domainStorage()->create($values);
  96. $domain->setMatchType(self::DOMAIN_MATCH_NONE);
  97. }
  98. // Now check with modules (like Domain Alias) that register alternate
  99. // lookup systems with the main module.
  100. $this->moduleHandler->alter('domain_request', $domain);
  101. // We must have registered a valid id, else the request made no match.
  102. if (!empty($domain->id())) {
  103. $this->setActiveDomain($domain);
  104. }
  105. // Fallback to default domain if no match.
  106. elseif ($domain = $this->domainStorage()->loadDefaultDomain()) {
  107. $this->moduleHandler->alter('domain_request', $domain);
  108. $domain->setMatchType(self::DOMAIN_MATCH_NONE);
  109. if (!empty($domain->id())) {
  110. $this->setActiveDomain($domain);
  111. }
  112. }
  113. }
  114. /**
  115. * {@inheritdoc}
  116. */
  117. public function setActiveDomain(DomainInterface $domain) {
  118. // @TODO: caching
  119. $this->domain = $domain;
  120. }
  121. /**
  122. * Determine the active domain.
  123. */
  124. protected function negotiateActiveDomain() {
  125. $httpHost = $this->negotiateActiveHostname();
  126. $this->setRequestDomain($httpHost);
  127. return $this->domain;
  128. }
  129. /**
  130. * {@inheritdoc}
  131. */
  132. public function getActiveDomain($reset = FALSE) {
  133. if ($reset) {
  134. $this->negotiateActiveDomain();
  135. }
  136. return $this->domain;
  137. }
  138. /**
  139. * {@inheritdoc}
  140. */
  141. public function getActiveId() {
  142. return $this->domain->id();
  143. }
  144. /**
  145. * {@inheritdoc}
  146. */
  147. public function negotiateActiveHostname() {
  148. if ($request = $this->requestStack->getCurrentRequest()) {
  149. $httpHost = $request->getHttpHost();
  150. }
  151. else {
  152. $httpHost = $_SERVER['HTTP_HOST'];
  153. }
  154. $hostname = !empty($httpHost) ? $httpHost : 'localhost';
  155. return $this->domainStorage()->prepareHostname($hostname);
  156. }
  157. /**
  158. * {@inheritdoc}
  159. */
  160. public function setHttpHost($httpHost) {
  161. $this->httpHost = $httpHost;
  162. }
  163. /**
  164. * {@inheritdoc}
  165. */
  166. public function getHttpHost() {
  167. return $this->httpHost;
  168. }
  169. /**
  170. * {@inheritdoc}
  171. */
  172. public function isRegisteredDomain($hostname) {
  173. // Direct hostname match always passes.
  174. if ($domain = $this->domainStorage()->loadByHostname($hostname)) {
  175. return TRUE;
  176. }
  177. // Check for registered alias matches.
  178. $values = ['hostname' => $hostname];
  179. /** @var \Drupal\domain\DomainInterface $domain */
  180. $domain = $this->domainStorage()->create($values);
  181. $domain->setMatchType(self::DOMAIN_MATCH_NONE);
  182. // Now check with modules (like Domain Alias) that register alternate
  183. // lookup systems with the main module.
  184. $this->moduleHandler->alter('domain_request', $domain);
  185. // We must have registered a valid id, else the request made no match.
  186. if (!empty($domain->id())) {
  187. return TRUE;
  188. }
  189. return FALSE;
  190. }
  191. /**
  192. * Retrieves the domain storage handler.
  193. *
  194. * @return \Drupal\domain\DomainStorageInterface
  195. * The domain storage handler.
  196. */
  197. protected function domainStorage() {
  198. if (!$this->domainStorage) {
  199. $this->domainStorage = $this->entityTypeManager->getStorage('domain');
  200. }
  201. return $this->domainStorage;
  202. }
  203. }