updated contrib modules

This commit is contained in:
Bachir Soussi Chiadmi
2018-03-13 14:16:18 +01:00
parent e668535a4e
commit 272fa07ccf
202 changed files with 5165 additions and 1725 deletions
@@ -1,7 +1,30 @@
Admin Toolbar 8.1.22, 2017-XX-XX
Admin Toolbar 8.1.23, 2018-02-06
--------------------------------
Changes since 8.1.22:
- #2924266 by sunlix, romainj, adriancid, samerali: Add a menu link for the
media module.
- #2941184 by daniel.nitsche, adriancid: Remove unwanted comment from
admin.toolbar.css.
- #2912503 by Amsteri, m.abdulqader: Right to left language direction support.
- #2937982 by romainj, adriancid: Auto-generation of menu links conflicts with
other modules.
- #2932873 by vaplas, saravanaprasanth, adriancid: Horizontal mode only works if
the page is loaded in horizontal mode.
- #2935311 by romainj, adriancid: Use the $entityTypeManager variable instead of
the \Drupal::entityTypeManager service.
- #2935449 by adriancid: Add the release information for the 1.22 version in the
CHANGELOG.txt.
- #2932476 by romainj: toolbar.tree library should have a dependency to the
core/drupal library.
- #2931503 by K3vin_nl: Admin toolbar generates invalid class names.
Admin Toolbar 8.1.22, 2018-01-02
--------------------------------
Changes since 8.1.21:
- #2929053 by kkuhnen, eme, adriancid: admin_toolbar.js should use Drupal
behaviors.
- #2929061 by romainj, dsnopek, adriancid: admin_toolbar_links_access_filter
doesn't do anything unless admin_toolbar is enabled.
- #2928836 by eme: One extra pixel line under the admin toolbar.
@@ -8,8 +8,8 @@ type: module
dependencies:
- drupal:toolbar
# Information added by Drupal.org packaging script on 2018-01-02
version: '8.x-1.22'
# Information added by Drupal.org packaging script on 2018-02-06
version: '8.x-1.23'
core: '8.x'
project: 'admin_toolbar'
datestamp: 1514888588
datestamp: 1517936588
@@ -7,3 +7,4 @@ toolbar.tree:
js/admin_toolbar.js: {}
dependencies:
- core/jquery
- core/drupal
@@ -8,6 +8,7 @@
use Drupal\Core\Menu\MenuTreeParameters;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
use Drupal\Component\Utility\Html;
/**
* Implements hook_toolbar_alter().
@@ -90,7 +91,7 @@ function toolbar_tools_menu_navigation_links(array $tree) {
$element->options['attributes']['class'][] = 'toolbar-icon';
$string = strtolower(str_replace(['.', ' ', '_'], ['-', '-', '-'], $definition['id']));
$element->options['attributes']['class'][] = 'toolbar-icon-' . $string;
$element->options['attributes']['class'][] = Html::cleanCssIdentifier('toolbar-icon-' . $string);
$element->options['attributes']['title'] = $link->getDescription();
}
return $tree;
@@ -1,13 +1,15 @@
name: Admin Toolbar Links Access Filter
description: Provides a workaround for the common problem that users with 'Use the administration pages and help' permission see menu links they don't have access permission for. Once the issue <a href='https://www.drupal.org/node/296693'>https://www.drupal.org/node/296693</a> be solved, this module will be deprecated.
package: Administration
dependencies:
- admin_toolbar:admin_toolbar
type: module
# core: 8.x
# Information added by Drupal.org packaging script on 2018-01-02
version: '8.x-1.22'
dependencies:
- admin_toolbar:admin_toolbar
# Information added by Drupal.org packaging script on 2018-02-06
version: '8.x-1.23'
core: '8.x'
project: 'admin_toolbar'
datestamp: 1514888588
datestamp: 1517936588
@@ -8,8 +8,8 @@ type: module
dependencies:
- admin_toolbar:admin_toolbar
# Information added by Drupal.org packaging script on 2018-01-02
version: '8.x-1.22'
# Information added by Drupal.org packaging script on 2018-02-06
version: '8.x-1.23'
core: '8.x'
project: 'admin_toolbar'
datestamp: 1514888588
datestamp: 1517936588
@@ -273,7 +273,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
'weight' => -5,
];
// Add node links for each content type.
foreach (\Drupal::entityTypeManager()->getStorage('node_type')->loadMultiple() as $type) {
foreach ($entityTypeManager->getStorage('node_type')->loadMultiple() as $type) {
$links['node.add.' . $type->id()] = [
'title' => t($type->label()),
'route_name' => 'node.add',
@@ -418,7 +418,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
'weight' => '-1',
];
if ($moduleHandler->moduleExists('webprofiler')) {
$links['admin_menu_tools.devel.webprofiler'] = [
$links['admin_toolbar_tools.devel.webprofiler'] = [
'title' => t('Web Profiler settings'),
'route_name' => 'webprofiler.settings',
'menu_name' => 'admin',
@@ -478,20 +478,33 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
'menu_name' => 'admin',
'parent' => 'admin_development',
];
// Menu link for the Toolbar module.
$links['admin_toolbar_tools.toolbar.settings'] = [
'title' => t('Toolbar settings'),
'route_name' => 'devel.toolbar.settings_form',
'menu_name' => 'admin',
'parent' => 'devel.admin_settings',
];
}
// If module Views Ui enabled.
if ($moduleHandler->moduleExists('views_ui')) {
$links['views_ui.add'] = [
$links['admin_toolbar_tools.views_ui.add'] = [
'title' => t('Add new view'),
'route_name' => 'views_ui.add',
'menu_name' => 'admin',
'parent' => 'entity.view.collection',
'weight' => -5,
];
$links['admin_toolbar_tools.views_ui.field_list'] = [
'title' => t('Used in views'),
'route_name' => 'views_ui.reports_fields',
'menu_name' => 'admin',
'parent' => 'entity.field_storage_config.collection',
];
}
$links['system.theme_settings_'] = [
$links['admin_toolbar_tools.system.theme_settings'] = [
'title' => t('Settings'),
'route_name' => 'system.theme_settings',
'menu_name' => 'admin',
@@ -499,13 +512,14 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
];
if ($moduleHandler->moduleExists('webprofiler')) {
$links['admin_menu_tools.devel.webprofiler'] = [
$links['admin_toolbar_tools.devel.webprofiler'] = [
'title' => t('Webprofiler settings'),
'route_name' => 'webprofiler.settings',
'menu_name' => 'admin',
'parent' => 'admin_development',
];
}
if ($moduleHandler->moduleExists('update')) {
$links['update.theme_install_'] = [
'title' => t('Install new theme'),
@@ -534,122 +548,52 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
}
}
// Add menu links for local tasks that sit below any admin menu link routes.
$manager = \Drupal::service('plugin.manager.menu.local_task');
foreach ($links as $key => $link) {
// If module Language enabled.
if ($moduleHandler->moduleExists('language')) {
$links['admin_toolbar_tools.language.negotiation'] = [
'title' => t('Detection and selection'),
'route_name' => 'language.negotiation',
'menu_name' => 'admin',
'parent' => 'entity.configurable_language.collection',
];
}
// Ignore menu links that have no route name.
if (empty($link['route_name'])) {
continue;
}
// Ignore links that are not in the admin menu, include parents in the
// check as they inherit the menu name from the parent if not set.
$link_to_check = $link;
do {
// @todo Use configuration for admin menu name once added in
// https://www.drupal.org/node/1869638.
if (isset($link_to_check['menu_name'])) {
// If the link belongs to the admin menu, then skip this loop and
// look for local tasks.
if ($link_to_check['menu_name'] === 'admin') {
break;
}
else {
// If it is explicitly not in the admin menu, skip.
continue 2;
}
}
if (!empty($link_to_check['parent']) && isset($links[$link_to_check['parent']])) {
$link_to_check = $links[$link_to_check['parent']];
}
else {
// No parent and we found no menu_name, skip.
continue 2;
}
} while ($link_to_check);
$route = $link['route_name'];
$route_local_tasks = $manager->getLocalTasksForRoute($route);
if (empty($route_local_tasks[0])) {
continue;
}
foreach ($route_local_tasks[0] as $task_plugin) {
$definition = $task_plugin->getPluginDefinition();
$local_route = $definition['route_name'];
if (empty($local_route)) {
continue;
}
$exists = FALSE;
$param = FALSE;
if (isset($link['route_parameters'])) {
$param = $link['route_parameters'];
}
// Check if local task has an already registered link in toolbar.
foreach ($links as $link2) {
// Route_name that could be a 'class'.
if (!(isset($link2['route_name']) && ($link2['route_name'] == $local_route))) {
continue;
}
// If route are equal, the parameters could be different.
// @todo: check if this is true.
if ($param) {
if (isset($link2['route_parameters']) && ($param == $link2['route_parameters'])) {
$exists = TRUE;
break;
}
}
else {
$exists = TRUE;
break;
}
}
$parent = FALSE;
if ($exists) {
continue;
}
$title = $definition['title'];
$title = $param ? $title . ' ' . $link['title'] : $title;
// The following code is to choose the parent of the added link.
// If the parent of the current tab also has the tab as local task
// for example: "Content" has "File" as task" and and
// "Content>Comment" also has "File" as a tab then we decide to
// set this one as parent of the added link if not the current tab
// will be the parent.
if (!empty($link['parent']) && isset($links[$link['parent']])) {
$parentlink = $links[$link['parent']];
$parentlink_route = $parentlink['route_name'];
$parent_primary = $manager->getLocalTasks($parentlink_route, 0);
foreach ($parent_primary['tabs'] as $parent_tab) {
if ($parent_tab['#link']['url']) {
$parent_route = $parent_tab['#link']['url']->getRouteName();
if ($parent_route == $local_route) {
$parent = $link['parent'];
break;
}
}
}
}
$parent = $parent ? $parent : $key;
// Make sure the key of the route is unique.
$links[$key . '_' . $local_route] = [
'title' => $title,
'route_name' => $local_route,
'menu_name' => 'admin',
'parent' => $parent,
'att' => TRUE,
// If module Media enabled.
if ($moduleHandler->moduleExists('media')) {
$links['admin_toolbar_tools.add_media'] = [
'title' => t('Add media'),
'route_name' => 'entity.media.add_page',
'menu_name' => 'admin',
'parent' => 'system.admin_content',
];
// Add node links for each media type.
foreach (\Drupal::entityTypeManager()->getStorage('media_type')->loadMultiple() as $type) {
$links['node.add.' . $type->id()] = [
'title' => t($type->label()),
'route_name' => 'entity.media.add_form',
'parent' => 'admin_toolbar_tools.add_media',
'route_parameters' => ['media_type' => $type->id()],
];
if ($param) {
$links[$key . '_' . $local_route]['route_parameters'] = $param;
}
}
}
// If module Config enabled.
if ($moduleHandler->moduleExists('config')) {
$links['admin_toolbar_tools.config.import'] = [
'title' => t('Import'),
'route_name' => 'config.import_full',
'menu_name' => 'admin',
'parent' => 'config.sync',
'weight' => 1,
];
$links['admin_toolbar_tools.config.export'] = [
'title' => t('Export'),
'route_name' => 'config.export_full',
'menu_name' => 'admin',
'parent' => 'config.sync',
'weight' => 2,
];
}
}
/**
@@ -1,4 +1,3 @@
/*---------------------- menu horizontal hover---- Krout Fethi FrontEnd Developer-----*/
.toolbar-tray-horizontal .menu-item:hover {
background: #fff;
}
@@ -105,32 +104,79 @@
display: block;
}
[dir="rtl"] .toolbar-tray-horizontal .toolbar .level-2 > ul {
[dir="rtl"] .toolbar-tray-horizontal .menu-item:hover {
background: #fff;
}
[dir="rtl"] .toolbar-tray-horizontal .menu-item a:focus {
background: #abeae4;
}
[dir="rtl"] .toolbar-tray-horizontal .toolbar-menu:not(:first-child) li.menu-item--expanded > a:focus {
background-position: center right;
background-image: url('../misc/icons/0074bd/chevron-right.svg');
background-repeat: no-repeat;
}
[dir="rtl"] .toolbar-tray-horizontal .menu-item--expanded .menu {
background: #fff;
width: auto;
height: auto;
}
[dir="rtl"] .toolbar-tray-horizontal .menu-item--expanded {
background-color: #f5f5f2;
}
[dir="rtl"] .toolbar-tray-horizontal ul li li.menu-item {
border-top: none transparent;
border-right: 1px solid #dddddd;
border-bottom: 1px solid #dddddd;
border-left: 1px solid #dddddd;
}
[dir="rtl"] .toolbar .toolbar-tray-horizontal .menu-item:last-child {
border-left: 1px solid #dddddd;
border-right: 1px solid #dddddd;
}
[dir="rtl"] .toolbar .toolbar-tray-horizontal ul ul li.menu-item:first-child {
border-top: 1px solid #dddddd;
}
[dir="rtl"] .toolbar-tray-horizontal li.menu-item--expanded.hover-intent ul ul,
[dir="rtl"] .toolbar-tray-horizontal li.menu-item--expanded.hover-intent ul ul ul,
[dir="rtl"] .toolbar-tray-horizontal li.menu-item--expanded.hover-intent ul ul ul ul,
[dir="rtl"] .toolbar-tray-horizontal li.menu-item--expanded.hover-intent ul ul ul ul ul {
display: none;
left: -999em; /* LTR */
}
/* Lists nested under hovered list items */
[dir="rtl"] .toolbar-tray-horizontal li.menu-item--expanded.hover-intent ul,
[dir="rtl"] .toolbar-tray-horizontal li li.menu-item--expanded.hover-intent ul,
[dir="rtl"] .toolbar-tray-horizontal li li li.menu-item--expanded.hover-intent ul,
[dir="rtl"] .toolbar-tray-horizontal li li li li.menu-item--expanded.hover-intent ul,
[dir="rtl"] .toolbar-tray-horizontal li li li li li.menu-item--expanded.hover-intent ul {
display: block;
left: auto; /* LTR */
}
[dir="rtl"] .toolbar-tray-horizontal .menu ul li a,
[dir="rtl"] .toolbar-tray-horizontal .menu ul .toolbar-icon {
padding: 12px 15px 12px 12px;
}
[dir="rtl"] .toolbar-tray-horizontal ul li.menu-item--expanded.hover-intent ul {
display: block;
position: absolute;
padding-top: 0;
top: 0;
right: 200px;
width: 200px;
box-shadow: 2px 2px 3px hsla(0, 0%, 0%, 0.4);
z-index: 1;
}
[dir="rtl"] .toolbar-tray-horizontal li:hover ul li {
float: none !important;
}
[dir="rtl"] .toolbar-tray-horizontal li:focus ul li {
float: none !important;
}
[dir="rtl"] .toolbar .toolbar-menu ul .toolbar-icon {
padding-left: 1.3333em;
}
[dir="rtl"] .toolbar-tray-horizontal ul li.menu-item--expanded .menu-item:hover ul {
margin: -40px 197px 0 0;
}
[dir="rtl"] .toolbar-tray-horizontal ul li.menu-item--expanded .menu-item:focus ul {
margin: -40px 197px 0 0;
[dir="rtl"] .toolbar-tray-horizontal ul li.menu-item--expanded .menu-item > ul {
display: none;
}
[dir="rtl"] .toolbar-tray-horizontal ul li.menu-item--expanded ul li.menu-item--expanded {
@@ -138,3 +184,28 @@
background-image: url('../misc/icons/0074bd/chevron-left.svg');
background-repeat: no-repeat;
}
[dir="rtl"] .toolbar-tray-horizontal ul li.menu-item--expanded .menu-item.hover-intent ul {
display: block;
margin: -40px 197px 0 0;
}
[dir="rtl"] .toolbar-tray-horizontal li:hover ul li {
float: none;
}
[dir="rtl"] .toolbar-tray-horizontal li.hover-intent ul li {
float: none;
}
[dir="rtl"] .toolbar-tray-horizontal .toolbar .level-2 > ul {
position: absolute;
padding-top: 0;
top: 0;
left: 200px;
width: 200px;
}
[dir="rtl"] .toolbar .toolbar-tray-vertical li.open > ul.toolbar-menu.clearfix {
display: block;
}
@@ -1,10 +1,10 @@
(function ($) {
(function ($, Drupal) {
Drupal.behaviors.adminToolbar = {
attach: function (context, settings) {
$('a.toolbar-icon', context).removeAttr('title');
$('.toolbar-tray-horizontal li.menu-item--expanded, .toolbar-tray-horizontal ul li.menu-item--expanded .menu-item', context).hoverIntent({
$('.toolbar-tray li.menu-item--expanded, .toolbar-tray ul li.menu-item--expanded .menu-item', context).hoverIntent({
over: function () {
// At the current depth, we should delete all "hover-intent" classes.
// Other wise we get unwanted behaviour where menu items are expanded while already in hovering other ones.
@@ -16,13 +16,13 @@
},
timeout: 250
});
// Make the toolbar menu navigable with keyboard.
$('ul.toolbar-menu li.menu-item--expanded a', context).on('focusin', function () {
$('li.menu-item--expanded', context).removeClass('hover-intent');
$(this).parents('li.menu-item--expanded').addClass('hover-intent');
});
$('ul.toolbar-menu li.menu-item a', context).keydown(function (e) {
if ((e.shiftKey && (e.keyCode || e.which) == 9)) {
if ($(this).parent('.menu-item').prev().hasClass('menu-item--expanded')) {
@@ -30,15 +30,15 @@
}
}
});
$('.toolbar-menu:first-child > .menu-item:not(.menu-item--expanded) a, .toolbar-tab > a', context).on('focusin', function () {
$('.menu-item--expanded').removeClass('hover-intent');
});
$('.toolbar-menu:first-child > .menu-item', context).on('hover', function () {
$(this,'a').css("background: #fff;");
$(this, 'a').css("background: #fff;");
});
$('ul:not(.toolbar-menu)', context).on({
mousemove: function () {
$('li.menu-item--expanded').removeClass('hover-intent');
@@ -50,4 +50,4 @@
}
};
})(jQuery);
})(jQuery, Drupal);
@@ -4,6 +4,8 @@ sudo: false
matrix:
fast_finish: true
include:
- env: DRUPAL=8.4.x
php: 7.1
- env: DRUPAL=8.4.x
php: 7.0
- env: DRUPAL=8.4.x
@@ -13,6 +13,8 @@ Changelog
23-APR-2017 8.x-1.0-alpha9
01-DEC-2017 8.x-1.0-alpha10
19-DEC-2017 8.x-1.0-alpha11
12-FEB-2018 8.x-1.0-alpha12
07-MAR-2018 8.x.1.0-alpha13
Status
====
@@ -108,13 +110,17 @@ marked with [x] are considered complete.
- [x] Check loader logic in Domain Access `node_access`
- [x] Check id logic in Domain Alias list controller
- [x] Check domain responses on configuration forms
- [ ] Remove deprecated `entity_get_form_display`
- [ ] Implement theme functions or twig templates where proper
- [x] Remove deprecated `entity_get_form_display`
- [x] Implement theme functions or twig templates where proper
- [ ] Advanced drush integration / complete labelled tasks
- [ ] Add filter options to domain_access and domain_source views
- [ ] Test cron handling
- [ ] Caching strategies in DomainNegotiator
- [ ] Caching strategies in DomainConfigOverrides
- [ ] Cache in the DomainAccessManager
- [ ] Add filter options to domain_access and domain_source views
- [ ] Proper handling of default node values
- [ ] Do not allow actions to be edited?
- [o] Recreate the Domain Theme module -- see https://www.drupal.org/project/domain_theme_switch
# Final
@@ -124,3 +130,4 @@ marked with [x] are considered complete.
- [x] Remove calls to deprecated methods / classes
- [ ] Remove unnecessary use statements
- [ ] Support Tour module
- [ ] Views schema fails -- see https://www.drupal.org/project/drupal/issues/2834801
@@ -8,8 +8,8 @@ dependencies:
- options
configure: domain.admin
# Information added by Drupal.org packaging script on 2017-12-19
version: '8.x-1.0-alpha11'
# Information added by Drupal.org packaging script on 2018-03-08
version: '8.x-1.0-alpha13'
core: '8.x'
project: 'domain'
datestamp: 1513718589
datestamp: 1520519900
@@ -27,12 +27,11 @@ function domain_update_8001() {
* Configures user form display to checkboxes widget for domain admin field.
*/
function _domain_configure_field() {
// @TODO: This function is deprecated, but using the OO syntax is causing
// test fails.
entity_get_form_display('user', 'user', 'default')
->setComponent(DOMAIN_ADMIN_FIELD, array(
if ($display = \Drupal::entityTypeManager()->getStorage('entity_form_display')->load('user.user.default')) {
$display->setComponent(DOMAIN_ADMIN_FIELD, [
'type' => 'options_buttons',
'weight' => 50,
))
])
->save();
}
}
@@ -15,3 +15,4 @@ process:
status: valid
destination:
plugin: entity:domain
destination_module: domain
@@ -188,7 +188,6 @@ class DomainElementManager implements DomainElementManagerInterface {
*/
public function listDisallowed(array $disallowed) {
$domains = $this->domainStorage->loadMultiple($disallowed);
// @TODO: Proper theme function here.
$string = $this->t('The following domains are currently assigned and cannot be changed:');
foreach ($domains as $domain) {
$items[] = $domain->label();
@@ -204,7 +204,7 @@ class DomainNegotiator implements DomainNegotiatorInterface {
return TRUE;
}
// Check for registered alias matches.
$values = array('hostname' => $httpHost);
$values = array('hostname' => $hostname);
/** @var \Drupal\domain\Entity\DomainInterface $domain */
$domain = $this->domainStorage->create($values);
$domain->setMatchType(self::DOMAIN_MATCH_NONE);
@@ -27,8 +27,6 @@ class DomainServerBlock extends DomainBlockBase {
/**
* Build the output.
*
* @TODO: abstract or theme this function?
*/
public function build() {
/** @var \Drupal\domain\DomainInterface $domain */
@@ -47,10 +45,14 @@ class DomainServerBlock extends DomainBlockBase {
$domain->getResponse();
$check = \Drupal::service('entity_type.manager')->getStorage('domain')->loadByHostname($_SERVER['HTTP_HOST']);
$match = $this->t('Exact match');
// This value is not translatable.
$environment = 'default';
if (!$check) {
// Specific check for Domain Alias.
if (isset($domain->alias)) {
$match = $this->t('ALIAS: Using alias %id', array('%id' => $domain->alias->getPattern()));
// Get the environment.
$environment = $domain->alias->getEnvironment();
}
else {
$match = $this->t('FALSE: Using default domain.');
@@ -60,6 +62,23 @@ class DomainServerBlock extends DomainBlockBase {
$this->t('Domain match'),
$match,
);
$rows[] = [
$this->t('Environment'),
$environment,
];
$rows[] = [
$this->t('Canonical hostname'),
$domain->getCanonical(),
];
$rows[] = [
$this->t('Base path'),
$domain->getPath(),
];
$rows[] = [
$this->t('Current URL'),
$domain->getUrl(),
];
$www = \Drupal::config('domain.settings')->get('www_prefix');
$rows[] = array(
$this->t('Strip www prefix'),
@@ -25,8 +25,6 @@ class DomainSwitcherBlock extends DomainBlockBase {
/**
* Build the output.
*
* @TODO: abstract or theme this function?
*/
public function build() {
/** @var \Drupal\domain\DomainInterface $active_domain */
@@ -27,8 +27,6 @@ class DomainTokenBlock extends DomainBlockBase {
/**
* Build the output.
*
* @TODO: abstract or theme this function?
*/
public function build() {
/** @var \Drupal\domain\DomainInterface $domain */
@@ -49,7 +47,7 @@ class DomainTokenBlock extends DomainBlockBase {
/**
* Generates available tokens for printing.
*
* @param Drupal\domain\DomainInterface $domain
* @param \Drupal\domain\DomainInterface $domain
* The active domain request.
* @return array
* An array keyed by token name, with value of replacement value.
@@ -8,7 +8,8 @@ use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
* Drupal 7 Domain source from database.
*
* @MigrateSource(
* id = "d7_domain"
* id = "d7_domain",
* source_module = "domain"
* )
*/
class DomainRecord extends DrupalSqlBase {
@@ -9,8 +9,8 @@ hidden: TRUE
dependencies:
- domain
# Information added by Drupal.org packaging script on 2017-12-19
version: '8.x-1.0-alpha11'
# Information added by Drupal.org packaging script on 2018-03-08
version: '8.x-1.0-alpha13'
core: '8.x'
project: 'domain'
datestamp: 1513718589
datestamp: 1520519900
@@ -150,11 +150,9 @@ class DomainEntityReferenceTest extends DomainTestBase {
$field_config->save();
// Tell the form system how to behave.
entity_get_form_display('node', 'article', 'default')
->setComponent($name, array(
'type' => 'options_buttons',
))
->save();
if ($display = \Drupal::entityTypeManager()->getStorage('entity_form_display')->load('node.article.default')) {
$display->setComponent($name, ['type' => 'options_buttons'])->save();
}
}
}
@@ -0,0 +1,63 @@
# Schema for the domain access plugins.
views.access.domain_access_admin:
type: mapping
label: 'Domain Access: Administer domain editors'
views.access.domain_access_editor:
type: mapping
label: 'Domain Access: Edit domain content'
views.argument.domain_access_argument:
type: views_argument
label: 'Domain Access'
views.field.domain_access_field:
type: views_field
label: 'Domain Access'
mapping:
click_sort_column:
type: string
label: 'Column used for click sorting'
type:
type: string
label: 'Formatter'
settings:
label: 'Settings'
type: field.formatter.settings.[%parent.type]
group_column:
type: string
label: 'Group by column'
group_columns:
type: sequence
label: 'Group by columns'
sequence:
type: string
label: 'Column'
group_rows:
type: boolean
label: 'Display all values in the same row'
delta_limit:
type: integer
label: 'Field'
delta_offset:
type: integer
label: 'Offset'
delta_reversed:
type: boolean
label: 'Reversed'
delta_first_last:
type: boolean
label: 'First and last only'
multi_type:
type: string
label: 'Display type'
separator:
type: label
label: 'Separator'
field_api_classes:
type: boolean
label: 'Use field template'
views.filter.domain_access_current_all_filter:
type: views_filter
label: 'Current Domain or All Domains'
views.filter.domain_access_filter:
type: views.filter.in_operator
label: 'Domain Access'
@@ -8,8 +8,8 @@ dependencies:
- domain
- node
# Information added by Drupal.org packaging script on 2017-12-19
version: '8.x-1.0-alpha11'
# Information added by Drupal.org packaging script on 2018-03-08
version: '8.x-1.0-alpha13'
core: '8.x'
project: 'domain'
datestamp: 1513718589
datestamp: 1520519900
@@ -343,7 +343,7 @@ function domain_access_node_access(NodeInterface $node, $op, AccountInterface $a
}
// Check to see that we have a valid active domain.
// Without one, we cannot assert an opinion about access.
if (empty($active_domain->getDomainId())) {
if (!$active_domain || empty($active_domain->getDomainId())) {
return AccessResult::neutral();
}
@@ -560,19 +560,16 @@ function domain_access_confirm_fields($entity_type, $bundle, $text = array()) {
$field_config->save();
}
// Tell the form system how to behave. Default to radio buttons.
// @TODO: This function is deprecated, but using the OO syntax is causing
// test fails.
entity_get_form_display($entity_type, $bundle, 'default')
->setComponent(DOMAIN_ACCESS_FIELD, array(
if ($display = \Drupal::entityTypeManager()->getStorage('entity_form_display')->load($entity_type . '.' . $bundle . '.default')) {
$display->setComponent(DOMAIN_ACCESS_FIELD, [
'type' => 'options_buttons',
'weight' => 40,
))
->setComponent(DOMAIN_ACCESS_ALL_FIELD, array(
])->setComponent(DOMAIN_ACCESS_ALL_FIELD, [
'type' => 'boolean_checkbox',
'settings' => array('display_label' => 1),
'settings' => ['display_label' => 1],
'weight' => 41,
))
->save();
])->save();
}
}
catch (Exception $e) {
\Drupal::logger('domain_access')->notice('Field installation failed.');
@@ -5,7 +5,7 @@ namespace Drupal\domain_access\Plugin\views\argument;
use Drupal\views\Plugin\views\argument\StringArgument;
/**
* Field handler to present the link an entity on a domain.
* Argument handler to find nodes by domain assignment.
*
* @ViewsArgument("domain_access_argument")
*/
@@ -11,8 +11,8 @@ dependencies:
- domain_access
- taxonomy
# Information added by Drupal.org packaging script on 2017-12-19
version: '8.x-1.0-alpha11'
# Information added by Drupal.org packaging script on 2018-03-08
version: '8.x-1.0-alpha13'
core: '8.x'
project: 'domain'
datestamp: 1513718589
datestamp: 1520519900
@@ -151,10 +151,12 @@ class DomainAccessFieldTest extends DomainTestBase {
// Create a new content type and test that the fields are created.
// Create a content type programmatically.
$type = $this->drupalCreateContentType();
$type_exists = (bool) NodeType::load($type->id());
$this->assertTrue($type_exists, 'The new content type has been created in the database.');
// The test is not passing to domain_access_node_type_insert() properly.
domain_access_confirm_fields('node', $type->id());
// Visit the article creation page.
$this->drupalGet('node/add/' . $type->id());
$this->assertResponse(200, $type->id() . ' creation found.');
@@ -7,8 +7,8 @@ package: Domain
dependencies:
- domain
# Information added by Drupal.org packaging script on 2017-12-19
version: '8.x-1.0-alpha11'
# Information added by Drupal.org packaging script on 2018-03-08
version: '8.x-1.0-alpha13'
core: '8.x'
project: 'domain'
datestamp: 1513718589
datestamp: 1520519900
@@ -7,8 +7,8 @@ package: Domain
dependencies:
- domain
# Information added by Drupal.org packaging script on 2017-12-19
version: '8.x-1.0-alpha11'
# Information added by Drupal.org packaging script on 2018-03-08
version: '8.x-1.0-alpha13'
core: '8.x'
project: 'domain'
datestamp: 1513718589
datestamp: 1520519900
@@ -7,8 +7,8 @@ package: Domain
dependencies:
- domain
# Information added by Drupal.org packaging script on 2017-12-19
version: '8.x-1.0-alpha11'
# Information added by Drupal.org packaging script on 2018-03-08
version: '8.x-1.0-alpha13'
core: '8.x'
project: 'domain'
datestamp: 1513718589
datestamp: 1520519900
@@ -10,8 +10,8 @@ dependencies:
- domain
- domain_config
# Information added by Drupal.org packaging script on 2017-12-19
version: '8.x-1.0-alpha11'
# Information added by Drupal.org packaging script on 2018-03-08
version: '8.x-1.0-alpha13'
core: '8.x'
project: 'domain'
datestamp: 1513718589
datestamp: 1520519900
@@ -10,8 +10,8 @@ dependencies:
- domain
- domain_config
# Information added by Drupal.org packaging script on 2017-12-19
version: '8.x-1.0-alpha11'
# Information added by Drupal.org packaging script on 2018-03-08
version: '8.x-1.0-alpha13'
core: '8.x'
project: 'domain'
datestamp: 1513718589
datestamp: 1520519900
@@ -326,17 +326,17 @@ display:
click_sort_column: target_id
type: entity_reference_label
settings:
link: 1
link: true
group_column: target_id
group_columns: { }
group_rows: 1
delta_limit: '0'
delta_offset: '0'
delta_reversed: 0
delta_first_last: 0
group_rows: true
delta_limit: 0
delta_offset: 0
delta_reversed: false
delta_first_last: false
multi_type: separator
separator: ', '
field_api_classes: 0
field_api_classes: false
plugin_id: domain_access_field
field_domain_all_affiliates:
id: field_domain_all_affiliates
@@ -770,7 +770,7 @@ display:
operation: view
multiple: 0
access: false
bundles: null
bundles: { }
glossary: false
limit: 0
case: none
@@ -1213,10 +1213,7 @@ display:
group_type: group
admin_label: ''
operator: '='
value:
min: ''
max: ''
value: '1'
value: '1'
group: 1
exposed: false
expose:
@@ -1269,7 +1266,7 @@ display:
authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: 0
reduce: false
is_grouped: false
group_info:
label: ''
@@ -402,17 +402,17 @@ display:
click_sort_column: target_id
type: entity_reference_label
settings:
link: 0
link: false
group_column: target_id
group_columns: { }
group_rows: 1
delta_limit: '0'
delta_offset: '0'
delta_reversed: 0
delta_first_last: 0
group_rows: true
delta_limit: 0
delta_offset: 0
delta_reversed: false
delta_first_last: false
multi_type: separator
separator: ', '
field_api_classes: 0
field_api_classes: false
plugin_id: domain_access_field
field_domain_all_affiliates:
id: field_domain_all_affiliates
@@ -1080,7 +1080,7 @@ display:
operation: view
multiple: 0
access: false
bundles: null
bundles: { }
glossary: false
limit: 0
case: none
@@ -1381,7 +1381,7 @@ display:
authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: 0
reduce: false
is_grouped: false
group_info:
label: ''
@@ -0,0 +1,8 @@
# Schema for the domain content plugins.
views.access.domain_content_admin:
type: mapping
label: 'Domain Content: View domain-specific editors'
views.access.domain_content_editor:
type: mapping
label: 'Domain Content: View domain-specific content'
@@ -11,8 +11,8 @@ dependencies:
- user
- views
# Information added by Drupal.org packaging script on 2017-12-19
version: '8.x-1.0-alpha11'
# Information added by Drupal.org packaging script on 2018-03-08
version: '8.x-1.0-alpha13'
core: '8.x'
project: 'domain'
datestamp: 1513718589
datestamp: 1520519900
@@ -32,7 +32,7 @@ class DomainContentController extends ControllerBase {
];
if ($account->hasPermission($options['all_permission'])) {
$build['#rows'][] = [
Link::fromTextAndUrl($this->t('All affiliates'), Url::fromUri('internal:/admin/content/' . $options['path'] . '/' . '/all_affiliates')),
Link::fromTextAndUrl($this->t('All affiliates'), Url::fromUri('internal:/admin/content/' . $options['path'] . '/all_affiliates')),
$this->getCount($options['type']),
];
}
@@ -0,0 +1,9 @@
views.field.domain_source:
type: views_field
label: 'Domain source'
views.filter.domain_source:
type: views.filter.in_operator
label: 'Domain source'
views.filter_value.domain_source:
type: views.filter_value.in_operator
label: 'Domain source'
@@ -8,8 +8,8 @@ dependencies:
- domain
- node
# Information added by Drupal.org packaging script on 2017-12-19
version: '8.x-1.0-alpha11'
# Information added by Drupal.org packaging script on 2018-03-08
version: '8.x-1.0-alpha13'
core: '8.x'
project: 'domain'
datestamp: 1513718589
datestamp: 1520519900
@@ -54,14 +54,12 @@ function domain_source_confirm_fields($entity_type, $bundle) {
}
// Tell the form system how to behave. Default to radio buttons.
// @TODO: This function is deprecated, but using the OO syntax is causing
// test fails.
entity_get_form_display($entity_type, $bundle, 'default')
->setComponent(DOMAIN_SOURCE_FIELD, array(
if ($display = \Drupal::entityTypeManager()->getStorage('entity_form_display')->load($entity_type . '.' . $bundle . '.default')) {
$display->setComponent(DOMAIN_SOURCE_FIELD, [
'type' => 'options_select',
'weight' => 42,
))
->save();
])->save();
}
}
/**
@@ -130,12 +128,20 @@ function domain_source_form_alter(&$form, &$form_state, $form_id) {
function domain_source_form_validate($element, \Drupal\Core\Form\FormStateInterface $form_state) {
$values = $form_state->getValues();
// This is only run if Domain Access is present.
$access_values = $values[DOMAIN_ACCESS_FIELD];
$source_value = current($values[DOMAIN_SOURCE_FIELD]);
if (isset($values[DOMAIN_SOURCE_FIELD]) && is_array($values[DOMAIN_SOURCE_FIELD]) && isset($values[DOMAIN_ACCESS_FIELD])) {
$access_values = $values[DOMAIN_ACCESS_FIELD];
$source_value = current($values[DOMAIN_SOURCE_FIELD]);
}
// If no value is selected, that's acceptable. Else run through a check.
// Note that the _none selection returns as [FALSE].
$source_set = empty($source_value);
foreach ($access_values as $value) {
if ($value == $source_value) {
// Core is inconsistent depending on the field order.
// See https://www.drupal.org/project/domain/issues/2945771#comment-12493199
if (is_array($value) && $value == $source_value) {
$source_set = TRUE;
}
elseif (is_string($value) && !empty($source_value['target_id']) && $value == $source_value['target_id']) {
$source_set = TRUE;
}
}
@@ -76,6 +76,10 @@ class DomainSourceElementTest extends DomainTestBase {
$this->pressButton('edit-submit');
$this->assertSession()->statusCodeEquals(200);
// Check the URL.
$url = $this->geturl();
$this->assert(strpos($url, 'node/1/edit') === FALSE, 'Form submitted.');
// Edit the node.
$this->drupalGet('node/1/edit');
$this->assertSession()->statusCodeEquals(200);
@@ -90,5 +94,33 @@ class DomainSourceElementTest extends DomainTestBase {
// Check the URL.
$url = $this->geturl();
$this->assert(strpos($url, 'node/1/edit') > 0, 'Form not submitted.');
// Set the field properly and save again.
$this->selectFieldOption($locator, 'one_example_com');
// Save the form.
$this->pressButton('edit-submit');
$this->assertSession()->statusCodeEquals(200);
// Check the URL.
$url = $this->geturl();
$this->assert(strpos($url, 'node/1/edit') === FALSE, 'Form submitted.');
// Save with no source.
// Edit the node.
$this->drupalGet('node/1/edit');
$this->assertSession()->statusCodeEquals(200);
// Set the domain source field to an unselected domain.
$this->selectFieldOption($locator, '_none');
// Save the form.
$this->pressButton('edit-submit');
$this->assertSession()->statusCodeEquals(200);
// Check the URL.
$url = $this->geturl();
$this->assert(strpos($url, 'node/1/edit') === FALSE, 'Form submitted.');
}
}
@@ -1,8 +1,10 @@
{
"name": "drupal/features",
"description": "Enables administrators to package configuration into modules.",
"type": "drupal-module",
"description": "Enables administrators to package configuration into modules",
"license": "GPL-2.0+",
"minimum-stability": "dev",
"require": { }
"name": "drupal/features",
"require": {
"drupal/config_update": "^1.4"
},
"type": "drupal-module"
}
@@ -38,7 +38,7 @@ features.bundle.*:
type: boolean
label: "Is install profile"
features.assignment.*:
features.assignment.settings:
type: mapping
label: "Assignment settings"
mapping:
@@ -49,16 +49,13 @@ features.assignment.*:
type: integer
label: "Weight"
features.assignment.*:
type: features.assignment.settings
features.assignment.base:
type: mapping
type: features.assignment.settings
label: "Base type"
mapping:
enabled:
type: boolean
label: "Enabled"
weight:
type: integer
label: "Weight"
types:
type: mapping
label: "Types"
@@ -75,15 +72,9 @@ features.assignment.base:
type: string
features.assignment.core:
type: mapping
type: features.assignment.settings
label: "Core type"
mapping:
enabled:
type: boolean
label: "Enabled"
weight:
type: integer
label: "Weight"
types:
type: mapping
label: "Types"
@@ -95,15 +86,9 @@ features.assignment.core:
type: string
features.assignment.exclude:
type: mapping
type: features.assignment.settings
label: "Exclude"
mapping:
enabled:
type: boolean
label: "Enabled"
weight:
type: integer
label: "Weight"
types:
type: mapping
label: "Types"
@@ -134,15 +119,9 @@ features.assignment.exclude:
label: "Don't exclude ANY configuration by namespace"
features.assignment.optional:
type: mapping
type: features.assignment.settings
label: "Optional"
mapping:
enabled:
type: boolean
label: "Enabled"
weight:
type: integer
label: "Weight"
types:
type: mapping
label: "Types"
@@ -154,15 +133,9 @@ features.assignment.optional:
type: string
features.assignment.profile:
type: mapping
type: features.assignment.settings
label: "Profile"
mapping:
enabled:
type: boolean
label: "Enabled"
weight:
type: integer
label: "Weight"
curated:
type: boolean
label: "Add commonly-needed configuration"
@@ -187,15 +160,9 @@ features.assignment.profile:
type: string
features.assignment.site:
type: mapping
type: features.assignment.settings
label: "Site"
mapping:
enabled:
type: boolean
label: "Enabled"
weight:
type: integer
label: "Weight"
types:
type: mapping
label: "Types"
@@ -205,3 +172,17 @@ features.assignment.site:
label: "Configuration Types"
sequence:
type: string
features.assignment.alter:
type: features.assignment.settings
label: "Alter"
mapping:
core:
type: boolean
label: "Core"
uuid:
type: boolean
label: "UUID"
user_permissions:
type: boolean
label: "User permissions"
@@ -0,0 +1,11 @@
services:
features.commands:
class: \Drupal\features\Commands\FeaturesCommands
arguments:
- '@features_assigner'
- '@features.manager'
- '@features_generator'
- '@config_update.config_diff'
- '@config.storage'
tags:
- { name: drush.command }
@@ -7,8 +7,8 @@ dependencies:
- config
- config_update
# Information added by Drupal.org packaging script on 2017-03-07
version: '8.x-3.5'
# Information added by Drupal.org packaging script on 2018-02-27
version: '8.x-3.7'
core: '8.x'
project: 'features'
datestamp: 1488908587
datestamp: 1519763291
@@ -7,8 +7,8 @@ configure: features.assignment
dependencies:
- features
# Information added by Drupal.org packaging script on 2017-03-07
version: '8.x-3.5'
# Information added by Drupal.org packaging script on 2018-02-27
version: '8.x-3.7'
core: '8.x'
project: 'features'
datestamp: 1488908587
datestamp: 1519763291
@@ -641,16 +641,15 @@ class FeaturesEditForm extends FormBase {
foreach (array('excluded', 'required') as $constraint) {
$this->{$constraint} = array();
$info = !empty($this->package->{'get' . $constraint}()) ? $this->package->{'get' . $constraint}() : array();
if (($constraint == 'required') && (empty($info) || !is_array($info))) {
// If required is True or empty array, add all config as required
$info = $this->package->getConfigOrig();
}
foreach ($info as $item_name) {
if (!isset($config[$item_name])) {
continue;
// $info may be boolean.
if (is_array($info)) {
foreach ($info as $item_name) {
if (!isset($config[$item_name])) {
continue;
}
$item = $config[$item_name];
$this->{$constraint}[$item->getType()][$item->getShortName()] = $item->getLabel();
}
$item = $config[$item_name];
$this->{$constraint}[$item->getType()][$item->getShortName()] = $item->getLabel();
}
}
@@ -133,10 +133,7 @@ class FeaturesExportForm extends FormBase {
// Add in un-packaged configuration items.
$this->addUnpackaged($packages, $config_collection);
// Filter packages on bundle if selected.
if (!$current_bundle->isDefault()) {
$packages = $this->featuresManager->filterPackages($packages, $current_bundle->getMachineName(), TRUE);
}
$packages = $this->featuresManager->filterPackages($packages, $current_bundle->getMachineName());
// Pass the packages and bundle data for use in the form pre_render
// callback.
@@ -51,7 +51,7 @@ class FeaturesBundleUITest extends WebTestBase {
* The features bundle.
*/
protected function defaultBundle() {
return $this->bundleStorage->load('default');
return $this->bundleStorage->load(FeaturesBundleInterface::DEFAULT_BUNDLE);
}
/**
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,7 @@
<?php
namespace Drupal\features\Exception;
class DomainException extends \DomainException {
}
@@ -0,0 +1,7 @@
<?php
namespace Drupal\features\Exception;
class InvalidArgumentException extends \InvalidArgumentException {
}
@@ -364,8 +364,7 @@ class FeaturesAssigner implements FeaturesAssignerInterface {
}
}
foreach ($new_bundles as $new_bundle) {
$new_bundle = $this->createBundleFromDefault($new_bundle['machine_name'], $new_bundle['name'], $new_bundle['description'], $new_bundle['is_profile']);
drupal_set_message($this->t('Features bundle @name automatically created.', ['@name' => $new_bundle->getName()]));
$this->createBundleFromDefault($new_bundle['machine_name'], $new_bundle['name'], $new_bundle['description'], $new_bundle['is_profile']);
}
}
@@ -57,7 +57,7 @@ class FeaturesConfigInstaller extends ConfigInstaller {
list($major, $minor, ) = explode('.', \Drupal::VERSION);
if ($major == 8 && $minor > 2) {
// D8.3 added the %install_profile% argument.
$install_profile = drupal_get_profile();
$install_profile = \Drupal::installProfile();
parent::__construct($config_factory, $active_storage, $typed_config, $config_manager, $event_dispatcher, $install_profile);
}
else {
@@ -35,7 +35,15 @@ class FeaturesInstallStorage extends ExtensionInstallStorage {
* default collection.
*/
public function __construct(StorageInterface $config_storage, $directory = self::CONFIG_INSTALL_DIRECTORY, $collection = StorageInterface::DEFAULT_COLLECTION) {
parent::__construct($config_storage, $directory, $collection, FALSE);
list($major, $minor, ) = explode('.', \Drupal::VERSION);
if ($major == 8 && $minor > 2) {
// D8.3 added the %profile% argument.
$profile = \Drupal::installProfile();
parent::__construct($config_storage, $directory, $collection, FALSE, $profile);
}
else {
parent::__construct($config_storage, $directory, $collection, FALSE);
}
}
/**
@@ -326,10 +326,13 @@ class FeaturesManager implements FeaturesManagerInterface {
// A package matches the namespace if:
// - it's prefixed with the namespace, or
// - it's assigned to a bundle named for the namespace, or
// - we're looking only for exported packages and it's not exported.
if (empty($namespace) || (strpos($package->getMachineName(), $namespace . '_') === 0) ||
// - the namespace is the default bundle and it has an empty bundle, and
// - we're not removing only exported packages, or
// - we are removing only exported packages and it's not exported.
if ((strpos($package->getMachineName(), $namespace . '_') === 0 ||
($package->getBundle() && $package->getBundle() === $namespace) ||
($only_exported && $package->getStatus() === FeaturesManagerInterface::STATUS_NO_EXPORT)) {
($namespace === FeaturesBundleInterface::DEFAULT_BUNDLE && empty($package->getBundle()))) &&
(!$only_exported || ($package->getStatus() === FeaturesManagerInterface::STATUS_NO_EXPORT))) {
$result[$key] = $package;
}
}
@@ -546,25 +549,30 @@ class FeaturesManager implements FeaturesManagerInterface {
protected function getConfigDependency(ConfigurationItem $config, $module_list = array()) {
$dependencies = [];
$type = $config->getType();
if ($type != FeaturesManagerInterface::SYSTEM_SIMPLE_CONFIG) {
$provider = $this->entityTypeManager->getDefinition($type)->getProvider();
// Ensure the provider is an installed module and not, for example, 'core'
if (isset($module_list[$provider])) {
$dependencies[] = $provider;
// For configuration in the InstallStorage::CONFIG_INSTALL_DIRECTORY
// directory, set any dependencies of the configuration item as package
// dependencies.
// As its name implies, the core-provided
// InstallStorage::CONFIG_OPTIONAL_DIRECTORY should not create
// dependencies.
if ($config->getSubdirectory() === InstallStorage::CONFIG_INSTALL_DIRECTORY) {
if ($type === FeaturesManagerInterface::SYSTEM_SIMPLE_CONFIG) {
$dependencies[] = strtok($config->getName(), '.');
}
else {
$dependencies[] = $this->entityTypeManager->getDefinition($type)->getProvider();
}
// For configuration in the InstallStorage::CONFIG_INSTALL_DIRECTORY
// directory, set any module dependencies of the configuration item
// as package dependencies.
// As its name implies, the core-provided
// InstallStorage::CONFIG_OPTIONAL_DIRECTORY should not create
// dependencies.
if ($config->getSubdirectory() === InstallStorage::CONFIG_INSTALL_DIRECTORY &&
isset($config->getData()['dependencies']['module'])
) {
if (isset($config->getData()['dependencies']['module'])) {
$dependencies = array_merge($dependencies, $config->getData()['dependencies']['module']);
}
// Only return dependencies for installed modules and not, for example,
// 'core'.
$dependencies = array_intersect($dependencies, array_keys($module_list));
}
return $dependencies;
}
@@ -755,20 +763,28 @@ class FeaturesManager implements FeaturesManagerInterface {
}
$config_collection = $this->getConfigCollection();
$module_list = $this->moduleHandler->getModuleList();
/** @var \Drupal\features\Package[] $packages */
foreach ($packages as $package) {
foreach ($package->getConfig() as $item_name) {
if (!empty($config_collection[$item_name]->getData()['dependencies']['config'])) {
foreach ($config_collection[$item_name]->getData()['dependencies']['config'] as $dependency_name) {
if (isset($config_collection[$dependency_name])) {
if (isset($config_collection[$dependency_name]) &&
// For configuration in the
// InstallStorage::CONFIG_INSTALL_DIRECTORY directory, set any
// package dependencies of the configuration item.
// As its name implies, the core-provided
// InstallStorage::CONFIG_OPTIONAL_DIRECTORY should not create
// dependencies.
($config_collection[$dependency_name]->getSubdirectory() === InstallStorage::CONFIG_INSTALL_DIRECTORY)) {
// If the required item is assigned to one of the packages, add
// a dependency on that package.
$dependency_set = FALSE;
if ($dependency_package = $config_collection[$dependency_name]->getPackage()) {
$package_name = $bundle->getFullName($dependency_package);
// Package shouldn't be dependent on itself.
if ($package_name && array_key_exists($package_name, $packages) && $package_name != $package->getMachineName()) {
if ($package_name && array_key_exists($package_name, $packages) && $package_name != $package->getMachineName() && isset($module_list[$package_name])) {
$package->setDependencies($this->mergeUniqueItems($package->getDependencies(), [$package_name]));
$dependency_set = TRUE;
}
@@ -778,7 +794,7 @@ class FeaturesManager implements FeaturesManagerInterface {
if (!$dependency_set && $extension_name = $config_collection[$dependency_name]->getProvider()) {
// No extension should depend on the install profile.
$package_name = $bundle->getFullName($package->getMachineName());
if ($extension_name != $package_name && $extension_name != $this->drupalGetProfile()) {
if ($extension_name != $package_name && $extension_name != $this->drupalGetProfile() && isset($module_list[$extension_name])) {
$package->setDependencies($this->mergeUniqueItems($package->getDependencies(), [$extension_name]));
}
}
@@ -235,7 +235,7 @@ class Package {
}
/**
* @return string[]
* @return string[]|bool
*/
public function getRequired() {
return $this->required;
@@ -245,12 +245,20 @@ class Package {
* @return bool
*/
public function getRequiredAll() {
// Mark all as required if the package is not yet exported.
if ($this->getStatus() === FeaturesManagerInterface::STATUS_NO_EXPORT) {
return TRUE;
}
// Mark all as required if required is TRUE.
if (is_bool($this->required)) {
return $this->required;
}
// Mark all as required if required contains all the exported config.
$config_orig = $this->getConfigOrig();
$info = is_array($this->required) ? $this->required : array();
$diff = array_diff($config_orig, $info);
// Mark all as required if required:true, or required is empty, or
// if required contains all the exported config
return empty($diff) || empty($info);
$diff = array_diff($config_orig, $this->required);
return empty($diff);
}
/**
@@ -26,7 +26,7 @@ class FeaturesAssignmentPackages extends FeaturesAssignmentMethodBase {
$short_name = $package->getMachineName();
// Copy over package excluded settings, if any.
if (!$package->getExcluded()) {
if ($package->getExcluded()) {
$config_collection = $this->featuresManager->getConfigCollection();
foreach ($package->getExcluded() as $config_name) {
if (isset($config_collection[$config_name])) {
@@ -6,8 +6,8 @@ package: Test
dependencies:
- features
# Information added by Drupal.org packaging script on 2017-03-07
version: '8.x-3.5'
# Information added by Drupal.org packaging script on 2018-02-27
version: '8.x-3.7'
core: '8.x'
project: 'features'
datestamp: 1488908587
datestamp: 1519763291
@@ -1,3 +1,5 @@
bundle: test_mybundle
excluded:
- system.theme
required:
- core.date_format.long
@@ -6,8 +6,8 @@ package: Test
dependencies:
- features
# Information added by Drupal.org packaging script on 2017-03-07
version: '8.x-3.5'
# Information added by Drupal.org packaging script on 2018-02-27
version: '8.x-3.7'
core: '8.x'
project: 'features'
datestamp: 1488908587
datestamp: 1519763291
@@ -700,6 +700,19 @@ class FeaturesAssignTest extends KernelTestBase {
public function testAssignPackages() {
$method_id = 'packages';
// A configuration item that will be excluded.
$this->addConfigurationItem('system.theme', [], [
'type' => FeaturesManagerInterface::SYSTEM_SIMPLE_CONFIG,
]);
// A configuration item that will be required.
$this->addConfigurationItem('core.date_format.long', [], [
'type' => 'date_format',
]);
// A configuration item that will be neither excluded nor required.
$this->addConfigurationItem('system.theme', [], [
'type' => FeaturesManagerInterface::SYSTEM_SIMPLE_CONFIG,
]);
// Enable the method.
$this->enableAssignmentMethod($method_id);
@@ -708,6 +721,14 @@ class FeaturesAssignTest extends KernelTestBase {
$packages = $this->featuresManager->getPackages();
$this->assertNotEmpty($packages[self::TEST_INSTALLED_PACKAGE], 'Expected package not created.');
$config = $this->featuresManager->getConfigCollection();
$this->assertTrue(in_array(self::TEST_INSTALLED_PACKAGE, $config['system.theme']->getPackageExcluded()), 'Configuration item not excluded from package.');
$this->assertFalse(in_array(self::TEST_INSTALLED_PACKAGE, $config['system.site']->getPackageExcluded()), 'Configuration item excluded from package.');
$this->assertEquals(self::TEST_INSTALLED_PACKAGE, $config['core.date_format.long']->getPackage(), 'Required item not assigned to package.');
$this->assertNotEquals(self::TEST_INSTALLED_PACKAGE, $config['system.site']->getPackage(), 'Unrequired item assigned to package.');
}
/**
@@ -730,7 +751,7 @@ class FeaturesAssignTest extends KernelTestBase {
'type' => 'image_style',
]);
$this->addConfigurationItem('system.cron', [], [
'type' => 'simple',
'type' => FeaturesManagerInterface::SYSTEM_SIMPLE_CONFIG,
]);
$this->bundle = $this->assigner->createBundleFromDefault('myprofile');
$this->bundle->setProfileName('myprofile');
@@ -105,10 +105,23 @@ class FeaturesManagerTest extends UnitTestCase {
$this->configManager = $this->getMock(ConfigManagerInterface::class);
$this->moduleHandler = $this->getMock(ModuleHandlerInterface::class);
// getModuleList should return an array of extension objects.
// but we just need ::getConfigDependency isset($module_list[$provider]).
// but we just need isset($module_list[$provider]) for
// ::getConfigDependency() and ::assignInterPackageDependencies().
$this->moduleHandler->expects($this->any())
->method('getModuleList')
->willReturn(['my_module' => true]);
->willReturn([
'my_module' => true,
'example' => true,
'example3' => true,
'my_feature' => true,
'my_other_feature' => true,
'package' => true,
'package2' => true,
'package3' => true,
'giraffe_package' => true,
'giraffe_package2' => true,
'giraffe_package3' => true,
]);
$this->configReverter = $this->getMock(ConfigRevertInterface::class);
$this->configReverter->expects($this->any())
->method('import')
@@ -188,6 +201,55 @@ class FeaturesManagerTest extends UnitTestCase {
$this->assertEquals($package, $this->featuresManager->getPackage('foo'));
}
/**
* @covers ::filterPackages
*/
public function testGetPackages() {
$packages = [
'package' => new Package('package', [
'bundle' => '',
'status' => FeaturesManagerInterface::STATUS_NO_EXPORT,
]),
'package2' => new Package('package2', [
'bundle' => '',
'status' => FeaturesManagerInterface::STATUS_UNINSTALLED,
]),
'package3' => new Package('package3', [
'bundle' => 'my_bundle',
'status' => FeaturesManagerInterface::STATUS_NO_EXPORT,
]),
'package4' => new Package('package4', [
'bundle' => 'my_bundle',
'status' => FeaturesManagerInterface::STATUS_UNINSTALLED,
]),
];
// Filter for the default bundle.
$filtered_packages = $this->featuresManager->filterPackages($packages, FeaturesBundleInterface::DEFAULT_BUNDLE);
$this->assertEquals(['package', 'package2'], array_keys($filtered_packages));
// Filter for a custom bundle.
$filtered_packages = $this->featuresManager->filterPackages($packages, 'my_bundle');
$this->assertEquals(['package3', 'package4'], array_keys($filtered_packages));
// Filter for a non-matching bundle.
$filtered_packages = $this->featuresManager->filterPackages($packages, 'some_bundle');
$this->assertEquals([], array_keys($filtered_packages));
// Filter for the default bundle removing only exported.
$filtered_packages = $this->featuresManager->filterPackages($packages, FeaturesBundleInterface::DEFAULT_BUNDLE, TRUE);
$this->assertEquals(['package'], array_keys($filtered_packages));
// Filter for a custom bundle removing only exported.
$filtered_packages = $this->featuresManager->filterPackages($packages, 'my_bundle', TRUE);
$this->assertEquals(['package3'], array_keys($filtered_packages));
// Filter for a non-matching bundle removing only exported.
$filtered_packages = $this->featuresManager->filterPackages($packages, 'some_bundle', TRUE);
$this->assertEquals([], array_keys($filtered_packages));
}
protected function getAssignInterPackageDependenciesConfigCollection() {
$config_collection = [];
$config_collection['example.config'] = (new ConfigurationItem('example.config', [
@@ -196,23 +258,46 @@ class FeaturesManagerTest extends UnitTestCase {
'example.config2',
'example.config3',
'example.config4',
'example.config5',
'example.config6',
'example.config7',
],
],
]))->setPackage('package');
]))
->setSubdirectory(InstallStorage::CONFIG_INSTALL_DIRECTORY)
->setPackage('package');
$config_collection['example.config2'] = (new ConfigurationItem('example.config2', [
'dependencies' => [],
]))
->setSubdirectory(InstallStorage::CONFIG_INSTALL_DIRECTORY)
->setPackage('package2')
->setProvider('my_feature');
$config_collection['example.config3'] = (new ConfigurationItem('example.config3', [
'dependencies' => [],
]))
->setSubdirectory(InstallStorage::CONFIG_INSTALL_DIRECTORY)
->setProvider('my_other_feature');
$config_collection['example.config4'] = (new ConfigurationItem('example.config3', [
'dependencies' => [],
]))
->setSubdirectory(InstallStorage::CONFIG_INSTALL_DIRECTORY)
->setProvider(static::PROFILE_NAME);
$config_collection['example.config5'] = (new ConfigurationItem('example.config5', [
'dependencies' => [],
]))
->setSubdirectory(InstallStorage::CONFIG_OPTIONAL_DIRECTORY)
->setPackage('package3');
$config_collection['example.config6'] = (new ConfigurationItem('example.config6', [
'dependencies' => [],
]))
->setSubdirectory(InstallStorage::CONFIG_INSTALL_DIRECTORY)
->setProvider('my_uninstalled_feature');
$config_collection['example.config7'] = (new ConfigurationItem('example.config7', [
'dependencies' => [],
]))
->setSubdirectory(InstallStorage::CONFIG_INSTALL_DIRECTORY)
->setProvider('package4');
return $config_collection;
}
@@ -225,8 +310,10 @@ class FeaturesManagerTest extends UnitTestCase {
// Provide a bundle without any prefix.
$bundle->getFullName('package')->willReturn('package');
$bundle->getFullName('package2')->willReturn('package2');
$bundle->getFullName('package3')->willReturn('package3');
$bundle->getFullName('package4')->willReturn('package4');
$bundle->isDefault()->willReturn(TRUE);
$assigner->getBundle('')->willReturn($bundle->reveal());
$assigner->getBundle()->willReturn($bundle->reveal());
// Use the wrapper because we need ::drupalGetProfile().
$features_manager = new TestFeaturesManager($this->root, $this->entityTypeManager, $this->configFactory, $this->configStorage, $this->configManager, $this->moduleHandler, $this->configReverter);
$features_manager->setAssigner($assigner->reveal());
@@ -244,6 +331,16 @@ class FeaturesManagerTest extends UnitTestCase {
'dependencies' => [],
'bundle' => '',
]),
'package3' => new Package('package3', [
'config' => ['example.config5'],
'dependencies' => [],
'bundle' => '',
]),
'package4' => new Package('package4', [
'config' => ['example.config7'],
'dependencies' => [],
'bundle' => '',
]),
];
$features_manager->setPackages($packages);
@@ -257,6 +354,13 @@ class FeaturesManagerTest extends UnitTestCase {
// my_package.
// Because package assignments take precedence over providing_feature ones,
// package2 should have been assigned rather than my_feature.
// Because it is assigned to the InstallStorage::CONFIG_OPTIONAL_DIRECTORY
// subdirectory, example.config5 does not create a dependency on its
// providing feature, package3.
// Because it's provided by an uninstalled module, example.config6 doesn't
// create a dependency on my_uninstalled_feature.
// Because it's provided by an uninstalled module, example.config7 doesn't
// create a dependency on package4.
$this->assertEquals(['my_other_feature', 'package2'], $packages['package']->getDependencies());
$this->assertEquals([], $packages['package2']->getDependencies());
}
@@ -270,6 +374,8 @@ class FeaturesManagerTest extends UnitTestCase {
// Provide a bundle without any prefix.
$bundle->getFullName('package')->willReturn('giraffe_package');
$bundle->getFullName('package2')->willReturn('giraffe_package2');
$bundle->getFullName('package3')->willReturn('giraffe_package3');
$bundle->getFullName('package4')->willReturn('giraffe_package4');
$bundle->getFullName('giraffe_package')->willReturn('giraffe_package');
$bundle->getFullName('giraffe_package2')->willReturn('giraffe_package2');
$bundle->isDefault()->willReturn(FALSE);
@@ -291,6 +397,16 @@ class FeaturesManagerTest extends UnitTestCase {
'dependencies' => [],
'bundle' => 'giraffe',
]),
'package3' => new Package('package3', [
'config' => ['example.config5'],
'dependencies' => [],
'bundle' => 'giraffe',
]),
'package4' => new Package('package4', [
'config' => ['example.config7'],
'dependencies' => [],
'bundle' => 'giraffe',
]),
];
$features_manager->setPackages($packages);
@@ -304,6 +420,13 @@ class FeaturesManagerTest extends UnitTestCase {
// my_package.
// Because package assignments take precedence over providing_feature ones,
// package2 should have been assigned rather than my_feature.
// Because it is assigned to the InstallStorage::CONFIG_OPTIONAL_DIRECTORY
// subdirectory, example.config5 does not create a dependency on its
// providing feature, package3.
// Because it's provided by an uninstalled module, example.config6 doesn't
// create a dependency on my_uninstalled_feature.
// Because it's provided by an uninstalled module, example.config7 doesn't
// create a dependency on giraffe_package4.
$expected = ['giraffe_package2', 'my_other_feature'];
$this->assertEquals($expected, $packages['giraffe_package']->getDependencies());
}
@@ -417,6 +540,7 @@ class FeaturesManagerTest extends UnitTestCase {
$assigner = $this->prophesize(FeaturesAssignerInterface::class);
$bundle = $this->prophesize(FeaturesBundleInterface::class);
$bundle->isProfilePackage('test_package')->willReturn(FALSE);
$bundle->isProfilePackage('test_package2')->willReturn(FALSE);
$assigner->getBundle(NULL)->willReturn($bundle->reveal());
$this->featuresManager->setAssigner($assigner->reveal());
@@ -424,21 +548,43 @@ class FeaturesManagerTest extends UnitTestCase {
'test_config' => new ConfigurationItem('test_config', []),
'test_config2' => new ConfigurationItem('test_config2', [
'dependencies' => [
'module' => ['example'],
'module' => ['example', 'example2'],
]
], [
'subdirectory' => InstallStorage::CONFIG_INSTALL_DIRECTORY,
]),
'example3.settings' => new ConfigurationItem('example3.settings', [], [
'type' => FeaturesManagerInterface::SYSTEM_SIMPLE_CONFIG,
'subdirectory' => InstallStorage::CONFIG_INSTALL_DIRECTORY,
]),
'test_config3' => new ConfigurationItem('test_config3', [
'dependencies' => [
'module' => ['example2'],
]
], [
'subdirectory' => InstallStorage::CONFIG_OPTIONAL_DIRECTORY,
]),
];
$this->featuresManager->setConfigCollection($config_collection);
$package = new Package('test_package');
$this->featuresManager->setPackage($package);
$this->featuresManager->assignConfigPackage('test_package', ['test_config', 'test_config2']);
$this->featuresManager->assignConfigPackage('test_package', ['test_config', 'test_config2', 'example3.settings']);
$this->assertEquals(['test_config', 'test_config2'], $this->featuresManager->getPackage('test_package')->getConfig());
$this->assertEquals(['example', 'my_module'], $this->featuresManager->getPackage('test_package')->getDependencies());
$this->assertEquals(['test_config', 'test_config2', 'example3.settings'], $this->featuresManager->getPackage('test_package')->getConfig());
// 'example2' is not returned by ::getModuleList() and so isn't a
// dependency.
$this->assertEquals(['example', 'example3', 'my_module'], $this->featuresManager->getPackage('test_package')->getDependencies());
// Test optional config, which doesn't create module dependencies.
$package = new Package('test_package2');
$this->featuresManager->setPackage($package);
$this->featuresManager->assignConfigPackage('test_package2', ['test_config3']);
$this->assertEquals(['test_config3'], $this->featuresManager->getPackage('test_package2')->getConfig());
$this->assertEquals([], $this->featuresManager->getPackage('test_package2')->getDependencies());
}
/**
@@ -451,6 +597,32 @@ class FeaturesManagerTest extends UnitTestCase {
];
$this->featuresManager->setConfigCollection($config_collection);
$feature_assigner = $this->prophesize(FeaturesAssignerInterface::class);
$feature_assigner->getBundle(NULL)->willReturn(new FeaturesBundle(['machine_name' => FeaturesBundleInterface::DEFAULT_BUNDLE], 'features_bundle'));
$this->featuresManager->setAssigner($feature_assigner->reveal());
$package = new Package('test_package');
$original_package = clone $package;
$this->featuresManager->setPackage($package);
$this->featuresManager->assignConfigPackage('test_package', ['test_config', 'test_config2']);
$this->assertEquals(['test_config'], $this->featuresManager->getPackage('test_package')->getConfig(), 'just assign new packages');
$this->featuresManager->setPackage($original_package);
$this->featuresManager->assignConfigPackage('test_package', ['test_config', 'test_config2'], TRUE);
$this->assertEquals(['test_config', 'test_config2'], $this->featuresManager->getPackage('test_package')->getConfig(), 'just assign new packages');
}
/**
* @covers ::assignConfigPackage
*/
public function testAssignConfigPackageWithPackageExcludedConfig() {
$config_collection = [
'test_config' => new ConfigurationItem('test_config', []),
'test_config2' => new ConfigurationItem('test_config2', [], ['packageExcluded' => ['test_package']]),
];
$this->featuresManager->setConfigCollection($config_collection);
$feature_assigner = $this->prophesize(FeaturesAssignerInterface::class);
$feature_assigner->getBundle(NULL)->willReturn(new FeaturesBundle(['machine_name' => 'default'], 'features_bundle'));
$this->featuresManager->setAssigner($feature_assigner->reveal());
@@ -687,6 +859,7 @@ EOT
/**
* @covers ::prepareFiles
* @covers ::addInfoFile
*/
public function testPrepareFiles() {
$packages = [];
@@ -695,12 +868,22 @@ EOT
'name' => 'Test feature',
]);
$packages['test_feature2'] = new Package('test_feature2', [
'config' => ['test_config2'],
'name' => 'Test feature 2',
'type' => 'profile',
'excluded' => ['my_config'],
'required' => ['test_config2'],
]);
$config_collection = [];
$config_collection['test_config'] = new ConfigurationItem('test_config', ['foo' => 'bar']);
$config_collection['test_config2'] = new ConfigurationItem('test_config2', ['foo' => 'bar']);
$this->featuresManager->setConfigCollection($config_collection);
$this->featuresManager->prepareFiles($packages);
// Test test_feature package.
$files = $packages['test_feature']->getFiles();
$this->assertCount(3, $files);
$this->assertEquals('test_feature.info.yml', $files['info']['filename']);
@@ -718,6 +901,14 @@ EOT
$this->assertEquals('test_feature.features.yml', $files['features']['filename']);
$this->assertEquals(Yaml::encode(TRUE), $files['features']['string']);
// Test test_feature2 package.
$files = $packages['test_feature2']->getFiles();
$this->assertEquals(Yaml::encode([
'excluded' => ['my_config'],
'required' => ['test_config2'],
]), $files['features']['string']);
}
/**