Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • project/group
  • issue/group-3157478
  • issue/group-3084140
  • issue/group-3159277
  • issue/group-3163334
  • issue/group-3166252
  • issue/group-3167443
  • issue/group-3169377
  • issue/group-2797793
  • issue/group-2919982
  • issue/group-3177042
  • issue/group-3177542
  • issue/group-2801603
  • issue/group-3179857
  • issue/group-3052620
  • issue/group-2872645
  • issue/group-3007472
  • issue/group-3162259
  • issue/group-3183791
  • issue/group-3150877
  • issue/group-3185179
  • issue/group-3067811
  • issue/group-3189659
  • issue/group-3190190
  • issue/group-3190306
  • issue/group-2876696
  • issue/group-3118383
  • issue/group-3026735
  • issue/group-3194750
  • issue/group-3197122
  • issue/group-2746839
  • issue/group-3163683
  • issue/group-3201941
  • issue/group-3202091
  • issue/group-3202966
  • issue/group-3202249
  • issue/group-3045373
  • issue/group-3278740
  • issue/group-3209096
  • issue/group-3207064
  • issue/group-3214009
  • issue/group-3166107
  • issue/group-3214895
  • issue/group-2916907
  • issue/group-3220758
  • issue/group-3221785
  • issue/group-3222359
  • issue/group-3222747
  • issue/group-3223957
  • issue/group-2824018
  • issue/group-3226713
  • issue/group-3227793
  • issue/group-3228454
  • issue/group-3229567
  • issue/group-3232851
  • issue/group-3137312
  • issue/group-2295249
  • issue/group-3236626
  • issue/group-3281530
  • issue/group-3202908
  • issue/group-3278778
  • issue/group-3245095
  • issue/group-2972933
  • issue/group-3074933
  • issue/group-3162511
  • issue/group-3253368
  • issue/group-2767155
  • issue/group-2877493
  • issue/group-3254038
  • issue/group-3257227
  • issue/group-3257756
  • issue/group-2717981
  • issue/group-3259178
  • issue/group-3256998
  • issue/group-3204083
  • issue/group-3082125
  • issue/group-3265962
  • issue/group-3266146
  • issue/group-3262923
  • issue/group-3276613
  • issue/group-3005047
  • issue/group-3284402
  • issue/group-3071489
  • issue/group-3061881
  • issue/group-3305051
  • issue/group-2842630
  • issue/group-3301785
  • issue/group-3310499
  • issue/group-3311119
  • issue/group-3307282
  • issue/group-3307291
  • issue/group-2933819
  • issue/group-3310605
  • issue/group-2774729
  • issue/group-3311949
  • issue/group-3313220
  • issue/group-3317459
  • issue/group-3313515
  • issue/group-3315779
  • issue/group-2817109
  • issue/group-3319274
  • issue/group-3325789
  • issue/group-3320513
  • issue/group-3328660
  • issue/group-3210808
  • issue/group-3317396
  • issue/group-3325994
  • issue/group-3322623
  • issue/group-3331923
  • issue/group-3332963
  • issue/group-3112501
  • issue/group-3324506
  • issue/group-3344283
  • issue/group-3180860
  • issue/group-3104345
  • issue/group-3332640
  • issue/group-3354135
  • issue/group-3322761
  • issue/group-3367755
  • issue/group-3406043
  • issue/group-3398778
  • issue/group-3399601
  • issue/group-3406373
  • issue/group-3371637
  • issue/group-3371641
  • issue/group-3371651
  • issue/group-3374041
  • issue/group-3378653
  • issue/group-3364226
  • issue/group-3378977
  • issue/group-3399569
  • issue/group-3336186
  • issue/group-3382559
  • issue/group-3382831
  • issue/group-3016197
  • issue/group-2878723
  • issue/group-3390016
  • issue/group-3268711
  • issue/group-3394724
  • issue/group-3379174
  • issue/group-3397015
  • issue/group-3397021
  • issue/group-3397114
  • issue/group-3399085
  • issue/group-3406840
  • issue/group-3336280
  • issue/group-3409735
  • issue/group-3411381
  • issue/group-3413722
  • issue/group-3414592
  • issue/group-3415695
  • issue/group-3416324
  • issue/group-3421138
  • issue/group-3422253
  • issue/group-3422445
  • issue/group-3423341
  • issue/group-2895988
  • issue/group-3420605
  • issue/group-3424972
  • issue/group-3132084
  • issue/group-3101314
  • issue/group-3425601
  • issue/group-3426007
  • issue/group-3426098
  • issue/group-3426239
  • issue/group-3426408
  • issue/group-3427343
  • issue/group-3397063
  • issue/group-3427547
  • issue/group-3427552
  • issue/group-3428392
  • issue/group-3419405
  • issue/group-3441929
  • issue/group-2774827
  • issue/group-3414708
  • issue/group-2815971
  • issue/group-3441076
  • issue/group-3438400
  • issue/group-3440222
  • issue/group-3409374
  • issue/group-3430826
  • issue/group-3446192
  • issue/group-3137221
  • issue/group-3448221
  • issue/group-3449620
  • issue/group-3449640
  • issue/group-3346626
  • issue/group-3451560
  • issue/group-3437029
  • issue/group-3457095
  • issue/group-3462425
  • issue/group-2929788
  • issue/group-3352235
  • issue/group-3455789
  • issue/group-3467754
  • issue/group-3469835
  • issue/group-3470663
  • issue/group-3036272
  • issue/group-3469890
  • issue/group-3475807
  • issue/group-2907838
  • issue/group-3476539
  • issue/group-3478088
  • issue/group-3475816
  • issue/group-3399452
  • issue/group-3480110
  • issue/group-2754399
  • issue/group-3278936
  • issue/group-3482975
  • issue/group-3421756
  • issue/group-3485785
  • issue/group-3482418
  • issue/group-3490229
  • issue/group-3490670
  • issue/group-3489243
  • issue/group-3493593
  • issue/group-3493597
  • issue/group-3493741
  • issue/group-3493807
  • issue/group-3494447
  • issue/group-3494780
  • issue/group-3494986
  • issue/group-3497467
  • issue/group-3499639
  • issue/group-3494298
  • issue/group-3501018
  • issue/group-3502994
  • issue/group-3504133
  • issue/group-3504805
  • issue/group-3505771
  • issue/group-3506061
  • issue/group-3506097
  • issue/group-3506163
  • issue/group-3507425
  • issue/group-3508876
  • issue/group-3509416
  • issue/group-3509657
  • issue/group-3511625
  • issue/group-3512941
  • issue/group-3511454
  • issue/group-3484817
