domain_microsite-1.0.0-alpha4/domain_microsite.module
domain_microsite.module
<?php
/**
* @file
* Allows creating microsites at paths using the Domain module/ecosystem.
*/
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\domain\DomainInterface;
use Drupal\domain_microsite\DomainMicrositeConstants;
/**
* Implements hook_help().
*/
function domain_microsite_help($route_name, RouteMatchInterface $route_match) {
if ($route_name == 'help.page.domain_microsite') {
$text = file_get_contents(dirname(__FILE__) . "/README.md");
$output = nl2br($text);
return $output;
}
}
/**
* Implements hook_domain_request_alter().
*
* Sets the requested domain (current/active domain) to a domain microsite if
* the request path is a subpath of a domain microsite base path.
*/
function domain_microsite_domain_request_alter(DomainInterface &$request_domain) {
// Stores calculated domain.
static $_domain;
if (isset($_domain)) {
$request_domain = $_domain;
}
else {
global $base_path;
$current_user = \Drupal::currentUser();
// Permission should match Drupal\domain\Access\DomainAccessCheck::access().
$current_user_is_admin = $current_user->hasPermission('administer domains') || $current_user->hasPermission('access inactive domains');
$request = parse_url($request_domain->getUrl());
$path = trim(substr($request['path'], strlen($base_path)), '/');
if ($path == '') {
return;
}
// Get eligible domain microsites on the requested hostname.
$microsites = [];
$domains = \Drupal::entityTypeManager()->getStorage('domain')->loadMultiple();
foreach ($domains as $domain) {
$parent_id = domain_microsite_parent_id($domain);
$microsite_path = domain_microsite_base_path($domain);
if ($microsite_path != '' && $parent_id != '' && isset($domains[$parent_id]) && $request['host'] == $domains[$parent_id]->getHostname()) {
$microsites[$microsite_path] = $domain->id();
}
}
// Compare request path against eligible domain microsite base paths,
// starting with the longest path possible, and if a match exists,
// set that domain microsite as the request domain.
do {
if (isset($microsites[$path])) {
$matched_domain = $domains[$microsites[$path]];
// If matched domain is inactive, do not switch unless admin.
if (!$matched_domain->status() && !$current_user_is_admin) {
break;
}
// Matched microsite should use the domain alias configuration of its
// parent domain (which would be the existing request domain).
if ($alias = $request_domain->get('alias')) {
$matched_domain->set('alias', $alias);
}
// Set matched microsite as new request domain.
$request_domain = $matched_domain;
$request_domain->setMatchType();
$_domain = $request_domain;
break;
}
// Remove last child of request path and check again.
$path = substr($path, 0, strrpos($path, '/'));
} while ($path != '');
}
}
/**
* Implements hook_ENTITY_TYPE_load() for domain.
*
* Sets domain microsite properties for path and url with working urls.
*/
function domain_microsite_domain_load($domains) {
global $base_path;
$original_base_path = $base_path;
foreach ($domains as $domain) {
$parent_id = domain_microsite_parent_id($domain);
$microsite_path = domain_microsite_base_path($domain);
if ($parent_id != '' && $microsite_path != '') {
// Must set and re-set hostname and global base path because of how setUrl
// and setPath work.
$original_hostname = $domain->getHostname();
$parent_domain = \Drupal::entityTypeManager()->getStorage('domain')->load($parent_id);
$domain->setHostname($parent_domain->getHostname());
$domain->setUrl();
$base_path = $base_path . $microsite_path . '/';
$domain->setPath();
$base_path = $original_base_path;
$domain->setHostname($original_hostname);
}
}
}
/**
* Implements hook_form_FORM_ID_alter() for domain_admin_overview_form.
*
* Modify domain admin overview list to make sense with domain microsites.
*/
function domain_microsite_form_domain_admin_overview_form_alter(&$form, FormStateInterface $form_state, $form_id) {
// Override hostname header to be more generic.
$form['domains']['#header']['hostname'] = t('Site URL');
// Modify row data to include domain microsite values.
foreach ($form['domains']['#domains'] as $domain) {
$domain_id = $domain->id();
// Override hostname column value with site url.
$url = $domain->getPath();
$form['domains'][$domain_id]['hostname']['#markup'] = t('<a href=:url>@name</a>', [
':url' => $url,
'@name' => $url,
]);
// Remove make default operation link for microsites.
if ($domain->getThirdPartySetting('domain_microsite', 'is_domain_microsite')) {
unset($form['domains'][$domain_id]['operations']['data']['#links']['default']);
}
}
}
/**
* Implements hook_form_FORM_ID_alter() for domain_edit_form.
*
* Adds domain microsite fields and functionality to domain edit form.
*/
function domain_microsite_form_domain_edit_form_alter(&$form, FormStateInterface $form_state, $form_id) {
$domain = $form_state->getFormObject()->getEntity();
$domain_id = $domain->id();
$is_domain_microsite = $domain->getThirdPartySetting('domain_microsite', 'is_domain_microsite');
$parent_domain_id = $domain->getThirdPartySetting('domain_microsite', 'parent_domain_id');
$base_path = $domain->getThirdPartySetting('domain_microsite', 'base_path');
// Add domain microsite by path fields.
$form['domain_microsite'] = [
'#type' => 'fieldset',
'#title' => t('Domain microsite by path'),
];
$domains = \Drupal::entityTypeManager()->getStorage('domain')->loadMultiple();
$parent_domains = [''];
foreach ($domains as $_domain) {
$_domain_id = $_domain->id();
if ($_domain->isDefault()) {
$default_domain_id = $_domain_id;
}
if (!($_parent_domain_id = $_domain->getThirdPartySetting('domain_microsite', 'parent_domain_id'))) {
$parent_domains[$_domain_id] = $_domain->getCanonical();
}
if ($_parent_domain_id && $_parent_domain_id == $domain_id) {
$form['domain_microsite']['text']['#markup'] = t('This domain may not be a domain microsite because other domain microsites have specified it as a parent domain.');
return;
}
}
asort($parent_domains);
$form['domain_microsite']['domain_microsite_is_domain_microsite'] = [
'#type' => 'checkbox',
'#title' => t('Make domain microsite'),
'#default_value' => $is_domain_microsite,
'#description' => t('Use this domain record as a domain microsite by path.<br />Cannot be <em>Default domain</em> and ignores <em>Test server response</em>.<br /><strong>Note:</strong> The required fields <em>Hostname</em> and <em>Machine name</em> will be overwritten with auto-generated identifiers. </strong>'),
];
$form['domain_microsite']['domain_microsite_parent_domain_id'] = [
'#type' => 'select',
'#title' => t('Parent domain'),
'#options' => $parent_domains,
'#default_value' => ($parent_domain_id) ? ($parent_domains[$parent_domain_id] ? $parent_domain_id : '') : ($default_domain_id ?? ''),
'#description' => t('The parent domain hostname to use as the canonical hostname of this microsite. The parent domain must not itself be a domain microsite.'),
];
$form['domain_microsite']['domain_microsite_base_path'] = [
'#type' => 'textfield',
'#title' => t('Base path'),
'#size' => 40,
'#maxlength' => 80,
'#default_value' => $base_path,
'#description' => t('The base path for this microsite. Start with a slash. Leave off trailing slash. Example: "/example-microsite".'),
];
$form['is_default']['#states'] = [
'disabled' => [':input[name="domain_microsite_is_domain_microsite"]' => ['checked' => TRUE]],
];
$form['validate_url']['#states'] = [
'disabled' => [':input[name="domain_microsite_is_domain_microsite"]' => ['checked' => TRUE]],
];
if ($is_domain_microsite) {
$form['hostname']['#attributes']['readonly'] = 'readonly';
$form['hostname']['#description'] = t('Auto-generated by Domain Microsite by Path and can not be changed while this domain is a domain microsite.');
}
// Must add custom validation function before ::validateForm.
array_unshift($form['#validate'], 'domain_microsite_domain_edit_form_validate');
}
/**
* Alters domain hostname and machine_name to auto-generated values.
*
* Also does validation for domain microsite fields.
*
* @see domain_microsite_form_domain_edit_form_alter()
*/
function domain_microsite_domain_edit_form_validate($form, FormStateInterface &$form_state) {
$form_object = $form_state->getFormObject();
$domain = $form_object->getEntity();
$is_domain_microsite = $form_state->getValue('domain_microsite_is_domain_microsite');
$parent_domain_id = $form_state->getValue('domain_microsite_parent_domain_id');
$base_path = $form_state->getValue('domain_microsite_base_path');
if ($is_domain_microsite) {
// Auto generate hostname and machine name for new domain microsites.
if ($domain->isNew()) {
$domain->createDomainId();
$new_domainid = $domain->getDomainId();
$new_id = sprintf(DomainMicrositeConstants::DOMAIN_MICROSITE_ID_PATTERN, $new_domainid);
$new_hostname = sprintf(DomainMicrositeConstants::DOMAIN_MICROSITE_HOSTNAME_PATTERN, $new_domainid);
$domain->set('id', $new_id);
$domain->set('hostname', $new_hostname);
// Machine name validation occurred earlier so an existing error must be
// removed to be able to set a new machine name here.
$form_errors = $form_state->getErrors();
unset($form_errors['id']);
$form_state->clearErrors();
foreach ($form_errors as $name => $error_message) {
$form_state->setErrorByName($name, $error_message);
}
// Form state values and form object must be updated for later validation.
$form_object->setEntity($domain);
$form_state->setValue('domain_id', $new_domainid);
$form_state->setValue('id', $new_id);
$form_state->setValue('hostname', $new_hostname);
}
$domain->setThirdPartySetting('domain_microsite', 'is_domain_microsite', $is_domain_microsite);
$domain->setThirdPartySetting('domain_microsite', 'parent_domain_id', $parent_domain_id);
$domain->setThirdPartySetting('domain_microsite', 'base_path', $base_path);
$domain_id = $domain->id();
$domains = \Drupal::entityTypeManager()->getStorage('domain')->loadMultiple();
if (!isset($domains[$parent_domain_id])) {
$form_state->setErrorByName('domain_microsite_parent_domain_id', t('Parent domain may not be empty or the selected domain no longer exists.'));
}
foreach ($domains as $_domain) {
$_domain_id = $_domain->id();
$_parent_domain_id = $_domain->getThirdPartySetting('domain_microsite', 'parent_domain_id');
$_base_path = $_domain->getThirdPartySetting('domain_microsite', 'base_path');
if ($_parent_domain_id && $_parent_domain_id == $domain_id) {
$form_state->setErrorByName('domain_microsite_is_domain_microsite', t('This domain may not be a domain microsite because other domain microsites have specified it as a parent domain.'));
break;
}
if ($domain_id != $_domain_id && $parent_domain_id == $_parent_domain_id && $base_path == $_base_path) {
$form_state->setErrorByName('domain_microsite_base_path', t('A domain microsite already exists with this parent domain and base path.'));
break;
}
}
if ($base_path == '/') {
$form_state->setErrorByName('domain_microsite_base_path', t('The domain microsite base path may not be "/".'));
}
if (!preg_match('/^\//i', $base_path)) {
$form_state->setErrorByName('domain_microsite_base_path', t('The domain microsite base path has to start with a slash.'));
}
if (preg_match('/\/$/i', $base_path)) {
$form_state->setErrorByName('domain_microsite_base_path', t('The domain microsite base path can not end with a slash.'));
}
if (!empty($form_state->getValue('is_default'))) {
$form_state->setErrorByName('is_default', t('Domain microsites cannot be default domain.'));
}
}
else {
foreach ($domain->getThirdPartySettings('domain_microsite') as $key => $value) {
$domain->unsetThirdPartySetting('domain_microsite', $key);
}
}
}
/**
* Implements hook_preprocess().
*
* Adds domain microsite data to contextual links placeholder id. The id is used
* as js storage cache key so this prevents bad cached data.
*
* This needs to run after contextual_preprocess().
*
* @see contextual_preprocess()
*/
function domain_microsite_preprocess(&$variables, $hook, $info) {
if ($id = $variables['title_suffix']['contextual_links']['#id'] ?? FALSE) {
$microsite_path = domain_microsite_base_path();
if ($microsite_path != '') {
$items = explode('|', $id);
$new_items = [];
foreach ($items as $item) {
$parts = explode(':', $item);
// part[2] holds route metadata info.
$parts[2] .= '&domain_microsite_base_path=' . $microsite_path;
$new_items[] = implode(':', $parts);
}
$new_id = implode('|', $new_items);
$variables['title_suffix']['contextual_links']['#id'] = $new_id;
}
}
}
/**
* Returns domain microsite base path or empty string.
*/
function domain_microsite_base_path($domain = NULL) {
if ($domain == NULL) {
$domain = \Drupal::service('domain.negotiator')->getActiveDomain();
}
if (!($domain instanceof DomainInterface)) {
return '';
}
$microsite_path = trim($domain->getThirdPartySetting('domain_microsite', 'base_path', ''), '/');
return $microsite_path;
}
/**
* Returns domain microsite parent id or empty string.
*/
function domain_microsite_parent_id($domain = NULL) {
if ($domain == NULL) {
$domain = \Drupal::service('domain.negotiator')->getActiveDomain();
}
if (!($domain instanceof DomainInterface)) {
return '';
}
$parent_id = $domain->getThirdPartySetting('domain_microsite', 'parent_domain_id', '');
return $parent_id;
}
/**
* Returns the Drupal base url of a given url.
*/
function domain_microsite_scheme_and_host($url) {
global $base_path;
$parsed_url = parse_url($url);
$scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : '';
$host = isset($parsed_url['host']) ? $parsed_url['host'] : '';
$port = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '';
return $scheme . $host . $port . rtrim($base_path, '/');
}
