class AjaxResponseAttachmentsProcessor in Content-Security-Policy 8
Processes attachments of AJAX responses.
Hierarchy
- class \Drupal\csp_extras\Ajax\AjaxResponseAttachmentsProcessor implements AttachmentsResponseProcessorInterface
Expanded class hierarchy of AjaxResponseAttachmentsProcessor
See also
\Drupal\Core\Ajax\AjaxResponse
\Drupal\Core\Render\MainContent\AjaxRenderer
1 string reference to 'AjaxResponseAttachmentsProcessor'
- csp_extras.services.yml in csp_extras/
csp_extras.services.yml - csp_extras/csp_extras.services.yml
1 service uses AjaxResponseAttachmentsProcessor
File
- csp_extras/
src/ Ajax/ AjaxResponseAttachmentsProcessor.php, line 23
Namespace
Drupal\csp_extras\AjaxView source
class AjaxResponseAttachmentsProcessor implements AttachmentsResponseProcessorInterface {
/**
* The asset resolver service.
*
* @var \Drupal\Core\Asset\AssetResolverInterface
*/
protected $assetResolver;
/**
* A config object for the system performance configuration.
*
* @var \Drupal\Core\Config\Config
*/
protected $config;
/**
* The request stack.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
protected $requestStack;
/**
* The module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* The time service.
*
* @var \Drupal\Component\Datetime\TimeInterface
*/
protected $time;
/**
* Constructs a AjaxResponseAttachmentsProcessor object.
*
* @param \Drupal\Core\Asset\AssetResolverInterface $asset_resolver
* An asset resolver.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* A config factory for retrieving required config objects.
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
* The request stack.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
* @param \Drupal\Component\Datetime\TimeInterface $time
* The time service.
*/
public function __construct(AssetResolverInterface $asset_resolver, ConfigFactoryInterface $config_factory, RequestStack $request_stack, ModuleHandlerInterface $module_handler, TimeInterface $time) {
$this->assetResolver = $asset_resolver;
$this->config = $config_factory
->get('system.performance');
$this->requestStack = $request_stack;
$this->moduleHandler = $module_handler;
$this->time = $time;
}
/**
* {@inheritdoc}
*/
public function processAttachments(AttachmentsInterface $response) {
// @todo Convert to assertion once https://www.drupal.org/node/2408013 lands
if (!$response instanceof AjaxResponse) {
throw new \InvalidArgumentException('\\Drupal\\Core\\Ajax\\AjaxResponse instance expected.');
}
$request = $this->requestStack
->getCurrentRequest();
if ($response
->getContent() == '{}') {
$response
->setData($this
->buildAttachmentsCommands($response, $request));
}
return $response;
}
/**
* Prepares the AJAX commands to attach assets.
*
* @param \Drupal\Core\Ajax\AjaxResponse $response
* The AJAX response to update.
* @param \Symfony\Component\HttpFoundation\Request $request
* The request object that the AJAX is responding to.
*
* @return array
* An array of commands ready to be returned as JSON.
*/
protected function buildAttachmentsCommands(AjaxResponse $response, Request $request) {
$ajax_page_state = $request->request
->get('ajax_page_state');
// Aggregate CSS/JS if necessary, but only during normal site operation.
$optimize_css = !defined('MAINTENANCE_MODE') && $this->config
->get('css.preprocess');
$optimize_js = !defined('MAINTENANCE_MODE') && $this->config
->get('js.preprocess');
$attachments = $response
->getAttachments();
// Resolve the attached libraries into asset collections.
$assets = new AttachedAssets();
$assets
->setLibraries(isset($attachments['library']) ? $attachments['library'] : [])
->setAlreadyLoadedLibraries(isset($ajax_page_state['libraries']) ? explode(',', $ajax_page_state['libraries']) : [])
->setSettings(isset($attachments['drupalSettings']) ? $attachments['drupalSettings'] : []);
$css_assets = $this->assetResolver
->getCssAssets($assets, $optimize_css);
list($js_assets_header, $js_assets_footer) = $this->assetResolver
->getJsAssets($assets, $optimize_js);
// First, AttachedAssets::setLibraries() ensures duplicate libraries are
// removed: it converts it to a set of libraries if necessary. Second,
// AssetResolver::getJsSettings() ensures $assets contains the final set of
// JavaScript settings. AttachmentsResponseProcessorInterface also mandates
// that the response it processes contains the final attachment values, so
// update both the 'library' and 'drupalSettings' attachments accordingly.
$attachments['library'] = $assets
->getLibraries();
$attachments['drupalSettings'] = $assets
->getSettings();
$response
->setAttachments($attachments);
// Render the HTML to load these files, and add AJAX commands to insert this
// HTML in the page. Settings are handled separately, afterwards.
$settings = [];
if (isset($js_assets_header['drupalSettings'])) {
$settings = $js_assets_header['drupalSettings']['data'];
unset($js_assets_header['drupalSettings']);
}
if (isset($js_assets_footer['drupalSettings'])) {
$settings = $js_assets_footer['drupalSettings']['data'];
unset($js_assets_footer['drupalSettings']);
}
// Remove assets that are not available to all browsers.
$css_assets = array_filter($css_assets, [
$this,
'filterBrowserAssets',
]);
$js_assets = array_filter(array_merge($js_assets_header, $js_assets_footer), [
$this,
'filterBrowserAssets',
]);
if (!empty($css_assets) || !empty($js_assets)) {
$default_query_string = \Drupal::state()
->get('system.css_js_query_string') ?: '0';
$css_assets = array_map(function ($css_asset) use ($default_query_string) {
$asset = [
'type' => 'stylesheet',
'attributes' => [
'media' => $css_asset['media'],
'href' => file_url_transform_relative(file_create_url($css_asset['data'])),
],
];
if (isset($css_asset['attributes'])) {
$asset['attributes'] += $css_asset['attributes'];
}
// Only add the cache-busting query string if this isn't an
// aggregate file.
if ($css_asset['type'] == 'file' && !isset($css_asset['preprocessed'])) {
$query_string_separator = strpos($css_asset['data'], '?') !== FALSE ? '&' : '?';
$asset['attributes']['href'] .= $query_string_separator . $default_query_string;
}
return $asset;
}, $css_assets);
$js_assets = array_map(function ($js_asset) use ($default_query_string) {
$asset = [
'type' => 'script',
'attributes' => [
'src' => file_url_transform_relative(file_create_url($js_asset['data'])),
],
];
if (isset($js_asset['attributes'])) {
$asset['attributes'] += $js_asset['attributes'];
}
// Only add the cache-busting query string if this isn't an
// aggregate file.
if ($js_asset['type'] == 'file' && !isset($js_asset['preprocessed'])) {
$query_string = $js_asset['version'] == -1 ? $default_query_string : 'v=' . $js_asset['version'];
$query_string_separator = strpos($js_asset['data'], '?') !== FALSE ? '&' : '?';
$asset['attributes']['src'] .= $query_string_separator . ($js_asset['cache'] ? $query_string : $this->time
->getRequestTime());
}
return $asset;
}, $js_assets);
$response
->addCommand(new AddAssetsCommand(array_merge($css_assets, $js_assets)), TRUE);
}
// Prepend a command to merge changes and additions to drupalSettings.
if (!empty($settings)) {
// During Ajax requests basic path-specific settings are excluded from
// new drupalSettings values. The original page where this request comes
// from already has the right values. An Ajax request would update them
// with values for the Ajax request and incorrectly override the page's
// values.
// @see system_js_settings_alter()
unset($settings['path']);
$response
->addCommand(new SettingsCommand($settings, TRUE), TRUE);
}
$commands = $response
->getCommands();
$this->moduleHandler
->alter('ajax_render', $commands);
return $commands;
}
/**
* Filter function for assets that are browser-restricted.
*
* @param array $asset
* An asset definition.
*
* @return bool
* FALSE if the asset is restricted to certain browsers.
*/
private static function filterBrowserAssets(array $asset) {
// @see Drupal\Core\Render\Element\HtmlTag::preRenderConditionalComments
if (isset($asset['browsers']['IE']) && $asset['browsers']['IE'] !== TRUE || isset($asset['browsers']['!IE']) && $asset['browsers']['!IE'] !== TRUE) {
trigger_error('Library asset with browser restrictions was omitted from AJAX response.', E_USER_WARNING);
return FALSE;
}
return TRUE;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
AjaxResponseAttachmentsProcessor:: |
protected | property | The asset resolver service. | |
AjaxResponseAttachmentsProcessor:: |
protected | property | A config object for the system performance configuration. | |
AjaxResponseAttachmentsProcessor:: |
protected | property | The module handler. | |
AjaxResponseAttachmentsProcessor:: |
protected | property | The request stack. | |
AjaxResponseAttachmentsProcessor:: |
protected | property | The time service. | |
AjaxResponseAttachmentsProcessor:: |
protected | function | Prepares the AJAX commands to attach assets. | |
AjaxResponseAttachmentsProcessor:: |
private static | function | Filter function for assets that are browser-restricted. | |
AjaxResponseAttachmentsProcessor:: |
public | function |
Processes the attachments of a response that has attachments. Overrides AttachmentsResponseProcessorInterface:: |
|
AjaxResponseAttachmentsProcessor:: |
public | function | Constructs a AjaxResponseAttachmentsProcessor object. |