241 results
Show changes
Commits on Source (90)
Showing
with 710 additions and 556 deletions
# Group-specific terminology.
gnode
grfd
gcfd
gids
# General list of terms.
subconditions
decoratable
# Test cases.
pagefoobarbaz
relationfoobar
relationfoobarbazfoo
bazfoo
# Not copying all comments from template, original found here:
# https://git.drupalcode.org/project/gitlab_templates/-/blob/1.0.x/gitlab-ci/template.gitlab-ci.yml
include:
- project: $_GITLAB_TEMPLATES_REPO
ref: 'main'
file:
- '/includes/include.drupalci.main.yml'
- '/includes/include.drupalci.variables.yml'
- '/includes/include.drupalci.workflows.yml'
variables:
SKIP_ESLINT: '1'
OPT_IN_TEST_MAX_PHP: '1'
OPT_IN_TEST_NEXT_MINOR: '1'
_CURL_TEMPLATES_REF: 'main'
......@@ -17,8 +17,12 @@
"license": "GPL-2.0-or-later",
"minimum-stability": "dev",
"require": {
"drupal/core": "^9 || ^10",
"drupal/core": "^10.3 || ^11",
"drupal/entity": "^1.2",
"drupal/flexible_permissions": "^1.0"
"drupal/flexible_permissions": "^2.0"
},
"require-dev": {
"drupal/variationcache": "^1.5",
"jangregor/phpstan-prophecy": "^1.0"
}
}
......@@ -4,9 +4,9 @@ dependencies:
module:
- 'group'
- 'options'
id: 'group_content.group_roles'
id: 'group_relationship.group_roles'
field_name: 'group_roles'
entity_type: 'group_content'
entity_type: 'group_relationship'
type: 'entity_reference'
settings:
target_type: 'group_role'
......
......@@ -3,13 +3,13 @@ status: true
dependencies:
module:
- group
id: group_content
id: group_relationship
label: 'Group relationship'
type: 'canonical_entities:group_content'
pattern: 'group/[group_content:group:id]/[group_content:pretty-path-key]/[group_content:id]'
type: 'canonical_entities:group_relationship'
pattern: 'group/[group_relationship:group:id]/[group_relationship:pretty-path-key]/[group_relationship:id]'
selection_criteria: { }
selection_logic: and
weight: -5
relationships:
'group_content:langcode:language':
'group_relationship:langcode:language':
label: Language
......@@ -2,7 +2,7 @@ langcode: en
status: true
dependencies:
config:
- field.storage.group_content.group_roles
- field.storage.group_relationship.group_roles
module:
- group
- user
......@@ -13,144 +13,14 @@ description: ''
tag: ''
base_table: group_relationship_field_data
base_field: id
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
display_plugin: default
position: 0
display_options:
access:
type: group_permission
options:
group_permission: 'administer members'
cache:
type: tag
options: { }
query:
type: views_query
options:
disable_sql_rewrite: false
distinct: false
replica: false
query_comment: ''
query_tags: { }
exposed_form:
type: basic
options:
submit_button: Apply
reset_button: false
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
pager:
type: full
options:
items_per_page: 50
offset: 0
id: 0
total_pages: null
tags:
previous: ‹‹
next: ››
first: '« First'
last: 'Last »'
expose:
items_per_page: false
items_per_page_label: 'Items per page'
items_per_page_options: '5, 10, 25, 50'
items_per_page_options_all: false
items_per_page_options_all_label: '- All -'
offset: false
offset_label: Offset
quantity: 9
style:
type: table
options:
grouping: { }
row_class: ''
default_row_class: true
override: true
sticky: true
caption: ''
summary: ''
description: ''
columns:
name: name
group_roles: group_roles
changed: changed
created: created
view_group_content: view_group_content
edit_group_content: edit_group_content
delete_group_content: delete_group_content
dropbutton: dropbutton
info:
name:
sortable: true
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
group_roles:
align: ''
separator: ''
empty_column: false
responsive: ''
changed:
sortable: true
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
created:
sortable: true
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
view_group_content:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
edit_group_content:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
delete_group_content:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
dropbutton:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
default: '-1'
empty_table: true
row:
type: fields
options:
inline: { }
separator: ''
hide_empty: false
default_field_elements: true
title: Members
fields:
name:
id: name
......@@ -159,6 +29,9 @@ display:
relationship: gc__user
group_type: group
admin_label: ''
entity_type: user
entity_field: name
plugin_id: field
label: User
exclude: false
alter:
......@@ -214,16 +87,14 @@ display:
multi_type: separator
separator: ', '
field_api_classes: false
entity_type: user
entity_field: name
plugin_id: field
group_roles:
id: group_roles
table: group_content__group_roles
table: group_relationship__group_roles
field: group_roles
relationship: none
group_type: group
admin_label: ''
plugin_id: field
label: Roles
exclude: false
alter:
......@@ -261,7 +132,7 @@ display:
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: '<div class="item-list"><ul><li>&lt;none&gt;</li></ul></div>'
empty: None
hide_empty: false
empty_zero: false
hide_alter_empty: true
......@@ -279,7 +150,6 @@ display:
multi_type: ul
separator: ', '
field_api_classes: false
plugin_id: field
changed:
id: changed
table: group_relationship_field_data
......@@ -287,6 +157,9 @@ display:
relationship: none
group_type: group
admin_label: ''
entity_type: group_relationship
entity_field: changed
plugin_id: field
label: Updated
exclude: false
alter:
......@@ -344,9 +217,6 @@ display:
multi_type: separator
separator: ', '
field_api_classes: false
entity_type: group_content
entity_field: changed
plugin_id: field
created:
id: created
table: group_relationship_field_data
......@@ -354,6 +224,9 @@ display:
relationship: none
group_type: group
admin_label: ''
entity_type: group_relationship
entity_field: created
plugin_id: field
label: Joined
exclude: false
alter:
......@@ -411,16 +284,15 @@ display:
multi_type: separator
separator: ', '
field_api_classes: false
entity_type: group_content
entity_field: created
plugin_id: field
view_group_content:
id: view_group_content
view_group_relationship:
id: view_group_relationship
table: group_relationship
field: view_group_content
field: view_group_relationship
relationship: none
group_type: group
admin_label: 'View member link'
entity_type: group_relationship
plugin_id: entity_link
label: ''
exclude: true
alter:
......@@ -463,17 +335,17 @@ display:
empty_zero: false
hide_alter_empty: true
text: 'View member'
entity_type: group_content
plugin_id: entity_link
output_url_as_text: false
absolute: false
edit_group_content:
id: edit_group_content
edit_group_relationship:
id: edit_group_relationship
table: group_relationship
field: edit_group_content
field: edit_group_relationship
relationship: none
group_type: group
admin_label: 'Edit member link'
entity_type: group_relationship
plugin_id: entity_link_edit
label: ''
exclude: true
alter:
......@@ -516,15 +388,15 @@ display:
empty_zero: false
hide_alter_empty: true
text: 'Edit member'
entity_type: group_content
plugin_id: entity_link_edit
delete_group_content:
id: delete_group_content
delete_group_relationship:
id: delete_group_relationship
table: group_relationship
field: delete_group_content
field: delete_group_relationship
relationship: none
group_type: group
admin_label: 'Remove member link'
entity_type: group_relationship
plugin_id: entity_link_delete
label: ''
exclude: true
alter:
......@@ -567,8 +439,6 @@ display:
empty_zero: false
hide_alter_empty: true
text: 'Remove member'
entity_type: group_content
plugin_id: entity_link_delete
dropbutton:
id: dropbutton
table: views
......@@ -576,6 +446,7 @@ display:
relationship: none
group_type: group
admin_label: ''
plugin_id: dropbutton
label: Operations
exclude: false
alter:
......@@ -617,20 +488,53 @@ display:
hide_empty: false
empty_zero: false
hide_alter_empty: true
destination: true
fields:
view_group_content: view_group_content
edit_group_content: edit_group_content
delete_group_content: delete_group_content
view_group_relationship: view_group_relationship
edit_group_relationship: edit_group_relationship
delete_group_relationship: delete_group_relationship
name: '0'
group_roles: '0'
changed: '0'
created: '0'
destination: true
plugin_id: dropbutton
filters: { }
sorts: { }
header: { }
footer: { }
pager:
type: full
options:
offset: 0
items_per_page: 50
total_pages: null
id: 0
tags:
next: ››
previous: ‹‹
first: '« First'
last: 'Last »'
expose:
items_per_page: false
items_per_page_label: 'Items per page'
items_per_page_options: '5, 10, 25, 50'
items_per_page_options_all: false
items_per_page_options_all_label: '- All -'
offset: false
offset_label: Offset
quantity: 9
exposed_form:
type: basic
options:
submit_button: Apply
reset_button: false
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
access:
type: group_permission
options:
group_permission: 'administer members'
cache:
type: tag
options: { }
empty:
area_text_custom:
id: area_text_custom
......@@ -639,23 +543,11 @@ display:
relationship: none
group_type: group
admin_label: ''
plugin_id: text_custom
empty: true
tokenize: false
content: 'No members available.'
plugin_id: text_custom
relationships:
gc__user:
id: gc__user
table: group_relationship_field_data
field: gc__user
relationship: none
group_type: group
admin_label: 'Member account'
required: true
group_content_plugins:
group_membership: group_membership
entity_type: group_content
plugin_id: group_content_to_entity
tokenize: false
sorts: { }
arguments:
gid:
id: gid
......@@ -664,6 +556,9 @@ display:
relationship: none
group_type: group
admin_label: ''
entity_type: group_relationship
entity_field: gid
plugin_id: numeric
default_action: 'access denied'
exception:
value: all
......@@ -674,12 +569,11 @@ display:
default_argument_type: fixed
default_argument_options:
argument: ''
default_argument_skip_url: false
summary_options:
base_path: ''
count: true
items_per_page: 25
override: false
items_per_page: 25
summary:
sort_order: asc
number_of_records: 0
......@@ -691,11 +585,115 @@ display:
validate_options: { }
break_phrase: false
not: false
entity_type: group_content
entity_field: gid
plugin_id: numeric
filters: { }
style:
type: table
options:
grouping: { }
row_class: ''
default_row_class: true
columns:
name: name
group_roles: group_roles
changed: changed
created: created
view_group_relationship: view_group_relationship
edit_group_relationship: edit_group_relationship
delete_group_relationship: delete_group_relationship
dropbutton: dropbutton
default: '-1'
info:
name:
sortable: true
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
group_roles:
align: ''
separator: ''
empty_column: false
responsive: ''
changed:
sortable: true
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
created:
sortable: true
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
view_group_relationship:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
edit_group_relationship:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
delete_group_relationship:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
dropbutton:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
override: true
sticky: true
summary: ''
empty_table: true
caption: ''
description: ''
row:
type: fields
options:
default_field_elements: true
inline: { }
separator: ''
hide_empty: false
query:
type: views_query
options:
query_comment: ''
disable_sql_rewrite: false
distinct: false
replica: false
query_tags: { }
relationships:
gc__user:
id: gc__user
table: group_relationship_field_data
field: gc__user
relationship: none
group_type: group
admin_label: 'Member account'
entity_type: group_relationship
plugin_id: group_relationship_to_entity
required: true
group_relation_plugins:
group_membership: group_membership
header: { }
footer: { }
display_extenders: { }
title: Members
cache_metadata:
max-age: -1
contexts:
......@@ -706,11 +704,11 @@ display:
- url.query_args
- user.group_permissions
tags:
- 'config:field.storage.group_content.group_roles'
- 'config:field.storage.group_relationship.group_roles'
page_1:
display_plugin: page
id: page_1
display_title: Page
display_plugin: page
position: 1
display_options:
display_extenders: { }
......@@ -719,12 +717,12 @@ display:
type: tab
title: Members
description: ''
weight: 20
enabled: true
expanded: false
menu_name: main
parent: ''
weight: 20
context: '0'
menu_name: main
enabled: true
cache_metadata:
max-age: -1
contexts:
......@@ -735,4 +733,4 @@ display:
- url.query_args
- user.group_permissions
tags:
- 'config:field.storage.group_content.group_roles'
- 'config:field.storage.group_relationship.group_roles'
......@@ -82,7 +82,7 @@ group.role.*:
type: 'string'
label: 'Group permission'
group_content_type:
group_relationship_type:
type: 'config_entity'
label: 'Group relationship type'
mapping:
......@@ -107,10 +107,10 @@ group_content_type:
sequence:
type: 'group_relation.config.[%key]'
# Follows the pattern group.content_type.GROUP_TYPE_ID-PLUGIN_ID.
# Follows the pattern group.content_type.GROUP_TYPE_ID-PLUGIN_ID-DERIVATIVE_ID.
group.content_type.*:
type: 'group_content_type'
# Follows the pattern group.relationship_type.GROUP_TYPE_ID-PLUGIN_ID.
# Follows the pattern group.relationship_type.GROUP_TYPE_ID-PLUGIN_ID-DERIVATIVE_ID.
group.relationship_type.*:
type: 'group_relationship_type'
label: 'Group relationship type'
entity_reference_selection.group_type:group_role:
......
......@@ -26,21 +26,21 @@ views.argument_default.group_id_from_url:
views_relationship_with_group_plugin_filter:
type: 'views_relationship'
mapping:
group_content_plugins:
group_relation_plugins:
type: 'sequence'
label: 'Group relation plugins'
sequence:
type: 'string'
label: 'Group relation plugin ID'
views.relationship.group_content_to_entity:
views.relationship.group_relationship_to_entity:
type: 'views_relationship_with_group_plugin_filter'
label: 'Group relationship to entity reference'
views.relationship.group_content_to_entity_reverse:
views.relationship.group_relationship_to_entity_reverse:
type: 'views_relationship_with_group_plugin_filter'
label: 'Reverse group relationship to entity reference'
views.relationship.group_to_group_content:
views.relationship.group_to_group_relationship:
type: 'views_relationship_with_group_plugin_filter'
label: 'Group to group relationship'
......@@ -4,20 +4,20 @@
/* Permissions page */
.permissions .module {
font-weight: bold;
font-weight: bold;
}
.permissions .section {
font-style: italic;
padding-left: 1.5em; /* LTR */
padding-left: 1.5em; /* LTR */
font-style: italic;
}
[dir="rtl"] .permissions .section {
padding-left: 0;
padding-right: 1.5em;
padding-right: 1.5em;
padding-left: 0;
}
.permissions .permission {
padding-left: 2.5em; /* LTR */
padding-left: 2.5em; /* LTR */
}
[dir="rtl"] .permissions .permission {
padding-left: 0;
padding-right: 2.5em;
padding-right: 2.5em;
padding-left: 0;
}
/**
* Main menu icons.
*/
.toolbar-icon-system-admin-group:before {
background-image: url(../images/icons/787878/toolbar.svg);
.toolbar-icon-system-admin-group::before {
background-image: url(../images/icons/787878/toolbar.svg);
}
.toolbar-icon-system-admin-group:active:before,
.toolbar-icon-system-admin-group.is-active:before {
background-image: url(../images/icons/000000/toolbar.svg);
.toolbar-icon-system-admin-group:active::before,
.toolbar-icon-system-admin-group.is-active::before {
background-image: url(../images/icons/000000/toolbar.svg);
}
......@@ -5,7 +5,6 @@
* Hooks specific to the Group module.
*/
use Drupal\Core\Session\AccountInterface;
use Drupal\group\Entity\GroupInterface;
/**
......@@ -18,7 +17,7 @@ use Drupal\group\Entity\GroupInterface;
*
* @param array $operations
* A list of links to be set in an 'operations' element.
* @param GroupInterface $group
* @param \Drupal\group\Entity\GroupInterface $group
* The group to alter the operations for.
*
* @see \Drupal\group\Plugin\Block\GroupOperationsBlock
......
......@@ -2,7 +2,7 @@ name: 'Group'
description: 'Allows you to group users, content and other entities'
package: 'Group'
type: 'module'
core_version_requirement: ^9 || ^10
core_version_requirement: ^10.3 || ^11
configure: 'group.settings'
dependencies:
- 'drupal:options'
......
......@@ -5,268 +5,340 @@
* Install, update and uninstall functions for the group module.
*/
use Drupal\Core\Config\Entity\Query\QueryFactory;
use Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\Sql\DefaultTableMapping;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\group\Entity\GroupRelationship;
use Drupal\group\Entity\GroupRelationshipType;
use Drupal\group\Entity\GroupTypeInterface;
use Drupal\group\PermissionScopeInterface;
use Drupal\user\RoleInterface;
use Drupal\field\FieldStorageConfigInterface;
/**
* Implements hook_update_last_removed().
*/
function group_update_last_removed() {
return 8023;
return 9210;
}
/**
* Update class name and handler class names for group_content_type.
* Updates database and fields from Group 2 to Group 3.
*/
function group_update_9201() {
$definition_update_manager = \Drupal::entityDefinitionUpdateManager();
// Update the class name and handlers for group_content_type.
$new_handlers = \Drupal::entityTypeManager()->getDefinition('group_content_type')->getHandlerClasses();
$entity_type = $definition_update_manager->getEntityType('group_content_type');
$entity_type->setClass(GroupRelationshipType::class);
$entity_type->set('handlers', $new_handlers);
$definition_update_manager->updateEntityType($entity_type);
}
function group_update_10300(&$sandbox) {
$state = \Drupal::state();
$config_factory = \Drupal::configFactory();
$group_content_type_configs = $config_factory->listAll('group.content_type.');
/**
* Update class name and handler class names for group_content.
*/
function group_update_9202() {
$definition_update_manager = \Drupal::entityDefinitionUpdateManager();
$last_installed_schema_repository = \Drupal::service('entity.last_installed_schema.repository');
assert($last_installed_schema_repository instanceof EntityLastInstalledSchemaRepositoryInterface);
// Short-circuit the following updates if we are already on version 3.
if (empty($group_content_type_configs)) {
$state->set('group_update_10300_detected_legacy_version', FALSE);
return t('Module was already on v3, skipping upgrade path.');
}
$state->set('group_update_10300_detected_legacy_version', TRUE);
// Update the class name and handlers for group_content.
$new_handlers = \Drupal::entityTypeManager()->getDefinition('group_content')->getHandlerClasses();
$entity_type = $definition_update_manager->getEntityType('group_content');
$entity_type->setClass(GroupRelationship::class);
$entity_type->set('handlers', $new_handlers);
$table_mapping = \Drupal::entityTypeManager()->getStorage('group_relationship')->getTableMapping();
assert($table_mapping instanceof DefaultTableMapping);
// Instead of using the entity definition update manager, we immediately write
// these changes as they would otherwise trigger a data migration and choke on
// the fact that the old storage class no longer exists.
$last_installed_schema_repository->setLastInstalledDefinition($entity_type);
}
/**
* Update group_content DB table, fields and indexes.
*/
function group_update_9203(&$sandbox) {
$definition_update_manager = \Drupal::entityDefinitionUpdateManager();
$last_installed_schema_repository = \Drupal::service('entity.last_installed_schema.repository');
assert($last_installed_schema_repository instanceof EntityLastInstalledSchemaRepositoryInterface);
// Update the database tables.
$entity_type = $definition_update_manager->getEntityType('group_content');
$entity_type->set('base_table', 'group_relationship');
$entity_type->set('data_table', 'group_relationship_field_data');
$installed_storage_schema = \Drupal::keyValue('entity.storage_schema.sql');
$definition_update_manager = \Drupal::entityDefinitionUpdateManager();
// Add the plugin_id and group_type field.
// Update field storages and DB tables that were created for group_content.
$field_storage_definitions = $last_installed_schema_repository->getLastInstalledFieldStorageDefinitions('group_content');
$field_storage_definitions['plugin_id'] = BaseFieldDefinition::create('string')
->setName('plugin_id')
->setTargetEntityTypeId('group_content')
->setTargetBundle(NULL)
->setLabel(t('Plugin ID'))
->setRequired(TRUE)
->setReadOnly(TRUE)
->setInitialValue('TEMP')
->setProvider('group');
$field_storage_definitions['group_type'] = BaseFieldDefinition::create('entity_reference')
->setName('group_type')
->setTargetEntityTypeId('group_content')
->setTargetBundle(NULL)
->setLabel(t('Group type'))
->setSetting('target_type', 'group_type')
->setRequired(TRUE)
->setReadOnly(TRUE)
->setInitialValue('TEMP')
->setProvider('group');
// Update the fields and regenerate indexes, the correct initial values will
// be retrieved from GroupRelationshipStorage::restore().
$definition_update_manager->updateFieldableEntityType($entity_type, $field_storage_definitions, $sandbox);
}
foreach ($field_storage_definitions as $fsd) {
if ($fsd instanceof BaseFieldDefinition) {
$fsd->setTargetEntityTypeId('group_relationship');
$schema = $installed_storage_schema->get('group_content.field_schema_data.' . $fsd->getName());
$installed_storage_schema->set('group_relationship.field_schema_data.' . $fsd->getName(), $schema);
}
elseif ($fsd instanceof FieldStorageConfigInterface) {
if ($requires_storage = $table_mapping->requiresDedicatedTableStorage($fsd)) {
$old_table = $table_mapping->getDedicatedDataTableName($fsd);
}
/**
* Remove the 'bypass group access' permission from all roles.
*/
function group_update_9204() {
$config_factory = \Drupal::configFactory();
foreach ($config_factory->listAll('user.role.') as $config_name) {
$role = $config_factory->getEditable($config_name);
$role->set('permissions', array_values(array_diff($role->get('permissions'), ['bypass group access'])));
$role->save(TRUE);
}
}
$old_id = $fsd->id();
$new_id = str_replace('group_content.', 'group_relationship.', $fsd->id());
/**
* Convert group roles with the 'administer group' permission to admin roles.
*/
function group_update_9205() {
$config_factory = \Drupal::configFactory();
foreach ($config_factory->listAll('group.role.') as $config_name) {
$role = $config_factory->getEditable($config_name);
if (in_array('administer group', $role->get('permissions'), TRUE)) {
$role->set('permissions', []);
$role->set('admin', TRUE);
$old_config = $config_factory->getEditable('field.storage.' . $old_id);
$new_config = $config_factory->getEditable('field.storage.' . $new_id);
$new_config->setData($old_config->getRawData());
$new_config->set('entity_type', 'group_relationship');
$new_config->set('id', $new_id);
$new_config->save(TRUE);
$old_config->delete();
$fsd->set('entity_type', 'group_relationship');
$fsd->set('id', $new_id);
if ($requires_storage) {
$new_table = $table_mapping->getDedicatedDataTableName($fsd);
\Drupal::database()->schema()->renameTable($old_table, $new_table);
}
}
else {
$role->set('admin', FALSE);
throw new \Exception('Found a group_content field we could not move to group_relationship.');
}
$role->save(TRUE);
}
}
/**
* Convert synchronized group roles to new scope and target_role structure.
*/
function group_update_9206() {
$config_factory = \Drupal::configFactory();
$last_installed_schema_repository->setLastInstalledFieldStorageDefinition($fsd);
}
$synchronized_role_ids = [];
foreach ($config_factory->listAll('user.role.') as $role_config_name) {
$role_id = $config_factory->get($role_config_name)->get('id');
// Update entity references that were pointing to group_content.
foreach ($last_installed_schema_repository->getLastInstalledDefinitions() as $entity_type) {
$field_storage_definitions = $last_installed_schema_repository->getLastInstalledFieldStorageDefinitions($entity_type->id());
foreach ($field_storage_definitions as $fsd) {
if ($fsd->getType() !== 'entity_reference') {
continue;
}
if ($fsd->getSetting('target_type') !== 'group_content') {
continue;
}
if ($fsd instanceof BaseFieldDefinition) {
// @todo Throw a warning saying a base or bundle field has changed and needs updating in code.
}
elseif ($fsd instanceof FieldStorageConfigInterface) {
$config = $config_factory->getEditable('field.storage.' . $fsd->id());
$settings = $config->get('settings');
$settings['target_type'] = 'group_relationship';
$config->set('settings', $settings);
$config->save(TRUE);
}
else {
throw new \Exception('Found an entity_reference field storage definition we could not alter the settings for.');
}
// We never synced any roles to anonymous or authenticated.
if ($role_id === RoleInterface::ANONYMOUS_ID || $role_id === RoleInterface::AUTHENTICATED_ID) {
continue;
$fsd->setSetting('target_type', 'group_relationship');
$last_installed_schema_repository->setLastInstalledFieldStorageDefinition($fsd);
}
$synchronized_role_ids[] = $role_id;
}
// Nothing to update if we had no user defined global roles.
if (empty($synchronized_role_ids)) {
return;
// Update all group_content_type entities to become group_relationship_type.
foreach ($group_content_type_configs as $old_id) {
$new_id = str_replace('group.content_type.', 'group.relationship_type.', $old_id);
$old_config = $config_factory->getEditable($old_id);
$new_config = $config_factory->getEditable($new_id);
$new_config->setData($old_config->getRawData());
$new_config->save(TRUE);
$old_config->delete();
}
foreach ($config_factory->listAll('group.type.') as $group_type_config_name) {
$group_type_id = $config_factory->get($group_type_config_name)->get('id');
// Delete the old config key store for QueryFactory.
\Drupal::keyValue(QueryFactory::CONFIG_LOOKUP_PREFIX . 'group_content_type')->deleteAll();
// Update field instances on group_content entities.
foreach ($config_factory->listAll('field.field.group_content.') as $old_name) {
$old_config = $config_factory->getEditable($old_name);
$new_name = str_replace('group_content.', 'group_relationship.', $old_name);
$new_id = str_replace('group_content.', 'group_relationship.', $old_config->get('id'));
$new_config = $config_factory->getEditable($new_name);
$new_config->setData($old_config->getRawData());
$new_config->set('entity_type', 'group_relationship');
$new_config->set('id', $new_id);
if ($dependencies = $new_config->get('dependencies')) {
if (!empty($dependencies['config'])) {
$dependencies['config'] = array_map(function ($dependency_name) {
$search = [
'group.content_type.',
'field.storage.group_content.',
];
$replace = [
'group.relationship_type.',
'field.storage.group_relationship.',
];
return str_replace($search, $replace, $dependency_name);
}, $dependencies['config']);
$new_config->set('dependencies', $dependencies);
}
}
foreach ($synchronized_role_ids as $role_id) {
// Copied the group role ID logic directly from the GroupRoleSynchronizer
// class because that class has been removed in favor of the new roles.
$machine_name_max_length = EntityTypeInterface::ID_MAX_LENGTH - GroupTypeInterface::ID_MAX_LENGTH - 1;
$machine_name = substr(md5('group_role_sync.' . $role_id), 0, $machine_name_max_length);
$group_role_id = "$group_type_id-$machine_name";
$new_config->save(TRUE);
$old_config->delete();
}
// Delete the synchronized role if they had no rights.
$group_role = $config_factory->getEditable('group.role.' . $group_role_id);
if (!$group_role->get('admin') && empty($group_role->get('permissions'))) {
$group_role->delete();
}
// Otherwise update the group role to use the new keys.
else {
$group_role->set('scope', PermissionScopeInterface::OUTSIDER_ID);
$group_role->set('global_role', $role_id);
// Clear the old keys and save.
$group_role->clear('permissions_ui');
$group_role->clear('internal');
$group_role->clear('audience');
$group_role->save(TRUE);
// The bundle field map is only updated when using the update manager.
// See \Drupal\Core\Entity\EntityFieldManager::getFieldMap() for more info on
// how the key value collection is used for this purpose.
$bundle_field_map_store = \Drupal::keyValue('entity.definitions.bundle_field_map');
$bundle_field_map = $bundle_field_map_store->get('group_content');
$bundle_field_map_store->set('group_relationship', $bundle_field_map);
$bundle_field_map_store->delete('group_content');
// Update form and view modes for changed instances.
foreach (['entity_form_display', 'entity_view_display'] as $display_key) {
foreach ($config_factory->listAll("core.$display_key.group_content.") as $old_name) {
$old_config = $config_factory->getEditable($old_name);
$new_name = str_replace('group_content.', 'group_relationship.', $old_name);
$new_id = str_replace('group_content.', 'group_relationship.', $old_config->get('id'));
$new_config = $config_factory->getEditable($new_name);
$new_config->setData($old_config->getRawData());
$new_config->set('targetEntityType', 'group_relationship');
$new_config->set('id', $new_id);
if ($dependencies = $new_config->get('dependencies')) {
if (!empty($dependencies['config'])) {
$dependencies['config'] = array_map(function ($dependency_name) {
$search = [
'group.content_type.',
'field.storage.group_content.',
'field.field.group_content.',
];
$replace = [
'group.relationship_type.',
'field.storage.group_relationship.',
'field.field.group_relationship.',
];
return str_replace($search, $replace, $dependency_name);
}, $dependencies['config']);
$new_config->set('dependencies', $dependencies);
}
}
$new_config->save(TRUE);
$old_config->delete();
}
}
// Update the entity type definitions directly so the DB is left untouched.
$definition = $last_installed_schema_repository->getLastInstalledDefinition('group_content_type');
$definition->set('id', 'group_relationship_type');
$definition->set('config_prefix', 'relationship_type');
$definition->set('bundle_of', 'group_content');
$last_installed_schema_repository->setLastInstalledDefinition($definition);
$definition_update_manager->updateEntityType($definition);
$definition = $last_installed_schema_repository->getLastInstalledDefinition('group_content');
$definition->set('id', 'group_relationship');
$definition->set('bundle_entity_type', 'group_relationship_type');
$definition->set('field_ui_base_route', 'entity.group_relationship_type.edit_form');
$last_installed_schema_repository->setLastInstalledDefinition($definition);
$definition_update_manager->updateEntityType($definition);
$last_installed_schema_repository->deleteLastInstalledDefinition('group_content');
$last_installed_schema_repository->deleteLastInstalledDefinition('group_content_type');
}
/**
* Updates indexes from Group 2 to Group 3.
*/
function group_update_10301(&$sandbox) {
// Short-circuit the update if we are already on version 3.
if (!\Drupal::state()->get('group_update_10300_detected_legacy_version', FALSE)) {
return t('Module was already on v3, skipping upgrade path.');
}
$definition_update_manager = \Drupal::entityDefinitionUpdateManager();
$last_installed_schema_repository = \Drupal::service('entity.last_installed_schema.repository');
assert($last_installed_schema_repository instanceof EntityLastInstalledSchemaRepositoryInterface);
$field_storage_definitions = $last_installed_schema_repository->getLastInstalledFieldStorageDefinitions('group_relationship');
$entity_type = $last_installed_schema_repository->getLastInstalledDefinition('group_relationship');
$definition_update_manager->updateFieldableEntityType($entity_type, $field_storage_definitions, $sandbox);
}
/**
* Convert default group roles to new scope and target_role structure.
* Updates views from Group 2 to Group 3.
*/
function group_update_9207() {
function group_update_10302(&$sandbox) {
// Short-circuit the update if we are already on version 3.
if (!\Drupal::state()->get('group_update_10300_detected_legacy_version', FALSE)) {
return t('Module was already on v3, skipping upgrade path.');
}
$config_factory = \Drupal::configFactory();
$group_role_info = [
'anonymous' => [
'scope' => PermissionScopeInterface::OUTSIDER_ID,
'global_role' => RoleInterface::ANONYMOUS_ID,
],
'outsider' => [
'scope' => PermissionScopeInterface::OUTSIDER_ID,
'global_role' => RoleInterface::AUTHENTICATED_ID,
],
'member' => [
'scope' => PermissionScopeInterface::INSIDER_ID,
'global_role' => RoleInterface::AUTHENTICATED_ID,
],
];
// Update anonymous, outsider and member.
foreach ($config_factory->listAll('group.type.') as $group_type_config_name) {
$group_type_id = $config_factory->get($group_type_config_name)->get('id');
foreach ($group_role_info as $group_role_suffix => $info) {
$group_role_id = "$group_type_id-$group_role_suffix";
// We do not delete the default roles, even if they have no rights.
$group_role = $config_factory->getEditable('group.role.' . $group_role_id);
$group_role->set('scope', $info['scope']);
$group_role->set('global_role', $info['global_role']);
// Clear the old keys and save.
$group_role->clear('permissions_ui');
$group_role->clear('internal');
$group_role->clear('audience');
$group_role->save(TRUE);
if (\Drupal::moduleHandler()->moduleExists('views')) {
foreach ($config_factory->listAll('views.view.') as $view_name) {
$view = $config_factory->getEditable($view_name);
$view->setData(_group_update_view_with_a_bazooka($view->getRawData()))->save(TRUE);
$view->save(TRUE);
}
}
}
/**
* Convert user created group roles to new scope and target_role structure.
* Replaces ALL mention of group_content in a Views view's data.
*
* This is a radical approach in that it makes no assumptions other than any
* mention of group_content on Group v3 or up being wrong and needing
* replacement with group_relationship. Which explains the function name.
*
* @param array $data
* The view data to fire the bazooka at.
*
* @return array
* The data with all replacements made.
*/
function group_update_9208() {
$config_factory = \Drupal::configFactory();
function _group_update_view_with_a_bazooka(array $data): array {
$search = ['group_content_plugins', 'group.content_type.', 'group_content'];
$replace = ['group_relation_plugins', 'group.relationship_type.', 'group_relationship'];
foreach ($config_factory->listAll('group.role.') as $config_name) {
// Now that we've updated synchronized and default roles, any role that
// still has the old properties is a user generated one. So skip the rest.
if (empty($config_factory->get($config_name)->get('audience'))) {
continue;
// As we loop over every item in the array, we fill a new one so that order
// of keys is preserved even if we change the key name.
$new_data = [];
foreach ($data as $key => $value) {
$new_key = str_replace($search, $replace, $key);
if (is_string($value)) {
$new_data[$new_key] = str_replace($search, $replace, $value);
}
elseif (is_array($value)) {
$new_data[$new_key] = _group_update_view_with_a_bazooka($value);
}
else {
$new_data[$new_key] = $value;
}
}
// We do not delete the user created roles, even if they have no rights.
$group_role = $config_factory->getEditable($config_name);
$group_role->set('scope', PermissionScopeInterface::INDIVIDUAL_ID);
return $new_data;
}
// Clear the old keys and save.
$group_role->clear('permissions_ui');
$group_role->clear('internal');
$group_role->clear('audience');
$group_role->save(TRUE);
/**
* Updates views to drop obsolete key.
*/
function group_update_10303(&$sandbox) {
if (\Drupal::moduleHandler()->moduleExists('views')) {
$view = \Drupal::configFactory()->getEditable('views.view.group_members');
if (!$view->isNew()) {
$view->clear('display.default.display_options.arguments.gid.default_argument_skip_url');
$view->save(TRUE);
}
}
}
/**
* Remove label and description from relationship types.
* Make state key for tracking if we came from version 2 clearly defined.
*/
function group_update_9209() {
$config_factory = \Drupal::configFactory();
function group_update_10304(&$sandbox) {
$state = \Drupal::state();
foreach ($config_factory->listAll('group.content_type.') as $config_name) {
$relationship_type = $config_factory->getEditable($config_name);
$relationship_type->clear('label');
$relationship_type->clear('description');
$relationship_type->save(TRUE);
// Previous updates ran with new state entry, do nothing.
if (!is_null($state->get('group_update_10300_detected_legacy_version'))) {
return t('State key was properly set before, skipping update.');
}
// Previous updates ran with old state entry, convert to new state entry.
$old_value = (bool) $state->get('group_update_10300_detected_version', FALSE);
$state->set('group_update_10300_detected_legacy_version', !$old_value);
$state->delete('group_update_10300_detected_version');
}
/**
* Introduce the group_config_wrapper entity type.
* Upgrade group_relationship type ER field.
*/
function group_update_9210() {
$definition_update_manager = \Drupal::entityDefinitionUpdateManager();
if (!$definition_update_manager->getEntityType('group_config_wrapper')) {
$entity_type = \Drupal::entityTypeManager()->getDefinition('group_config_wrapper');
$definition_update_manager->installEntityType($entity_type);
function group_update_10305(&$sandbox) {
// Short-circuit the update if we are already on version 3.
if (!\Drupal::state()->get('group_update_10300_detected_legacy_version', FALSE)) {
return t('Module was already on v3, skipping upgrade path.');
}
$definition_update_manager = \Drupal::entityDefinitionUpdateManager();
$field_storage_definition = $definition_update_manager->getFieldStorageDefinition('type', 'group_relationship');
assert($field_storage_definition instanceof BaseFieldDefinition);
$field_storage_definition->setSetting('target_type', 'group_relationship_type');
$definition_update_manager->updateFieldStorageDefinition($field_storage_definition);
}
......@@ -17,7 +17,7 @@ group.add_group_role:
- 'entity.group_role.collection'
group.add_member:
route_name: 'entity.group_content.add_form'
route_name: 'entity.group_relationship.add_form'
route_parameters:
plugin_id: 'group_membership'
class: '\Drupal\group\Plugin\Menu\LocalAction\WithDestination'
......@@ -25,14 +25,14 @@ group.add_member:
appears_on:
- 'view.group_members.page_1'
group_content.add_page:
route_name: 'entity.group_content.add_page'
group_relationship.add_page:
route_name: 'entity.group_relationship.add_page'
title: 'Add existing entity'
appears_on:
- 'entity.group_content.collection'
- 'entity.group_relationship.collection'
group_content.create_page:
route_name: 'entity.group_content.create_page'
group_relationship.create_page:
route_name: 'entity.group_relationship.create_page'
title: 'Add new entity'
appears_on:
- 'entity.group_content.collection'
- 'entity.group_relationship.collection'
......@@ -38,15 +38,9 @@ group.delete_form:
group.content:
title: 'All entities'
base_route: 'entity.group.canonical'
route_name: 'entity.group_content.collection'
route_name: 'entity.group_relationship.collection'
weight: 15
group.version_history:
title: 'Revisions'
base_route: 'entity.group.canonical'
route_name: 'entity.group.version_history'
weight: 20
group_type.edit_form:
title: 'Edit'
base_route: 'entity.group_type.edit_form'
......@@ -71,10 +65,10 @@ group_type.content_plugins:
route_name: 'entity.group_type.content_plugins'
weight: 25
group_content_type.edit_form:
group_relationship_type.edit_form:
title: 'Configure'
base_route: 'entity.group_content_type.edit_form'
route_name: 'entity.group_content_type.edit_form'
base_route: 'entity.group_relationship_type.edit_form'
route_name: 'entity.group_relationship_type.edit_form'
weight: 0
group_role.edit_form:
......@@ -95,20 +89,20 @@ group_role.permissions_form:
base_route: 'entity.group_role.edit_form'
weight: 10
group_content.view:
group_relationship.view:
title: 'View'
base_route: 'entity.group_content.canonical'
route_name: 'entity.group_content.canonical'
base_route: 'entity.group_relationship.canonical'
route_name: 'entity.group_relationship.canonical'
weight: 0
group_content.edit:
group_relationship.edit:
title: 'Edit'
base_route: 'entity.group_content.canonical'
route_name: 'entity.group_content.edit_form'
base_route: 'entity.group_relationship.canonical'
route_name: 'entity.group_relationship.edit_form'
weight: 5
group_content.delete:
group_relationship.delete:
title: 'Remove'
base_route: 'entity.group_content.canonical'
route_name: 'entity.group_content.delete_form'
base_route: 'entity.group_relationship.canonical'
route_name: 'entity.group_relationship.delete_form'
weight: 10
......@@ -8,7 +8,9 @@
use Drupal\Component\Utility\Html;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
use Drupal\Core\Database\Query\AlterableInterface;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\Core\Entity\EntityFormInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
......@@ -16,14 +18,14 @@ use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\group\Entity\GroupRelationshipInterface;
use Drupal\group\Entity\GroupInterface;
use Drupal\group\Entity\GroupRelationshipInterface;
use Drupal\group\Entity\Storage\ConfigWrapperStorageInterface;
use Drupal\group\Entity\Storage\GroupRelationshipStorageInterface;
use Drupal\group\Entity\Storage\GroupRoleStorageInterface;
use Drupal\group\QueryAccess\EntityQueryAlter;
use Drupal\group\QueryAccess\GroupRelationshipQueryAlter;
use Drupal\group\QueryAccess\GroupQueryAlter;
use Drupal\group\QueryAccess\GroupRelationshipQueryAlter;
use Drupal\views\Plugin\views\query\QueryPluginBase;
use Drupal\views\Plugin\views\query\Sql;
use Drupal\views\ViewExecutable;
......@@ -118,7 +120,7 @@ function group_theme() {
'group' => [
'render element' => 'elements',
],
'group_content' => [
'group_relationship' => [
'render element' => 'elements',
],
];
......@@ -147,20 +149,20 @@ function group_theme_suggestions_group(array $variables) {
/**
* Implements hook_theme_suggestions_HOOK().
*/
function group_theme_suggestions_group_content(array $variables) {
function group_theme_suggestions_group_relationship(array $variables) {
$suggestions = [];
$group_relationship = $variables['elements']['#group_content'];
$group_relationship = $variables['elements']['#group_relationship'];
assert($group_relationship instanceof GroupRelationshipInterface);
$sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_');
$sanitized_bundle = strtr($group_relationship->bundle(), '-', '_');
$suggestions[] = 'group_content__' . $sanitized_view_mode;
$suggestions[] = 'group_content__' . $sanitized_bundle;
$suggestions[] = 'group_content__' . $sanitized_bundle . '__' . $sanitized_view_mode;
$suggestions[] = 'group_content__' . $group_relationship->id();
$suggestions[] = 'group_content__' . $group_relationship->id() . '__' . $sanitized_view_mode;
$suggestions[] = 'group_relationship__' . $sanitized_view_mode;
$suggestions[] = 'group_relationship__' . $sanitized_bundle;
$suggestions[] = 'group_relationship__' . $sanitized_bundle . '__' . $sanitized_view_mode;
$suggestions[] = 'group_relationship__' . $group_relationship->id();
$suggestions[] = 'group_relationship__' . $group_relationship->id() . '__' . $sanitized_view_mode;
return $suggestions;
}
......@@ -168,7 +170,7 @@ function group_theme_suggestions_group_content(array $variables) {
/**
* Prepares variables for the group template.
*
* Default template: group.html.twig
* Default template: group.html.twig.
*
* @param array $variables
* - elements: An array of elements to display in view mode.
......@@ -182,19 +184,26 @@ function template_preprocess_group(&$variables) {
$variables['group'] = $group;
$variables['view_mode'] = $variables['elements']['#view_mode'];
$variables['label'] = $group->label();
$variables['url'] = $group->toUrl('canonical', ['language' => $group->language()]);
$variables['attributes']['class'][] = 'group';
$variables['attributes']['class'][] = Html::cleanCssIdentifier('group--' . $variables['view_mode']);
$variables['attributes']['class'][] = Html::cleanCssIdentifier('group--' . $variables['group']->bundle());
// See if we are rendering the group at its canonical route.
$route_match = \Drupal::routeMatch();
if ($route_match->getRouteName() == 'entity.group.canonical') {
$page_group = $route_match->getParameter('group');
// Set variables that depend on the group being saved.
$variables['url'] = '';
$variables['page'] = FALSE;
if (!$group->isNew()) {
$variables['url'] = $group->toUrl('canonical', ['language' => $group->language()]);
// See if we are rendering the group at its canonical route.
$route_match = \Drupal::routeMatch();
if ($route_match->getRouteName() == 'entity.group.canonical') {
$page_group = $route_match->getParameter('group');
}
$is_page = !empty($page_group) && $page_group->id() == $group->id();
$variables['page'] = $variables['view_mode'] == 'full' && $is_page;
}
$is_page = (!empty($page_group) ? $page_group->id() == $group->id() : FALSE);
$variables['page'] = $variables['view_mode'] == 'full' && $is_page;
// Helpful $content variable for templates.
$variables += ['content' => []];
......@@ -206,18 +215,18 @@ function template_preprocess_group(&$variables) {
/**
* Prepares variables for the group relationship template.
*
* Default template: group-content.html.twig
* Default template: group-relationship.html.twig.
*
* @param array $variables
* - elements: An array of elements to display in view mode.
* - group_content: The group relationship object.
* - group_relationship: The group relationship object.
* - view_mode: View mode; e.g., 'full', 'teaser', etc.
*/
function template_preprocess_group_content(&$variables) {
$group_relationship = $variables['elements']['#group_content'];
function template_preprocess_group_relationship(&$variables) {
$group_relationship = $variables['elements']['#group_relationship'];
assert($group_relationship instanceof GroupRelationshipInterface);
$variables['group_content'] = $group_relationship;
$variables['group_relationship'] = $group_relationship;
$variables['view_mode'] = $variables['elements']['#view_mode'];
$variables['label'] = $group_relationship->label();
$variables['url'] = $group_relationship->toUrl('canonical', ['language' => $group_relationship->language()]);
......@@ -227,8 +236,8 @@ function template_preprocess_group_content(&$variables) {
// See if we are rendering the group at its canonical route.
$route_match = \Drupal::routeMatch();
if ($route_match->getRouteName() == 'entity.group_content.canonical') {
$page_group_relationship = $route_match->getParameter('group_content');
if ($route_match->getRouteName() == 'entity.group_relationship.canonical') {
$page_group_relationship = $route_match->getParameter('group_relationship');
}
$is_page = (!empty($page_group_relationship) ? $page_group_relationship->id() == $group_relationship->id() : FALSE);
$variables['page'] = $variables['view_mode'] == 'full' && $is_page;
......@@ -259,10 +268,6 @@ function group_modules_installed($modules) {
/**
* Implements hook_form_FORM_ID_alter().
*
* @param array $form
* @param \Drupal\Core\Form\FormStateInterface $form_state
* @param string $form_id
*/
function group_form_block_form_alter(&$form, FormStateInterface $form_state, $form_id) {
if (isset($form['visibility']['group_type'])) {
......@@ -290,7 +295,11 @@ function group_module_implements_alter(&$implementations, $hook) {
/**
* Implements hook_query_TAG_alter().
*/
function group_query_entity_query_alter(SelectInterface $query) {
function group_query_entity_query_alter(AlterableInterface $query) {
if (!$query instanceof SelectInterface) {
return;
}
$entity_type_id = $query->getMetaData('entity_type');
if ($query->hasTag($entity_type_id . '_access')) {
$entity_type_manager = \Drupal::entityTypeManager();
......@@ -311,7 +320,7 @@ function group_query_entity_query_alter(SelectInterface $query) {
$class_name = GroupQueryAlter::class;
break;
case 'group_content':
case 'group_relationship':
$class_name = GroupRelationshipQueryAlter::class;
break;
......@@ -328,7 +337,11 @@ function group_query_entity_query_alter(SelectInterface $query) {
/**
* Implements hook_query_TAG_alter().
*/
function group_query_views_entity_query_alter(SelectInterface $query) {
function group_query_views_entity_query_alter(AlterableInterface $query) {
if (!$query instanceof SelectInterface) {
return;
}
$entity_type_id = $query->getMetaData('entity_type');
$query->addTag($entity_type_id . '_access');
group_query_entity_query_alter($query);
......@@ -338,27 +351,29 @@ function group_query_views_entity_query_alter(SelectInterface $query) {
* Implements hook_views_query_alter().
*/
function group_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
if ($query instanceof Sql && empty($query->options['disable_sql_rewrite'])) {
$table_info = $query->getEntityTableInfo();
$base_table = reset($table_info);
if (empty($base_table['entity_type']) || $base_table['relationship_id'] != 'none') {
return;
}
if (!$query instanceof Sql || !empty($query->options['disable_sql_rewrite'])) {
return;
}
// Add a custom tag so we don't trigger all other 'entity_query' tag alters.
$entity_type_id = $base_table['entity_type'];
$query->addTag('views_entity_query');
$table_info = $query->getEntityTableInfo();
$base_table = reset($table_info);
if (empty($base_table['entity_type']) || $base_table['relationship_id'] != 'none') {
return;
}
// Build the Views query already so we can access the DB query.
$query->build($view);
$view->built = TRUE;
// Add a custom tag so we don't trigger all other 'entity_query' tag alters.
$entity_type_id = $base_table['entity_type'];
$query->addTag('views_entity_query');
// Add metadata to the DB query.
$query = $view->build_info['query'];
$count_query = $view->build_info['count_query'];
$query->addMetaData('entity_type', $entity_type_id);
$count_query->addMetaData('entity_type', $entity_type_id);
}
// Build the Views query already so we can access the DB query.
$query->build($view);
$view->built = TRUE;
// Add metadata to the DB query.
$query = $view->build_info['query'];
$count_query = $view->build_info['count_query'];
$query->addMetaData('entity_type', $entity_type_id);
$count_query->addMetaData('entity_type', $entity_type_id);
}
/**
......@@ -385,7 +400,7 @@ function group_entity_access(EntityInterface $entity, $operation, AccountInterfa
// plugins, it might change access.
$plugin_cache_tags = [];
foreach ($plugin_ids as $plugin_id) {
$plugin_cache_tags[] = "group_content_list:plugin:$plugin_id";
$plugin_cache_tags[] = "group_relationship_list:plugin:$plugin_id";
}
$access = AccessResult::neutral()->addCacheTags($plugin_cache_tags);
......@@ -401,7 +416,7 @@ function group_entity_access(EntityInterface $entity, $operation, AccountInterfa
// Reduce the plugin IDs to those that are actually in use.
$data_table = \Drupal::entityTypeManager()
->getDefinition('group_content')
->getDefinition('group_relationship')
->getDataTable();
$plugin_ids_used = \Drupal::database()
......@@ -431,7 +446,7 @@ function group_entity_access(EntityInterface $entity, $operation, AccountInterfa
* Implements hook_entity_delete().
*/
function group_entity_delete(EntityInterface $entity) {
$storage = \Drupal::entityTypeManager()->getStorage('group_content');
$storage = \Drupal::entityTypeManager()->getStorage('group_relationship');
assert($storage instanceof GroupRelationshipStorageInterface);
// See if any relationships exist for the entity and delete them as well.
......@@ -459,7 +474,7 @@ function group_entity_delete(EntityInterface $entity) {
* @todo Move this to a form controller so we can hide the field if it has no
* options available to it?
*/
function group_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
function group_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, ?FieldItemListInterface $items = NULL) {
// Can't retrieve an entity from an empty item list.
if (!isset($items)) {
return AccessResult::neutral();
......@@ -471,7 +486,7 @@ function group_entity_field_access($operation, FieldDefinitionInterface $field_d
}
// We only care if it is attached to a relationship type entity.
if ($items->getEntity()->getEntityTypeId() != 'group_content') {
if ($items->getEntity()->getEntityTypeId() != 'group_relationship') {
return AccessResult::neutral();
}
......@@ -637,13 +652,13 @@ function group_form_alter(&$form, FormStateInterface $form_state, $form_id) {
if ($wizard) {
foreach ($submit as $key => $handler) {
if ($handler == '::save') {
$form['actions'][$name]['#submit'][$key] = 'group_content_wizard_store';
$form['actions'][$name]['#submit'][$key] = 'group_relationship_wizard_store';
}
}
}
// Otherwise, we can simply add our submit handler and be done with it.
else {
$form['actions'][$name]['#submit'][] = 'group_content_entity_submit';
$form['actions'][$name]['#submit'][] = 'group_relationship_entity_submit';
}
}
......@@ -652,7 +667,7 @@ function group_form_alter(&$form, FormStateInterface $form_state, $form_id) {
$form['actions']['cancel'] = [
'#type' => 'submit',
'#value' => t('Cancel'),
'#submit' => ['group_content_wizard_cancel'],
'#submit' => ['group_relationship_wizard_cancel'],
'#limit_validation_errors' => [],
];
}
......@@ -665,13 +680,14 @@ function group_form_alter(&$form, FormStateInterface $form_state, $form_id) {
* @see group_form_alter()
* @see \Drupal\group\Entity\Controller\GroupRelationshipController::createForm()
*/
function group_content_wizard_store($form, FormStateInterface $form_state) {
$entity = $form_state->getFormObject()->getEntity();
function group_relationship_wizard_store($form, FormStateInterface $form_state) {
$form_object = $form_state->getFormObject();
assert($form_object instanceof EntityFormInterface);
// Store the unsaved entity in the temp store.
$store = \Drupal::service('tempstore.private')->get($form_state->get('group_wizard_id'));
$store_id = $form_state->get('store_id');
$store->set("$store_id:entity", $entity);
$store->set("$store_id:entity", $form_object->getEntity());
$store->set("$store_id:step", 2);
// Disable any URL-based redirect until the final step.
......@@ -686,7 +702,7 @@ function group_content_wizard_store($form, FormStateInterface $form_state) {
* @see group_form_alter()
* @see \Drupal\group\Entity\Controller\GroupRelationshipController::createForm()
*/
function group_content_wizard_cancel($form, FormStateInterface $form_state) {
function group_relationship_wizard_cancel($form, FormStateInterface $form_state) {
$store = \Drupal::service('tempstore.private')->get($form_state->get('group_wizard_id'));
$store_id = $form_state->get('store_id');
$store->delete("$store_id:entity");
......@@ -705,8 +721,11 @@ function group_content_wizard_cancel($form, FormStateInterface $form_state) {
* @see group_form_alter()
* @see \Drupal\group\Entity\Controller\GroupRelationshipController::createForm()
*/
function group_content_entity_submit($form, FormStateInterface $form_state) {
$entity = $form_state->getFormObject()->getEntity();
function group_relationship_entity_submit($form, FormStateInterface $form_state) {
$form_object = $form_state->getFormObject();
assert($form_object instanceof EntityFormInterface);
$entity = $form_object->getEntity();
$group = $form_state->get('group');
assert($group instanceof GroupInterface);
$group->addRelationship($entity, $form_state->get('group_relation'));
......
......@@ -82,26 +82,26 @@ entity.group_role.permissions_form:
# todo This route needs a requirement which only allows access if the plugin
# isn't installed on the group type yet.
entity.group_content_type.add_form:
entity.group_relationship_type.add_form:
path: '/admin/group/content/install/{group_type}/{plugin_id}'
defaults:
_entity_form: 'group_content_type.add'
_entity_form: 'group_relationship_type.add'
_title: 'Install content plugin'
requirements:
_permission: 'administer group'
entity.group_content_type.edit_form:
path: '/admin/group/content/manage/{group_content_type}'
entity.group_relationship_type.edit_form:
path: '/admin/group/content/manage/{group_relationship_type}'
defaults:
_entity_form: 'group_content_type.edit'
_entity_form: 'group_relationship_type.edit'
_title: 'Configure content plugin'
requirements:
_permission: 'administer group'
entity.group_content_type.delete_form:
path: '/admin/group/content/manage/{group_content_type}/uninstall'
entity.group_relationship_type.delete_form:
path: '/admin/group/content/manage/{group_relationship_type}/uninstall'
defaults:
_entity_form: 'group_content_type.delete'
_entity_form: 'group_relationship_type.delete'
_title: 'Uninstall content plugin'
requirements:
_permission: 'administer group'
......@@ -15,24 +15,24 @@ services:
class: 'Drupal\group\Access\GroupOwnsContentAccessCheck'
tags:
- { name: 'access_check', applies_to: '_group_owns_content' }
access_check.group_content.create:
access_check.group_relationship.create:
class: 'Drupal\group\Access\GroupRelationshipCreateAccessCheck'
arguments: ['@entity_type.manager']
tags:
- { name: 'access_check', applies_to: '_group_content_create_access' }
access_check.group_content.create_any:
- { name: 'access_check', applies_to: '_group_relationship_create_access' }
access_check.group_relationship.create_any:
class: 'Drupal\group\Access\GroupRelationshipCreateAnyAccessCheck'
arguments: ['@entity_type.manager']
tags:
- { name: 'access_check', applies_to: '_group_content_create_any_access' }
access_check.group_content.create_entity:
- { name: 'access_check', applies_to: '_group_relationship_create_any_access' }
access_check.group_relationship.create_entity:
class: 'Drupal\group\Access\GroupRelationshipCreateEntityAccessCheck'
tags:
- { name: 'access_check', applies_to: '_group_content_create_entity_access' }
access_check.group_content.create_any_entity:
- { name: 'access_check', applies_to: '_group_relationship_create_entity_access' }
access_check.group_relationship.create_any_entity:
class: 'Drupal\group\Access\GroupRelationshipCreateAnyEntityAccessCheck'
tags:
- { name: 'access_check', applies_to: '_group_content_create_any_entity_access' }
- { name: 'access_check', applies_to: '_group_relationship_create_any_entity_access' }
access_check.group_latest_revision:
class: 'Drupal\group\Entity\Access\GroupLatestRevisionCheck'
arguments: ['@entity_type.manager']
......@@ -41,6 +41,26 @@ services:
tags:
- { name: 'access_check', applies_to: '_group_latest_revision' }
cache.group_memberships_memory:
class: 'Drupal\Core\Cache\MemoryCache\MemoryCacheInterface'
tags:
- { name: 'cache.bin.memory', default_backend: 'cache.backend.memory.memory' }
factory: ['@cache_factory', 'get']
arguments: ['group_memberships_memory']
cache.group_memberships:
class: 'Drupal\Core\Cache\CacheBackendInterface'
tags:
- { name: 'cache.bin' }
factory: ['@cache_factory', 'get']
arguments: ['group_memberships']
cache.group_memberships_chained:
class: 'Drupal\Core\Cache\BackendChain'
calls:
- ['appendBackend', ['@cache.group_memberships_memory']]
- ['appendBackend', ['@cache.group_memberships']]
tags:
- { name: 'cache.bin.memory' }
cache_context.route.group:
class: 'Drupal\group\Cache\Context\RouteGroupCacheContext'
arguments: ['@current_route_match', '@entity_type.manager']
......@@ -62,6 +82,11 @@ services:
arguments: ['@config.factory']
tags:
- { name: 'event_subscriber' }
group.anonymous_user_response_subscriber:
class: 'Drupal\group\EventSubscriber\AnonymousUserResponseSubscriber'
arguments: ['@current_user', '@group_permission.calculator']
tags:
- { name: 'event_subscriber' }
group.latest_revision.route_subscriber:
class: 'Drupal\group\Entity\Routing\GroupLatestRevisionRouteSubscriber'
tags:
......@@ -86,11 +111,11 @@ services:
arguments: ['@entity_type.manager', '@current_user']
group.permissions:
class: 'Drupal\group\Access\GroupPermissionHandler'
arguments: ['@module_handler', '@string_translation', '@controller_resolver', '@group_relation_type.manager']
arguments: ['@module_handler', '@string_translation', '@controller_resolver', '@group_relation_type.manager', '@extension.list.module']
group_permission.hash_generator:
class: 'Drupal\group\Access\GroupPermissionsHashGenerator'
arguments: ['@private_key', '@cache.static', '@group_permission.calculator']
arguments: ['@private_key', '@cache.static', '@group_permission.calculator', '@entity_type.manager', '@database']
# Wrappers for Flexible permissions services.
group_permission.calculator:
......@@ -112,14 +137,14 @@ services:
tags:
- { name: flexible_permission_calculator, priority: -50 }
group.uninstall_validator.group_content:
group.uninstall_validator.group_relationship:
class: 'Drupal\group\UninstallValidator\GroupRelationshipUninstallValidator'
tags:
- { name: 'module_install.uninstall_validator' }
arguments: ['@string_translation', '@entity_type.manager', '@group_relation_type.manager']
lazy: 'true'
group_content_type.breadcrumb:
group_relationship_type.breadcrumb:
class: 'Drupal\group\Breadcrumb\GroupRelationshipTypeBreadcrumbBuilder'
tags:
- { name: 'breadcrumb_builder', priority: 100 }
......@@ -127,7 +152,6 @@ services:
group_relation_type.manager:
class: 'Drupal\group\Plugin\Group\Relation\GroupRelationTypeManager'
arguments: ['@container.namespaces', '@cache.discovery', '@module_handler', '@entity_type.manager']
parent: container.trait
tags:
- { name: plugin_manager_cache_clear }
......@@ -156,19 +180,18 @@ services:
shared: false
# Specific group relation handlers.
group.relation_handler.access_control.group_membership:
class: 'Drupal\group\Plugin\Group\RelationHandler\GroupMembershipAccessControl'
arguments: ['@group.relation_handler.access_control']
group.relation_handler.entity_reference.group_membership:
class: 'Drupal\group\Plugin\Group\RelationHandler\GroupMembershipEntityReference'
arguments: ['@group.relation_handler.entity_reference']
shared: false
group.relation_handler.operation_provider.group_membership:
class: 'Drupal\group\Plugin\Group\RelationHandler\GroupMembershipOperationProvider'
arguments: ['@group.relation_handler.operation_provider', '@current_user', '@string_translation']
shared: false
group.relation_handler.permission_provider.group_membership:
class: 'Drupal\group\Plugin\Group\RelationHandler\GroupMembershipPermissionProvider'
arguments: ['@group.relation_handler.permission_provider']
shared: false
group.relation_handler.post_install.group_membership:
class: 'Drupal\group\Plugin\Group\RelationHandler\GroupMembershipPostInstall'
arguments: ['@group.relation_handler.post_install', '@entity_type.manager', '@string_translation']
shared: false
......@@ -76,49 +76,49 @@ function group_token_info() {
'type' => 'user',
];
$types['group_content'] = [
$types['group_relationship'] = [
'name' => t('Group relationship'),
'description' => t('Tokens related to the relationships between a group and its content.'),
'needs-data' => 'group_content',
'needs-data' => 'group_relationship',
];
$tokens['group_content']['id'] = [
$tokens['group_relationship']['id'] = [
'name' => t('Group relationship ID'),
'description' => t('The unique ID of the group relationship.'),
];
$tokens['group_content']['langcode'] = [
$tokens['group_relationship']['langcode'] = [
'name' => t('Language code'),
'description' => t('The language code of the language the group relationship is in.'),
];
$tokens['group_content']['url'] = [
$tokens['group_relationship']['url'] = [
'name' => t('URL'),
'description' => t('The URL of the group relationship.'),
];
$tokens['group_content']['edit-url'] = [
$tokens['group_relationship']['edit-url'] = [
'name' => t('Edit URL'),
'description' => t("The URL of the group's edit page."),
];
$tokens['group_content']['created'] = [
$tokens['group_relationship']['created'] = [
'name' => t('Date created'),
'type' => 'date',
];
$tokens['group_content']['changed'] = [
$tokens['group_relationship']['changed'] = [
'name' => t('Date changed'),
'description' => t('The date the group relationship was most recently updated.'),
'type' => 'date',
];
$tokens['group_content']['group'] = [
$tokens['group_relationship']['group'] = [
'name' => t('Group'),
'type' => 'group',
];
$tokens['group_content']['pretty-path-key'] = [
$tokens['group_relationship']['pretty-path-key'] = [
'name' => t('Pretty path key'),
'description' => t('A prettier way of labeling group relationship of the same relation type.'),
];
......@@ -214,8 +214,8 @@ function group_tokens($type, $tokens, array $data, array $options, BubbleableMet
$replacements += $token_service->generate('date', $changed_tokens, ['date' => $group->getChangedTime()], $options, $bubbleable_metadata);
}
}
elseif ($type == 'group_content' && !empty($data[$type])) {
$group_relationship = $data['group_content'];
elseif ($type == 'group_relationship' && !empty($data[$type])) {
$group_relationship = $data['group_relationship'];
assert($group_relationship instanceof GroupRelationshipInterface);
foreach ($tokens as $name => $original) {
......
......@@ -16,7 +16,7 @@ function group_views_data_alter(array &$data) {
$entity_types = $entity_type_manager->getDefinitions();
// Get the data table for GroupRelationship entities.
$data_table = $entity_types['group_content']->getDataTable();
$data_table = $entity_types['group_relationship']->getDataTable();
$plugin_manager = \Drupal::service('group_relation_type.manager');
assert($plugin_manager instanceof GroupRelationTypeManagerInterface);
......@@ -32,8 +32,8 @@ function group_views_data_alter(array &$data) {
$entity_type = $entity_types[$entity_type_id];
$entity_data_table = $entity_type->getDataTable() ?: $entity_type->getBaseTable();
// We only add one 'group_content' entry per entity type.
if (isset($data[$entity_data_table]['group_content'])) {
// We only add one 'group_relationship' entry per entity type.
if (isset($data[$entity_data_table]['group_relationship'])) {
continue;
}
......@@ -43,7 +43,7 @@ function group_views_data_alter(array &$data) {
// This relationship will allow a content entity to easily map to the group
// content entity that ties it to a group, optionally filtering by plugin.
$data[$entity_data_table]['group_content'] = [
$data[$entity_data_table]['group_relationship'] = [
'title' => t('Group relationship for @entity_type', $t_args),
'help' => t('Relates to the group relationship entities that represent the @entity_type.', $t_args),
'relationship' => [
......@@ -51,7 +51,7 @@ function group_views_data_alter(array &$data) {
'base' => $data_table,
'base field' => 'entity_id',
'relationship field' => $entity_type->getKey('id'),
'id' => 'group_content_to_entity_reverse',
'id' => 'group_relationship_to_entity_reverse',
'label' => t('@entity_type group relationship', $t_args),
],
];
......