Drupal 8.0.0 beta 12. More info: https://www.drupal.org/node/2514176
This commit is contained in:
commit
9921556621
13277 changed files with 1459781 additions and 0 deletions
46
core/modules/views/config/install/views.settings.yml
Normal file
46
core/modules/views/config/install/views.settings.yml
Normal file
|
@ -0,0 +1,46 @@
|
|||
display_extenders: { }
|
||||
skip_cache: false
|
||||
sql_signature: false
|
||||
ui:
|
||||
show:
|
||||
additional_queries: false
|
||||
advanced_column: false
|
||||
master_display: false
|
||||
performance_statistics: false
|
||||
preview_information: true
|
||||
sql_query:
|
||||
enabled: false
|
||||
where: above
|
||||
display_embed: false
|
||||
always_live_preview: true
|
||||
exposed_filter_any_label: old_any
|
||||
field_rewrite_elements:
|
||||
div: DIV
|
||||
span: SPAN
|
||||
h1: H1
|
||||
h2: H2
|
||||
h3: H3
|
||||
h4: H4
|
||||
h5: H5
|
||||
h6: H6
|
||||
p: P
|
||||
header: HEADER
|
||||
footer: FOOTER
|
||||
article: ARTICLE
|
||||
section: SECTION
|
||||
aside: ASIDE
|
||||
details: DETAILS
|
||||
blockquote: BLOCKQUOTE
|
||||
figure: FIGURE
|
||||
address: ADDRESS
|
||||
code: CODE
|
||||
pre: PRE
|
||||
var: VAR
|
||||
samp: SAMP
|
||||
kbd: KBD
|
||||
strong: STRONG
|
||||
em: EM
|
||||
del: DEL
|
||||
ins: INS
|
||||
q: Q
|
||||
s: S
|
5
core/modules/views/config/schema/views.access.schema.yml
Normal file
5
core/modules/views/config/schema/views.access.schema.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Schema for the views access plugins.
|
||||
|
||||
views.access.none:
|
||||
type: mapping
|
||||
label: 'None'
|
80
core/modules/views/config/schema/views.area.schema.yml
Normal file
80
core/modules/views/config/schema/views.area.schema.yml
Normal file
|
@ -0,0 +1,80 @@
|
|||
# Schema for the views area plugins.
|
||||
|
||||
views.area.*:
|
||||
type: views_area
|
||||
label: 'Default area'
|
||||
|
||||
views.area.entity:
|
||||
type: views_area
|
||||
label: 'Entity'
|
||||
mapping:
|
||||
target:
|
||||
type: string
|
||||
label: 'The target entity'
|
||||
view_mode:
|
||||
type: string
|
||||
label: 'View mode'
|
||||
tokenize:
|
||||
type: boolean
|
||||
label: 'Should replacement tokens be used from the first row'
|
||||
bypass_access:
|
||||
type: boolean
|
||||
label: 'Bypass access checks'
|
||||
|
||||
views.area.text:
|
||||
type: views_area
|
||||
label: 'Text'
|
||||
mapping:
|
||||
content:
|
||||
type: text_format
|
||||
label: 'The formatted text of the area'
|
||||
tokenize:
|
||||
type: boolean
|
||||
label: 'Should replacement tokens be used from the first row'
|
||||
|
||||
views.area.text_custom:
|
||||
type: views_area
|
||||
label: 'Text custom'
|
||||
mapping:
|
||||
content:
|
||||
type: text
|
||||
label: 'The shown text of the area'
|
||||
tokenize:
|
||||
type: boolean
|
||||
label: 'Should replacement tokens be used from the first row'
|
||||
|
||||
views.area.result:
|
||||
type: views_area
|
||||
label: 'Result'
|
||||
mapping:
|
||||
content:
|
||||
type: text
|
||||
label: 'The shown text of the result summary area'
|
||||
|
||||
views.area.title:
|
||||
type: views_area
|
||||
label: 'Title'
|
||||
mapping:
|
||||
title:
|
||||
type: label
|
||||
label: 'The title which will be overridden for the page'
|
||||
|
||||
views.area.view:
|
||||
type: views_area
|
||||
label: 'View'
|
||||
mapping:
|
||||
view_to_insert:
|
||||
type: string
|
||||
label: 'View to insert'
|
||||
inherit_arguments:
|
||||
type: boolean
|
||||
label: 'Inherit contextual filters'
|
||||
|
||||
views.area.http_status_code:
|
||||
type: views_area
|
||||
label: 'HTTP status code'
|
||||
mapping:
|
||||
status_code:
|
||||
type: integer
|
||||
label: 'HTTP status code'
|
||||
|
152
core/modules/views/config/schema/views.argument.schema.yml
Normal file
152
core/modules/views/config/schema/views.argument.schema.yml
Normal file
|
@ -0,0 +1,152 @@
|
|||
# Schema for the views argument plugins.
|
||||
|
||||
views.argument.*:
|
||||
type: views_argument
|
||||
label: 'Default argument'
|
||||
|
||||
views.argument.many_to_one:
|
||||
type: views_argument
|
||||
label: 'Many to one'
|
||||
mapping:
|
||||
break_phrase:
|
||||
type: boolean
|
||||
label: 'Allow multiple values'
|
||||
add_table:
|
||||
type: boolean
|
||||
label: 'Allow multiple filter values to work together'
|
||||
require_value:
|
||||
type: boolean
|
||||
label: 'Do not display items with no value in summary'
|
||||
reduce_duplicates:
|
||||
type: boolean
|
||||
label: 'Reduce duplicates'
|
||||
|
||||
views.argument.null:
|
||||
type: views_argument
|
||||
label: 'Null'
|
||||
mapping:
|
||||
must_not_be:
|
||||
type: boolean
|
||||
label: 'Fail basic validation if any argument is given'
|
||||
|
||||
views.argument.numeric:
|
||||
type: views_argument
|
||||
label: 'Numeric'
|
||||
mapping:
|
||||
break_phrase:
|
||||
type: boolean
|
||||
label: 'Allow multiple values'
|
||||
not:
|
||||
type: boolean
|
||||
label: 'Exclude'
|
||||
|
||||
views.argument.string:
|
||||
type: views_argument
|
||||
label: 'String'
|
||||
mapping:
|
||||
glossary:
|
||||
type: boolean
|
||||
label: 'Glossary mode'
|
||||
limit:
|
||||
type: integer
|
||||
label: 'Character limit'
|
||||
case:
|
||||
type: string
|
||||
label: 'Case'
|
||||
path_case:
|
||||
type: string
|
||||
label: 'Case in path'
|
||||
transform_dash:
|
||||
type: boolean
|
||||
label: 'Transform spaces to dashes in URL'
|
||||
break_phrase:
|
||||
type: boolean
|
||||
label: 'Allow multiple values'
|
||||
add_table:
|
||||
type: boolean
|
||||
label: 'Allow multiple filter values to work together'
|
||||
require_value:
|
||||
type: boolean
|
||||
label: 'Do not display items with no value in summary'
|
||||
|
||||
|
||||
views.argument.broken:
|
||||
type: views_argument
|
||||
label: 'Broken'
|
||||
|
||||
views.argument.date:
|
||||
type: views_argument
|
||||
label: 'Date'
|
||||
mapping:
|
||||
date:
|
||||
type: string
|
||||
label: 'Date'
|
||||
node_created:
|
||||
type: string
|
||||
label: 'Node Creation Time'
|
||||
node_changed:
|
||||
type: string
|
||||
label: 'Node Update Time'
|
||||
|
||||
views.argument.date_day:
|
||||
type: views.argument.date
|
||||
label: 'Day Date'
|
||||
mapping:
|
||||
day:
|
||||
type: string
|
||||
label: 'Day'
|
||||
|
||||
views.argument.formula:
|
||||
type: views_argument
|
||||
label: 'Formula'
|
||||
mapping:
|
||||
placeholder:
|
||||
type: string
|
||||
label: 'Place Holder'
|
||||
formula:
|
||||
type: string
|
||||
label: 'Formula Used'
|
||||
|
||||
views.argument.date_fulldate:
|
||||
type: views.argument.date
|
||||
label: 'Full Date'
|
||||
mapping:
|
||||
created:
|
||||
type: string
|
||||
label: 'Full Date'
|
||||
|
||||
views.argument.groupby_numeric:
|
||||
type: views_argument
|
||||
label: 'Group by Numeric'
|
||||
|
||||
views.argument.date_month:
|
||||
type: views.argument.date
|
||||
label: 'Month Date'
|
||||
mapping:
|
||||
month:
|
||||
type: string
|
||||
label: 'Month'
|
||||
|
||||
views.argument.standard:
|
||||
type: views_argument
|
||||
label: 'Standard'
|
||||
|
||||
views.argument.date_week:
|
||||
type: views.argument.date
|
||||
label: 'Week Date'
|
||||
|
||||
views.argument.date_year:
|
||||
type: views.argument.date
|
||||
label: 'Year Date'
|
||||
|
||||
views.argument.date_year_month:
|
||||
type: views.argument.date
|
||||
label: 'YearMonthDate'
|
||||
mapping:
|
||||
created:
|
||||
type: string
|
||||
label: 'Date Year month'
|
||||
|
||||
views.argument.language:
|
||||
type: views_argument
|
||||
label: 'Language'
|
|
@ -0,0 +1,28 @@
|
|||
# Schema for the views default arguments.
|
||||
|
||||
views.argument_default.fixed:
|
||||
type: mapping
|
||||
label: 'Fixed'
|
||||
mapping:
|
||||
argument:
|
||||
type: string
|
||||
label: 'Fixed value'
|
||||
|
||||
views.argument_default.php:
|
||||
type: mapping
|
||||
label: 'PHP Code'
|
||||
mapping:
|
||||
code:
|
||||
type: string
|
||||
label: 'PHP contextual filter code'
|
||||
|
||||
views.argument_default.raw:
|
||||
type: mapping
|
||||
label: 'Raw value from URL'
|
||||
mapping:
|
||||
index:
|
||||
type: integer
|
||||
label: 'Path component'
|
||||
use_alias:
|
||||
type: boolean
|
||||
label: 'Use path alias'
|
|
@ -0,0 +1,38 @@
|
|||
# Schema for the views argument validators.
|
||||
|
||||
views.argument_validator.none:
|
||||
type: sequence
|
||||
label: 'Basic validation'
|
||||
sequence:
|
||||
type: string
|
||||
|
||||
views.argument_validator.php:
|
||||
type: mapping
|
||||
label: 'PHP Code'
|
||||
mapping:
|
||||
code:
|
||||
type: string
|
||||
label: 'PHP validate code'
|
||||
|
||||
views.argument_validator.numeric:
|
||||
type: boolean
|
||||
label: 'Numeric'
|
||||
|
||||
views.argument_validator_entity:
|
||||
type: mapping
|
||||
mapping:
|
||||
bundles:
|
||||
type: sequence
|
||||
label: 'Bundles'
|
||||
sequence:
|
||||
type: string
|
||||
label: 'Bundle'
|
||||
access:
|
||||
type: boolean
|
||||
label: 'Access'
|
||||
operation:
|
||||
type: string
|
||||
label: 'Access operation to check'
|
||||
multiple:
|
||||
type: integer
|
||||
label: 'Multiple arguments'
|
38
core/modules/views/config/schema/views.cache.schema.yml
Normal file
38
core/modules/views/config/schema/views.cache.schema.yml
Normal file
|
@ -0,0 +1,38 @@
|
|||
# Schema for the views cache.
|
||||
|
||||
views.cache.none:
|
||||
type: views_cache
|
||||
label: 'No caching'
|
||||
mapping:
|
||||
options:
|
||||
type: sequence
|
||||
label: 'Options'
|
||||
|
||||
views.cache.tag:
|
||||
type: views_cache
|
||||
label: 'Tag based caching'
|
||||
mapping:
|
||||
options:
|
||||
type: sequence
|
||||
label: 'Options'
|
||||
|
||||
views.cache.time:
|
||||
type: views_cache
|
||||
label: 'Time based caching'
|
||||
mapping:
|
||||
options:
|
||||
type: mapping
|
||||
label: 'Cache options'
|
||||
mapping:
|
||||
results_lifespan:
|
||||
type: integer
|
||||
label: 'The length of time raw query results should be cached.'
|
||||
results_lifespan_custom:
|
||||
type: integer
|
||||
label: 'Length of time in seconds raw query results should be cached.'
|
||||
output_lifespan:
|
||||
type: integer
|
||||
label: 'The length of time rendered HTML output should be cached.'
|
||||
output_lifespan_custom:
|
||||
type: integer
|
||||
label: 'Length of time in seconds rendered HTML output should be cached.'
|
822
core/modules/views/config/schema/views.data_types.schema.yml
Normal file
822
core/modules/views/config/schema/views.data_types.schema.yml
Normal file
|
@ -0,0 +1,822 @@
|
|||
# Basic data types for views.
|
||||
|
||||
views_display:
|
||||
type: mapping
|
||||
label: 'Display options'
|
||||
mapping:
|
||||
enabled:
|
||||
type: boolean
|
||||
label: 'Status'
|
||||
title:
|
||||
type: text
|
||||
label: 'Display title'
|
||||
format:
|
||||
type: string
|
||||
label: 'Format'
|
||||
fields:
|
||||
type: sequence
|
||||
label: 'Fields'
|
||||
sequence:
|
||||
type: views.field.[plugin_id]
|
||||
pager:
|
||||
type: mapping
|
||||
label: 'Pager'
|
||||
mapping:
|
||||
type:
|
||||
type: string
|
||||
label: 'Pager type'
|
||||
options:
|
||||
type: views.pager.[%parent.type]
|
||||
exposed_form:
|
||||
type: mapping
|
||||
label: 'Exposed form'
|
||||
mapping:
|
||||
type:
|
||||
type: string
|
||||
label: 'Exposed form type'
|
||||
options:
|
||||
label: 'Options'
|
||||
type: views.exposed_form.[%parent.type]
|
||||
access:
|
||||
type: mapping
|
||||
label: 'Access'
|
||||
mapping:
|
||||
type:
|
||||
type: string
|
||||
label: 'Access type'
|
||||
options:
|
||||
type: views.access.[%parent.type]
|
||||
cache:
|
||||
type: views.cache.[type]
|
||||
empty:
|
||||
type: sequence
|
||||
label: 'No results behavior'
|
||||
sequence:
|
||||
type: views.area.[plugin_id]
|
||||
sorts:
|
||||
type: sequence
|
||||
label: 'Sorts'
|
||||
sequence:
|
||||
type: views.sort.[plugin_id]
|
||||
arguments:
|
||||
type: sequence
|
||||
label: 'Arguments'
|
||||
sequence:
|
||||
type: views.argument.[plugin_id]
|
||||
filters:
|
||||
type: sequence
|
||||
label: 'Filters'
|
||||
sequence:
|
||||
type: views.filter.[plugin_id]
|
||||
filter_groups:
|
||||
type: mapping
|
||||
label: 'Groups'
|
||||
mapping:
|
||||
operator:
|
||||
type: string
|
||||
label: 'Operator'
|
||||
groups:
|
||||
type: sequence
|
||||
label: 'Groups'
|
||||
sequence:
|
||||
type: string
|
||||
label: 'Operator'
|
||||
style:
|
||||
type: mapping
|
||||
label: 'Format'
|
||||
mapping:
|
||||
type:
|
||||
type: string
|
||||
label: 'Type'
|
||||
options:
|
||||
type: views.style.[%parent.type]
|
||||
row:
|
||||
type: mapping
|
||||
label: 'Row'
|
||||
mapping:
|
||||
type:
|
||||
type: string
|
||||
label: 'Row type'
|
||||
options:
|
||||
type: views.row.[%parent.type]
|
||||
query:
|
||||
type: mapping
|
||||
label: 'Query'
|
||||
mapping:
|
||||
type:
|
||||
type: string
|
||||
label: 'Query type'
|
||||
options:
|
||||
type: views.query.[%parent.type]
|
||||
defaults:
|
||||
type: mapping
|
||||
label: 'Defaults'
|
||||
mapping:
|
||||
empty:
|
||||
type: boolean
|
||||
label: 'Empty'
|
||||
access:
|
||||
type: boolean
|
||||
label: 'Access restrictions'
|
||||
cache:
|
||||
type: boolean
|
||||
label: 'Caching'
|
||||
query:
|
||||
type: boolean
|
||||
label: 'Query options'
|
||||
title:
|
||||
type: boolean
|
||||
label: 'Title'
|
||||
css_class:
|
||||
type: boolean
|
||||
label: 'CSS class'
|
||||
display_description:
|
||||
type: boolean
|
||||
label: 'Administrative description'
|
||||
use_ajax:
|
||||
type: boolean
|
||||
label: 'Use AJAX'
|
||||
hide_attachment_summary:
|
||||
type: boolean
|
||||
label: 'Hide attachments when displaying a contextual filter summary'
|
||||
show_admin_links:
|
||||
type: boolean
|
||||
label: 'Show contextual links'
|
||||
pager:
|
||||
type: boolean
|
||||
label: 'Use pager'
|
||||
use_more:
|
||||
type: boolean
|
||||
label: 'Create more link'
|
||||
use_more_always:
|
||||
type: boolean
|
||||
label: 'Display ''more'' link only if there is more content'
|
||||
use_more_text:
|
||||
type: boolean
|
||||
label: 'The text to display for the more link.'
|
||||
exposed_form:
|
||||
type: boolean
|
||||
label: 'Exposed form style'
|
||||
link_display:
|
||||
type: boolean
|
||||
label: 'Link display'
|
||||
link_url:
|
||||
type: boolean
|
||||
label: 'Link URL'
|
||||
group_by:
|
||||
type: boolean
|
||||
label: 'Aggregate'
|
||||
style:
|
||||
type: boolean
|
||||
label: 'Style'
|
||||
row:
|
||||
type: boolean
|
||||
label: 'Row'
|
||||
relationships:
|
||||
type: boolean
|
||||
label: 'Relationships'
|
||||
fields:
|
||||
type: boolean
|
||||
label: 'Fields'
|
||||
sorts:
|
||||
type: boolean
|
||||
label: 'Sorts'
|
||||
arguments:
|
||||
type: boolean
|
||||
label: 'Arguments'
|
||||
filters:
|
||||
type: boolean
|
||||
label: 'Filters'
|
||||
filter_groups:
|
||||
type: boolean
|
||||
label: 'Filter groups'
|
||||
header:
|
||||
type: boolean
|
||||
label: 'Header'
|
||||
footer:
|
||||
type: boolean
|
||||
label: 'Footer'
|
||||
relationships:
|
||||
type: sequence
|
||||
label: 'Relationships'
|
||||
sequence:
|
||||
type: views.relationship.[plugin_id]
|
||||
css_class:
|
||||
type: string
|
||||
label: 'CSS class'
|
||||
use_ajax:
|
||||
type: boolean
|
||||
label: 'Use AJAX'
|
||||
group_by:
|
||||
type: boolean
|
||||
label: 'Aggregate'
|
||||
display_description:
|
||||
type: label
|
||||
label: 'Administrative description'
|
||||
show_admin_links:
|
||||
type: boolean
|
||||
label: 'Show contextual links'
|
||||
use_more:
|
||||
type: boolean
|
||||
label: 'Create more link'
|
||||
use_more_always:
|
||||
type: boolean
|
||||
label: 'Display ''more'' link only if there is more content'
|
||||
use_more_text:
|
||||
type: label
|
||||
label: 'The text to display for the more link.'
|
||||
link_display:
|
||||
type: string
|
||||
label: 'Link display'
|
||||
link_url:
|
||||
type: string
|
||||
label: 'Link URL'
|
||||
header:
|
||||
type: sequence
|
||||
label: 'Header'
|
||||
sequence:
|
||||
type: views.area.[plugin_id]
|
||||
footer:
|
||||
type: sequence
|
||||
label: 'Footer'
|
||||
sequence:
|
||||
type: views.area.[plugin_id]
|
||||
display_comment:
|
||||
type: label
|
||||
label: 'Display comment'
|
||||
hide_attachment_summary:
|
||||
type: boolean
|
||||
label: 'Hide attachments in summary'
|
||||
rendering_language:
|
||||
type: string
|
||||
label: 'Entity language'
|
||||
exposed_block:
|
||||
type: boolean
|
||||
label: 'Put the exposed form in a block'
|
||||
display_extenders:
|
||||
type: sequence
|
||||
label: 'Display extenders'
|
||||
sequence:
|
||||
type: views.display_extender.[%key]
|
||||
|
||||
views_sort:
|
||||
type: views_handler
|
||||
label: 'Sort criteria'
|
||||
mapping:
|
||||
order:
|
||||
type: string
|
||||
label: 'Sort order'
|
||||
expose:
|
||||
type: views.sort_expose.[%parent.plugin_id]
|
||||
exposed:
|
||||
type: boolean
|
||||
label: 'Expose this sort to visitors, to allow them to change it'
|
||||
plugin_id:
|
||||
type: string
|
||||
label: 'Plugin ID'
|
||||
|
||||
views_sort_expose:
|
||||
type: mapping
|
||||
mapping:
|
||||
label:
|
||||
type: label
|
||||
label: 'Label'
|
||||
|
||||
views_area:
|
||||
type: views_handler
|
||||
label: 'Area'
|
||||
mapping:
|
||||
label:
|
||||
type: label
|
||||
label: 'A string to identify the area instance in the admin UI.'
|
||||
empty:
|
||||
type: boolean
|
||||
label: 'Should the area be displayed on empty results.'
|
||||
plugin_id:
|
||||
type: string
|
||||
label: 'Plugin ID'
|
||||
|
||||
views_handler:
|
||||
type: mapping
|
||||
mapping:
|
||||
id:
|
||||
type: string
|
||||
label: 'A unique ID per handler type'
|
||||
table:
|
||||
type: string
|
||||
label: 'The views_data table for this handler'
|
||||
field:
|
||||
type: string
|
||||
label: 'The views_data field for this handler'
|
||||
relationship:
|
||||
type: string
|
||||
label: 'The ID of the relationship instance used by this handler'
|
||||
group_type:
|
||||
type: string
|
||||
label: 'A sql aggregation type'
|
||||
admin_label:
|
||||
type: label
|
||||
label: 'A string to identify the handler instance in the admin UI.'
|
||||
entity_type:
|
||||
type: string
|
||||
label: 'The entity type'
|
||||
entity_field:
|
||||
type: string
|
||||
label: 'The corresponding entity field'
|
||||
plugin_id:
|
||||
type: string
|
||||
label: 'The plugin ID'
|
||||
|
||||
views_argument:
|
||||
type: views_handler
|
||||
label: 'Argument'
|
||||
mapping:
|
||||
default_action:
|
||||
type: string
|
||||
label: 'When the filter value is NOT available'
|
||||
exception:
|
||||
type: mapping
|
||||
label: 'Exception value'
|
||||
mapping:
|
||||
value:
|
||||
type: string
|
||||
label: 'Value'
|
||||
title_enable:
|
||||
type: boolean
|
||||
label: 'Override title'
|
||||
title:
|
||||
type: label
|
||||
label: 'Title'
|
||||
title_enable:
|
||||
type: boolean
|
||||
label: 'Override title'
|
||||
title:
|
||||
type: label
|
||||
label: 'Overridden title'
|
||||
default_argument_type:
|
||||
type: string
|
||||
label: 'Type'
|
||||
default_argument_options:
|
||||
type: views.argument_default.[%parent.default_argument_type]
|
||||
label: 'Default argument options'
|
||||
default_argument_skip_url:
|
||||
type: boolean
|
||||
label: 'Skip default argument for view URL'
|
||||
summary_options:
|
||||
type: views.style.[%parent.summary.format]
|
||||
label: 'Summary options'
|
||||
summary:
|
||||
type: mapping
|
||||
label: 'Display a summary'
|
||||
mapping:
|
||||
sort_order:
|
||||
type: string
|
||||
label: 'Sort order'
|
||||
number_of_records:
|
||||
type: integer
|
||||
label: 'Sort by'
|
||||
format:
|
||||
type: string
|
||||
label: 'Format'
|
||||
specify_validation:
|
||||
type: boolean
|
||||
label: 'Specify validation criteria'
|
||||
validate:
|
||||
type: mapping
|
||||
label: 'Validation settings'
|
||||
mapping:
|
||||
type:
|
||||
type: string
|
||||
label: 'Validator'
|
||||
fail:
|
||||
type: string
|
||||
label: 'Action to take if filter value does not validate'
|
||||
validate_options:
|
||||
type: views.argument_validator.[%parent.validate.type]
|
||||
label: 'Validate options'
|
||||
glossary:
|
||||
type: boolean
|
||||
label: 'Glossary mode'
|
||||
limit:
|
||||
type: integer
|
||||
label: 'Character limit'
|
||||
case:
|
||||
type: string
|
||||
label: 'Case'
|
||||
path_case:
|
||||
type: string
|
||||
label: 'Case in path'
|
||||
transform_dash:
|
||||
type: boolean
|
||||
label: 'Transform spaces to dashes in URL'
|
||||
break_phrase:
|
||||
type: boolean
|
||||
label: 'Allow multiple values'
|
||||
plugin_id:
|
||||
type: string
|
||||
label: 'Plugin ID'
|
||||
|
||||
views_exposed_form:
|
||||
type: mapping
|
||||
mapping:
|
||||
submit_button:
|
||||
type: label
|
||||
label: 'Submit button text'
|
||||
reset_button:
|
||||
type: boolean
|
||||
label: 'Include reset button'
|
||||
reset_button_label:
|
||||
type: label
|
||||
label: 'Reset button label'
|
||||
exposed_sorts_label:
|
||||
type: label
|
||||
label: 'Exposed sorts label'
|
||||
expose_sort_order:
|
||||
type: boolean
|
||||
label: 'Expose sort order'
|
||||
sort_asc_label:
|
||||
type: label
|
||||
label: 'Ascending'
|
||||
sort_desc_label:
|
||||
type: label
|
||||
label: 'Descending'
|
||||
|
||||
views_field:
|
||||
type: views_handler
|
||||
mapping:
|
||||
label:
|
||||
type: label
|
||||
label: 'Create a label'
|
||||
exclude:
|
||||
type: boolean
|
||||
label: 'Exclude from display'
|
||||
alter:
|
||||
type: mapping
|
||||
label: 'Rewrite results'
|
||||
mapping:
|
||||
alter_text:
|
||||
type: boolean
|
||||
label: 'Override the output of this field with custom text'
|
||||
text:
|
||||
type: text
|
||||
label: 'Text'
|
||||
make_link:
|
||||
type: boolean
|
||||
label: 'Output this field as a custom link'
|
||||
path:
|
||||
type: string
|
||||
label: 'Link path'
|
||||
absolute:
|
||||
type: boolean
|
||||
label: 'Use absolute path'
|
||||
external:
|
||||
type: boolean
|
||||
label: 'External server URL'
|
||||
replace_spaces:
|
||||
type: boolean
|
||||
label: 'Replace spaces with dashes'
|
||||
path_case:
|
||||
type: string
|
||||
label: 'Transform the case'
|
||||
trim_whitespace:
|
||||
type: boolean
|
||||
label: 'Remove whitespace'
|
||||
alt:
|
||||
type: label
|
||||
label: 'Title text'
|
||||
rel:
|
||||
type: string
|
||||
label: 'Rel Text'
|
||||
link_class:
|
||||
type: string
|
||||
label: 'Link class'
|
||||
prefix:
|
||||
type: label
|
||||
label: 'Prefix text'
|
||||
suffix:
|
||||
type: label
|
||||
label: 'Suffix text'
|
||||
target:
|
||||
type: string
|
||||
label: 'Target'
|
||||
nl2br:
|
||||
type: boolean
|
||||
label: 'Convert newlines to HTML <br> tags'
|
||||
max_length:
|
||||
type: integer
|
||||
label: 'Maximum number of characters'
|
||||
word_boundary:
|
||||
type: boolean
|
||||
label: 'Trim only on a word boundary'
|
||||
ellipsis:
|
||||
type: boolean
|
||||
label: 'Add "…" at the end of trimmed text'
|
||||
more_link:
|
||||
type: boolean
|
||||
label: 'Add a read-more link if output is trimmed'
|
||||
more_link_text:
|
||||
type: label
|
||||
label: 'More link label'
|
||||
more_link_path:
|
||||
type: string
|
||||
label: 'More link path'
|
||||
strip_tags:
|
||||
type: boolean
|
||||
label: 'Strip HTML tags'
|
||||
trim:
|
||||
type: boolean
|
||||
label: 'Trim this field to a maximum number of characters'
|
||||
preserve_tags:
|
||||
type: string
|
||||
label: 'Preserve certain tags'
|
||||
html:
|
||||
type: boolean
|
||||
label: 'Field can contain HTML'
|
||||
element_type:
|
||||
type: string
|
||||
label: 'HTML element'
|
||||
element_class:
|
||||
type: string
|
||||
label: 'CSS class'
|
||||
element_label_type:
|
||||
type: string
|
||||
label: 'Label HTML element'
|
||||
element_label_class:
|
||||
type: string
|
||||
label: 'CSS class'
|
||||
element_label_colon:
|
||||
type: boolean
|
||||
label: 'Place a colon after the label'
|
||||
element_wrapper_type:
|
||||
type: string
|
||||
label: 'Wrapper HTML element'
|
||||
element_wrapper_class:
|
||||
type: string
|
||||
label: 'CSS class'
|
||||
element_default_classes:
|
||||
type: boolean
|
||||
label: 'Add default classes'
|
||||
empty:
|
||||
type: string
|
||||
label: 'No results text'
|
||||
hide_empty:
|
||||
type: boolean
|
||||
label: 'Hide if empty'
|
||||
empty_zero:
|
||||
type: boolean
|
||||
label: 'Count the number 0 as empty'
|
||||
hide_alter_empty:
|
||||
type: boolean
|
||||
label: 'Hide rewriting if empty'
|
||||
destination:
|
||||
type: boolean
|
||||
label: 'Append a destination query string to operation links.'
|
||||
plugin_id:
|
||||
type: string
|
||||
label: 'Plugin ID'
|
||||
|
||||
views_pager:
|
||||
type: mapping
|
||||
label: 'Pager'
|
||||
mapping:
|
||||
offset:
|
||||
type: integer
|
||||
label: 'Offset'
|
||||
items_per_page:
|
||||
type: integer
|
||||
label: 'Items per page'
|
||||
|
||||
views_pager_sql:
|
||||
type: views_pager
|
||||
label: 'SQL pager'
|
||||
mapping:
|
||||
items_per_page:
|
||||
type: integer
|
||||
label: 'Items per page'
|
||||
total_pages:
|
||||
type: integer
|
||||
label: 'Number of pages'
|
||||
id:
|
||||
type: integer
|
||||
label: 'Pager ID'
|
||||
tags:
|
||||
type: mapping
|
||||
label: 'Pager link labels'
|
||||
mapping:
|
||||
next:
|
||||
type: label
|
||||
label: 'Next page link text'
|
||||
previous:
|
||||
type: label
|
||||
label: 'Previous page link text'
|
||||
quantity:
|
||||
type: integer
|
||||
label: 'Number of pager links visible'
|
||||
expose:
|
||||
type: mapping
|
||||
label: 'Exposed options'
|
||||
mapping:
|
||||
items_per_page:
|
||||
type: boolean
|
||||
label: 'Items per page'
|
||||
items_per_page_label:
|
||||
type: label
|
||||
label: 'Items per page label'
|
||||
items_per_page_options:
|
||||
type: string
|
||||
label: 'Exposed items per page options'
|
||||
items_per_page_options_all:
|
||||
type: boolean
|
||||
label: 'Include all items option'
|
||||
items_per_page_options_all_label:
|
||||
type: label
|
||||
label: 'All items label'
|
||||
offset:
|
||||
type: boolean
|
||||
label: 'Expose Offset'
|
||||
offset_label:
|
||||
type: label
|
||||
label: 'Offset label'
|
||||
|
||||
views_style:
|
||||
type: mapping
|
||||
mapping:
|
||||
grouping:
|
||||
type: sequence
|
||||
label: 'Grouping field number %i'
|
||||
sequence:
|
||||
type: mapping
|
||||
label: 'Field'
|
||||
mapping:
|
||||
field:
|
||||
type: string
|
||||
label: 'Field'
|
||||
rendered:
|
||||
type: boolean
|
||||
label: 'Use rendered output to group rows'
|
||||
rendered_strip:
|
||||
type: boolean
|
||||
label: 'Remove tags from rendered output'
|
||||
row_class:
|
||||
type: string
|
||||
label: 'Row class'
|
||||
default_row_class:
|
||||
type: boolean
|
||||
label: 'Add views row classes'
|
||||
uses_fields:
|
||||
type: boolean
|
||||
label: 'Force using fields'
|
||||
|
||||
views_filter:
|
||||
type: views_handler
|
||||
mapping:
|
||||
operator:
|
||||
type: string
|
||||
label: 'Operator'
|
||||
value:
|
||||
type: views.filter_value.[%parent.plugin_id]
|
||||
label: 'Value'
|
||||
group:
|
||||
type: integer
|
||||
label: 'Group'
|
||||
exposed:
|
||||
type: boolean
|
||||
label: 'Expose this filter to visitors, to allow them to change it'
|
||||
expose:
|
||||
type: mapping
|
||||
label: 'Expose'
|
||||
mapping:
|
||||
operator_id:
|
||||
type: string
|
||||
label: 'Operator identifier'
|
||||
label:
|
||||
type: label
|
||||
label: 'Label'
|
||||
description:
|
||||
type: label
|
||||
label: 'Description'
|
||||
use_operator:
|
||||
type: boolean
|
||||
label: 'Expose operator'
|
||||
operator:
|
||||
type: string
|
||||
label: 'Operator'
|
||||
identifier:
|
||||
type: string
|
||||
label: 'Filter identifier'
|
||||
required:
|
||||
type: boolean
|
||||
label: 'Required'
|
||||
remember:
|
||||
type: boolean
|
||||
label: 'Remember the last selection'
|
||||
multiple:
|
||||
type: boolean
|
||||
label: 'Allow multiple selections'
|
||||
remember_roles:
|
||||
type: sequence
|
||||
label: 'User roles'
|
||||
sequence:
|
||||
type: string
|
||||
label: 'Role'
|
||||
is_grouped:
|
||||
type: boolean
|
||||
label: 'Grouped filters'
|
||||
group_info:
|
||||
type: mapping
|
||||
label: 'Group'
|
||||
mapping:
|
||||
label:
|
||||
type: label
|
||||
label: 'Label'
|
||||
description:
|
||||
type: label
|
||||
label: 'Description'
|
||||
identifier:
|
||||
type: string
|
||||
label: 'Identifier'
|
||||
optional:
|
||||
type: boolean
|
||||
label: 'Optional'
|
||||
widget:
|
||||
type: string
|
||||
label: 'Widget type'
|
||||
multiple:
|
||||
type: boolean
|
||||
label: 'Allow multiple selections'
|
||||
remember:
|
||||
type: boolean
|
||||
label: 'Remember'
|
||||
default_group:
|
||||
type: string
|
||||
label: 'Default'
|
||||
default_group_multiple:
|
||||
type: sequence
|
||||
label: 'Defaults'
|
||||
sequence:
|
||||
type: integer
|
||||
label: 'Default'
|
||||
group_items:
|
||||
type: sequence
|
||||
label: 'Group items'
|
||||
sequence:
|
||||
type: views.filter.group_item.[%parent.%parent.%parent.plugin_id]
|
||||
label: 'Group item'
|
||||
plugin_id:
|
||||
type: string
|
||||
label: 'Plugin ID'
|
||||
|
||||
views_filter_group_item:
|
||||
type: mapping
|
||||
label: 'Group item'
|
||||
mapping:
|
||||
title:
|
||||
type: label
|
||||
label: 'Label'
|
||||
operator:
|
||||
type: string
|
||||
label: 'Operator'
|
||||
value:
|
||||
type: label
|
||||
label: 'Value'
|
||||
|
||||
views_relationship:
|
||||
type: views_handler
|
||||
mapping:
|
||||
admin_label:
|
||||
type: string
|
||||
label: 'Administrative title'
|
||||
required:
|
||||
type: boolean
|
||||
label: 'Require this relationship'
|
||||
|
||||
views_query:
|
||||
type: mapping
|
||||
label: 'Query options'
|
||||
|
||||
views_row:
|
||||
type: mapping
|
||||
label: 'Row options'
|
||||
mapping:
|
||||
relationship:
|
||||
type: string
|
||||
label: 'Relationship'
|
||||
|
||||
views_entity_row:
|
||||
type: views_row
|
||||
mapping:
|
||||
view_mode:
|
||||
type: string
|
||||
label: 'View mode'
|
||||
|
||||
views_cache:
|
||||
type: mapping
|
||||
label: 'Cache configuration'
|
||||
mapping:
|
||||
type:
|
||||
type: string
|
||||
label: 'Cache type'
|
||||
|
||||
views_display_extender:
|
||||
type: mapping
|
||||
label: 'Display extender settings'
|
129
core/modules/views/config/schema/views.display.schema.yml
Normal file
129
core/modules/views/config/schema/views.display.schema.yml
Normal file
|
@ -0,0 +1,129 @@
|
|||
# Schema for the views display plugins.
|
||||
|
||||
views.display.default:
|
||||
type: views_display
|
||||
label: 'Default display options'
|
||||
|
||||
views_display_path:
|
||||
type: views_display
|
||||
mapping:
|
||||
path:
|
||||
type: string
|
||||
label: 'Page path'
|
||||
route_name:
|
||||
type: string
|
||||
label: 'Route name'
|
||||
|
||||
views.display.page:
|
||||
type: views_display_path
|
||||
label: 'Page display options'
|
||||
mapping:
|
||||
menu:
|
||||
type: mapping
|
||||
label: 'Menu'
|
||||
mapping:
|
||||
type:
|
||||
type: string
|
||||
label: 'Type'
|
||||
title:
|
||||
type: text
|
||||
label: 'Title'
|
||||
description:
|
||||
type: text
|
||||
label: 'Description'
|
||||
weight:
|
||||
type: integer
|
||||
label: 'Weight'
|
||||
menu_name:
|
||||
type: string
|
||||
label: 'Menu name'
|
||||
parent:
|
||||
type: string
|
||||
label: 'Parent'
|
||||
context:
|
||||
type: string
|
||||
label: 'Context'
|
||||
tab_options:
|
||||
type: mapping
|
||||
label: 'Tab options'
|
||||
mapping:
|
||||
type:
|
||||
type: string
|
||||
label: 'Type'
|
||||
title:
|
||||
type: text
|
||||
label: 'Title'
|
||||
description:
|
||||
type: text
|
||||
label: 'Description'
|
||||
weight:
|
||||
type: integer
|
||||
label: 'Weight'
|
||||
menu_name:
|
||||
type: string
|
||||
label: 'Menu name'
|
||||
|
||||
views.display.block:
|
||||
type: views_display
|
||||
label: 'Block display options'
|
||||
mapping:
|
||||
block_description:
|
||||
type: label
|
||||
label: 'Block name'
|
||||
block_category:
|
||||
type: text
|
||||
label: 'Block category'
|
||||
block_hide_empty:
|
||||
type: boolean
|
||||
label: 'Hide block if no result/empty text'
|
||||
allow:
|
||||
type: mapping
|
||||
label: 'Allow'
|
||||
mapping:
|
||||
items_per_page:
|
||||
type: boolean
|
||||
label: 'Items per page'
|
||||
|
||||
views.display.feed:
|
||||
type: views_display_path
|
||||
label: 'Feed display options'
|
||||
mapping:
|
||||
sitename_title:
|
||||
type: boolean
|
||||
label: 'Use the site name for the title'
|
||||
displays:
|
||||
type: sequence
|
||||
label: 'The feed icon will be available only to the selected displays.'
|
||||
sequence:
|
||||
type: string
|
||||
label: 'Display'
|
||||
|
||||
views.display.embed:
|
||||
type: views_display
|
||||
label: 'Embed display options'
|
||||
|
||||
views.display.attachment:
|
||||
type: views_display
|
||||
label: 'Attachment display options'
|
||||
mapping:
|
||||
displays:
|
||||
type: sequence
|
||||
label: 'Attach to'
|
||||
sequence:
|
||||
type: string
|
||||
label: 'Display'
|
||||
attachment_position:
|
||||
type: string
|
||||
label: 'Attachment position'
|
||||
inherit_arguments:
|
||||
type: boolean
|
||||
label: 'Inherit contextual filters'
|
||||
inherit_exposed_filters:
|
||||
type: boolean
|
||||
label: 'Inherit exposed filters'
|
||||
inherit_pager:
|
||||
type: boolean
|
||||
label: 'Inherit pager'
|
||||
render_pager:
|
||||
type: boolean
|
||||
label: 'Render pager'
|
|
@ -0,0 +1,22 @@
|
|||
# Schema for the views entity reference selection plugins.
|
||||
|
||||
entity_reference_selection.views:
|
||||
type: mapping
|
||||
label: 'View handler settings'
|
||||
mapping:
|
||||
view:
|
||||
type: mapping
|
||||
label: 'View used to select the entities'
|
||||
mapping:
|
||||
view_name:
|
||||
type: string
|
||||
label: 'View name'
|
||||
display_name:
|
||||
type: string
|
||||
label: 'Display name'
|
||||
arguments:
|
||||
type: sequence
|
||||
label: 'View arguments'
|
||||
sequence:
|
||||
type: string
|
||||
label: 'Argument'
|
|
@ -0,0 +1,16 @@
|
|||
# Schema for the views exposed form.
|
||||
|
||||
views.exposed_form.basic:
|
||||
type: views_exposed_form
|
||||
label: 'Basic'
|
||||
|
||||
views.exposed_form.input_required:
|
||||
type: views_exposed_form
|
||||
label: 'Input required'
|
||||
mapping:
|
||||
text_input_required:
|
||||
type: text
|
||||
label: 'Text on demand'
|
||||
text_input_required_format:
|
||||
type: string
|
||||
label: 'Text on demand format'
|
245
core/modules/views/config/schema/views.field.schema.yml
Normal file
245
core/modules/views/config/schema/views.field.schema.yml
Normal file
|
@ -0,0 +1,245 @@
|
|||
# Schema for the views field plugins.
|
||||
|
||||
views.field.*:
|
||||
type: views_field
|
||||
label: 'Default field'
|
||||
|
||||
views.field.boolean:
|
||||
type: views_field
|
||||
label: 'Boolean'
|
||||
mapping:
|
||||
type:
|
||||
type: string
|
||||
label: 'Output format'
|
||||
type_custom_true:
|
||||
type: string
|
||||
label: 'Custom output for TRUE'
|
||||
type_custom_false:
|
||||
type: string
|
||||
label: 'Custom output for FALSE'
|
||||
not:
|
||||
type: boolean
|
||||
label: 'Reverse'
|
||||
|
||||
views.field.broken:
|
||||
type: views_field
|
||||
label: 'Broken'
|
||||
|
||||
views.field.counter:
|
||||
type: views_field
|
||||
label: 'Counter'
|
||||
mapping:
|
||||
counter_start:
|
||||
type: integer
|
||||
label: 'Starting value'
|
||||
|
||||
views.field.custom:
|
||||
type: views_field
|
||||
label: 'Custom'
|
||||
|
||||
views.field.date:
|
||||
type: views_field
|
||||
label: 'Date'
|
||||
mapping:
|
||||
date_format:
|
||||
type: string
|
||||
label: 'Date format'
|
||||
custom_date_format:
|
||||
type: string
|
||||
label: 'Custom date format'
|
||||
timezone:
|
||||
type: string
|
||||
label: 'Timezone'
|
||||
|
||||
views.field.entity_label:
|
||||
type: views_field
|
||||
label: 'Entity label'
|
||||
mapping:
|
||||
link_to_entity:
|
||||
type: boolean
|
||||
label: 'Link to entity'
|
||||
|
||||
views.field.file_size:
|
||||
type: views_field
|
||||
label: 'File size'
|
||||
mapping:
|
||||
file_size_display:
|
||||
type: string
|
||||
label: 'File size display'
|
||||
|
||||
views.field.links:
|
||||
type: views_field
|
||||
label: 'Links'
|
||||
mapping:
|
||||
fields:
|
||||
type: sequence
|
||||
label: 'Fields'
|
||||
sequence:
|
||||
type: string
|
||||
label: 'Field'
|
||||
destination:
|
||||
type: boolean
|
||||
label: 'Include destination'
|
||||
|
||||
views.field.dropbutton:
|
||||
type: views.field.links
|
||||
label: 'Drop button'
|
||||
|
||||
views.field.machine_name:
|
||||
type: views_field
|
||||
label: 'Machine name'
|
||||
mapping:
|
||||
machine_name:
|
||||
type: boolean
|
||||
label: 'Output machine name'
|
||||
|
||||
views.field.markup:
|
||||
type: views_field
|
||||
label: 'Markup'
|
||||
|
||||
views.field.numeric:
|
||||
type: views_field
|
||||
label: 'Numeric'
|
||||
mapping:
|
||||
set_precision:
|
||||
type: boolean
|
||||
label: 'Round'
|
||||
precision:
|
||||
type: integer
|
||||
label: 'Precision'
|
||||
decimal:
|
||||
type: string
|
||||
label: 'Decimal point'
|
||||
separator:
|
||||
type: string
|
||||
label: 'Thousands marker'
|
||||
format_plural:
|
||||
type: boolean
|
||||
label: 'Format plural'
|
||||
format_plural_string:
|
||||
type: label
|
||||
label: 'Singular and one or more plurals'
|
||||
prefix:
|
||||
type: label
|
||||
label: 'Prefix'
|
||||
suffix:
|
||||
type: label
|
||||
label: 'Suffix'
|
||||
|
||||
views.field.prerender_list:
|
||||
type: views_field
|
||||
label: 'List'
|
||||
mapping:
|
||||
type:
|
||||
type: string
|
||||
label: 'Display type'
|
||||
separator:
|
||||
type: string
|
||||
label: 'Separator'
|
||||
|
||||
views.field.serialized:
|
||||
type: views_field
|
||||
label: 'Serialized'
|
||||
mapping:
|
||||
format:
|
||||
type: string
|
||||
label: 'Display format'
|
||||
key:
|
||||
type: string
|
||||
label: 'Which key should be displayed'
|
||||
|
||||
views.field.standard:
|
||||
type: views_field
|
||||
label: 'Standard'
|
||||
|
||||
views.field.time_interval:
|
||||
type: views_field
|
||||
label: 'Time interval'
|
||||
mapping:
|
||||
granularity:
|
||||
type: integer
|
||||
label: 'Granularity'
|
||||
|
||||
views.field.url:
|
||||
type: views_field
|
||||
label: 'URL'
|
||||
mapping:
|
||||
display_as_link:
|
||||
type: boolean
|
||||
label: 'Display as link'
|
||||
|
||||
views.field.language:
|
||||
type: views_field
|
||||
label: 'Language'
|
||||
mapping:
|
||||
native_language:
|
||||
type: boolean
|
||||
label: 'Display in native language'
|
||||
|
||||
|
||||
views.field.entity_link:
|
||||
type: views_field
|
||||
label: 'Entity link'
|
||||
mapping:
|
||||
text:
|
||||
type: label
|
||||
label: 'Text to display'
|
||||
|
||||
views.field.entity_link_delete:
|
||||
type: views.field.entity_link
|
||||
label: 'Entity delete link'
|
||||
|
||||
views.field.entity_link_edit:
|
||||
type: views.field.entity_link
|
||||
label: 'Entity edit link'
|
||||
|
||||
views.field.bulk_form:
|
||||
type: views_field_bulk_form
|
||||
label: 'Bulk form'
|
||||
|
||||
views.field.field:
|
||||
type: views_field
|
||||
label: 'Views entity field handler'
|
||||
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'
|
133
core/modules/views/config/schema/views.filter.schema.yml
Normal file
133
core/modules/views/config/schema/views.filter.schema.yml
Normal file
|
@ -0,0 +1,133 @@
|
|||
# Schema for the views filter plugins.
|
||||
|
||||
views.filter.*:
|
||||
type: views_filter
|
||||
label: 'Default filter'
|
||||
|
||||
views.filter.boolean:
|
||||
type: views_filter
|
||||
label: 'Boolean'
|
||||
|
||||
views_filter_boolean_string:
|
||||
type: views_filter
|
||||
label: 'Boolean string'
|
||||
|
||||
views.filter.broken:
|
||||
type: views_filter
|
||||
label: 'Broken'
|
||||
|
||||
views.filter.bundle:
|
||||
type: views.filter.in_operator
|
||||
label: 'Bundle'
|
||||
|
||||
views.filter.combine:
|
||||
type: views.filter.string
|
||||
label: 'Combine'
|
||||
mapping:
|
||||
fields:
|
||||
type: sequence
|
||||
label: 'Fields'
|
||||
sequence:
|
||||
type: string
|
||||
label: 'Field'
|
||||
|
||||
views.filter_value.date:
|
||||
type: views.filter_value.numeric
|
||||
label: 'Date'
|
||||
mapping:
|
||||
type:
|
||||
type: string
|
||||
label: 'Type'
|
||||
|
||||
views.filter_value.groupby_numeric:
|
||||
type: views.filter_value.numeric
|
||||
label: 'Group by numeric'
|
||||
|
||||
views.filter.in_operator:
|
||||
type: views_filter
|
||||
label: 'IN operator'
|
||||
mapping:
|
||||
operator:
|
||||
type: string
|
||||
label: 'Operator'
|
||||
value:
|
||||
type: sequence
|
||||
label: 'Values'
|
||||
sequence:
|
||||
type: string
|
||||
label: 'Value'
|
||||
expose:
|
||||
type: mapping
|
||||
label: 'Expose'
|
||||
mapping:
|
||||
reduce:
|
||||
type: boolean
|
||||
label: 'Reduce'
|
||||
|
||||
views.filter.string:
|
||||
type: views_filter
|
||||
label: 'String'
|
||||
mapping:
|
||||
expose:
|
||||
type: mapping
|
||||
label: 'Exposed'
|
||||
mapping:
|
||||
required:
|
||||
type: boolean
|
||||
label: 'Required'
|
||||
value:
|
||||
type: string
|
||||
label: 'Value'
|
||||
|
||||
views.filter_value.numeric:
|
||||
type: mapping
|
||||
label: 'Numeric'
|
||||
mapping:
|
||||
min:
|
||||
type: string
|
||||
label: 'Min'
|
||||
max:
|
||||
type: string
|
||||
label: 'And max'
|
||||
value:
|
||||
type: string
|
||||
label: 'Value'
|
||||
|
||||
views.filter_value.equality:
|
||||
type: views.filter_value.numeric
|
||||
label: 'Equality'
|
||||
|
||||
views.filter.many_to_one:
|
||||
type: views.filter.in_operator
|
||||
label: 'Many to one'
|
||||
mapping:
|
||||
reduce_duplicates:
|
||||
type: boolean
|
||||
label: 'Reduce duplicate'
|
||||
|
||||
views.filter.standard:
|
||||
type: views_filter
|
||||
label: 'Standard'
|
||||
|
||||
views.filter.group_item.*:
|
||||
type: views_filter_group_item
|
||||
label: 'Default'
|
||||
|
||||
views.filter.group_item.numeric:
|
||||
type: views_filter_group_item
|
||||
label: 'Group items'
|
||||
mapping:
|
||||
value:
|
||||
type: views.filter_value.numeric
|
||||
|
||||
# Schema for the views filter value.
|
||||
|
||||
views.filter_value.boolean:
|
||||
type: boolean
|
||||
|
||||
views.filter_value.combine:
|
||||
type: string
|
||||
|
||||
views.filter.language:
|
||||
type: views.filter.in_operator
|
||||
label: 'Language'
|
35
core/modules/views/config/schema/views.pager.schema.yml
Normal file
35
core/modules/views/config/schema/views.pager.schema.yml
Normal file
|
@ -0,0 +1,35 @@
|
|||
# Schema for the views pager plugins.
|
||||
|
||||
views.pager.*:
|
||||
type: views_pager
|
||||
label: 'Default pager'
|
||||
|
||||
views.pager.none:
|
||||
type: views_pager
|
||||
label: 'Display all items'
|
||||
|
||||
views.pager.some:
|
||||
type: views_pager
|
||||
label: 'Display a specified number of items'
|
||||
|
||||
views.pager.mini:
|
||||
type: views_pager_sql
|
||||
label: 'Paged output, mini pager'
|
||||
|
||||
views.pager.full:
|
||||
type: views_pager_sql
|
||||
label: 'Paged output, full pager'
|
||||
mapping:
|
||||
tags:
|
||||
type: mapping
|
||||
label: 'Tags'
|
||||
mapping:
|
||||
first:
|
||||
type: label
|
||||
label: 'First page link text'
|
||||
last:
|
||||
type: label
|
||||
label: 'Last page link text'
|
||||
quantity:
|
||||
type: integer
|
||||
label: 'Number of pager links visible'
|
24
core/modules/views/config/schema/views.query.schema.yml
Normal file
24
core/modules/views/config/schema/views.query.schema.yml
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Schema for the views query.
|
||||
|
||||
views.query.views_query:
|
||||
type: views_query
|
||||
label: 'Views query'
|
||||
mapping:
|
||||
query_comment:
|
||||
type: string
|
||||
label: 'Query comment'
|
||||
disable_sql_rewrite:
|
||||
type: boolean
|
||||
label: 'Disable SQL rewriting'
|
||||
distinct:
|
||||
type: boolean
|
||||
label: 'Distinct'
|
||||
replica:
|
||||
type: boolean
|
||||
label: 'Use Replica Server'
|
||||
query_tags:
|
||||
type: sequence
|
||||
label: 'Query Tags'
|
||||
sequence:
|
||||
type: string
|
||||
label: 'Tag'
|
|
@ -0,0 +1,33 @@
|
|||
# Schema for the views relationship.
|
||||
|
||||
views.relationship.*:
|
||||
type: views_relationship
|
||||
label: 'Standard'
|
||||
|
||||
views.relationship.standard:
|
||||
type: views_relationship
|
||||
label: 'Standard'
|
||||
|
||||
views.relationship.broken:
|
||||
type: views_relationship
|
||||
label: 'Broken'
|
||||
|
||||
views.relationship.groupwise_max:
|
||||
type: views_relationship
|
||||
label: 'Groupwise max'
|
||||
mapping:
|
||||
subquery_sort:
|
||||
type: string
|
||||
label: 'Representative sort criteria'
|
||||
subquery_order:
|
||||
type: string
|
||||
label: 'Representative sort order'
|
||||
subquery_regenerate:
|
||||
type: boolean
|
||||
label: 'Generate subquery each time view is run'
|
||||
subquery_view:
|
||||
type: string
|
||||
label: 'Representative view'
|
||||
subquery_namespace:
|
||||
type: string
|
||||
label: 'Subquery namespace'
|
87
core/modules/views/config/schema/views.row.schema.yml
Normal file
87
core/modules/views/config/schema/views.row.schema.yml
Normal file
|
@ -0,0 +1,87 @@
|
|||
# Schema for the views row.
|
||||
|
||||
views.row.*:
|
||||
type: views_row
|
||||
|
||||
views.row.entity:*:
|
||||
type: views_entity_row
|
||||
label: 'Entity options'
|
||||
|
||||
views.row.fields:
|
||||
type: views_row
|
||||
label: 'Field options'
|
||||
mapping:
|
||||
default_field_elements:
|
||||
type: boolean
|
||||
label: 'Provide default field wrapper elements'
|
||||
inline:
|
||||
type: sequence
|
||||
label: 'Inline'
|
||||
sequence:
|
||||
type: string
|
||||
label: 'Inline'
|
||||
separator:
|
||||
type: string
|
||||
label: 'Separator'
|
||||
hide_empty:
|
||||
type: boolean
|
||||
label: 'Hide empty'
|
||||
|
||||
views.row.rss_fields:
|
||||
type: views_row
|
||||
label: 'RSS field options'
|
||||
mapping:
|
||||
title_field:
|
||||
type: string
|
||||
label: 'Title field'
|
||||
link_field:
|
||||
type: string
|
||||
label: 'Link field'
|
||||
description_field:
|
||||
type: string
|
||||
label: 'Description field'
|
||||
creator_field:
|
||||
type: string
|
||||
label: 'Creator field'
|
||||
date_field:
|
||||
type: string
|
||||
label: 'Publication date field'
|
||||
guid_field_options:
|
||||
type: mapping
|
||||
label: 'Guid settings'
|
||||
mapping:
|
||||
guid_field:
|
||||
type: string
|
||||
label: 'GUID field'
|
||||
guid_field_is_permalink:
|
||||
type: boolean
|
||||
label: 'GUID is permalink'
|
||||
|
||||
views.row.opml_fields:
|
||||
type: views_row
|
||||
label: 'OPML field options'
|
||||
mapping:
|
||||
type_field:
|
||||
type: string
|
||||
label: 'Type attribute'
|
||||
text_field:
|
||||
type: string
|
||||
label: 'Text attribute'
|
||||
created_field:
|
||||
type: string
|
||||
label: 'Created attribute'
|
||||
description_field:
|
||||
type: string
|
||||
label: 'Description attribute'
|
||||
html_url_field:
|
||||
type: string
|
||||
label: 'HTML URL attribute'
|
||||
language_field:
|
||||
type: string
|
||||
label: 'Language attribute'
|
||||
xml_url_field:
|
||||
type: string
|
||||
label: 'XML URL attribute'
|
||||
url_field:
|
||||
type: string
|
||||
label: 'URL attribute'
|
145
core/modules/views/config/schema/views.schema.yml
Normal file
145
core/modules/views/config/schema/views.schema.yml
Normal file
|
@ -0,0 +1,145 @@
|
|||
# Schema for the configuration files of the Views module.
|
||||
|
||||
views.settings:
|
||||
type: config_object
|
||||
label: 'Views settings'
|
||||
mapping:
|
||||
display_extenders:
|
||||
type: sequence
|
||||
label: 'Display extenders'
|
||||
sequence:
|
||||
type: string
|
||||
label: 'Display extender'
|
||||
skip_cache:
|
||||
type: boolean
|
||||
label: 'Disable views data caching'
|
||||
sql_signature:
|
||||
type: boolean
|
||||
label: 'Add Views signature to all SQL queries'
|
||||
ui:
|
||||
type: mapping
|
||||
label: 'UI settings'
|
||||
mapping:
|
||||
show:
|
||||
type: mapping
|
||||
label: 'Live preview settings'
|
||||
mapping:
|
||||
additional_queries:
|
||||
type: boolean
|
||||
label: 'Show other queries run during render during live preview'
|
||||
advanced_column:
|
||||
type: boolean
|
||||
label: 'Always show advanced display settings'
|
||||
master_display:
|
||||
type: boolean
|
||||
label: 'Always show the master (default) display'
|
||||
performance_statistics:
|
||||
type: boolean
|
||||
label: 'Show performance statistics'
|
||||
preview_information:
|
||||
type: boolean
|
||||
label: 'Show information and statistics about the view during live preview'
|
||||
sql_query:
|
||||
type: mapping
|
||||
label: 'Query settings'
|
||||
mapping:
|
||||
enabled:
|
||||
type: boolean
|
||||
label: 'Show the SQL query'
|
||||
where:
|
||||
type: string
|
||||
label: 'Show SQL query'
|
||||
display_embed:
|
||||
type: boolean
|
||||
label: 'Allow embedded displays'
|
||||
always_live_preview:
|
||||
type: boolean
|
||||
label: 'Automatically update preview on changes'
|
||||
exposed_filter_any_label:
|
||||
type: string
|
||||
label: 'Label for "Any" value on non-required single-select exposed filters'
|
||||
field_rewrite_elements:
|
||||
type: sequence
|
||||
label: 'Field rewrite elements'
|
||||
sequence:
|
||||
type: string
|
||||
label: 'Element'
|
||||
|
||||
views.view.*:
|
||||
type: config_entity
|
||||
label: 'View'
|
||||
mapping:
|
||||
id:
|
||||
type: string
|
||||
label: 'ID'
|
||||
label:
|
||||
type: label
|
||||
label: 'Label'
|
||||
module:
|
||||
type: string
|
||||
label: 'Module'
|
||||
description:
|
||||
type: text
|
||||
label: 'Administrative description'
|
||||
tag:
|
||||
type: string
|
||||
label: 'Tag'
|
||||
base_table:
|
||||
type: string
|
||||
label: 'Base table'
|
||||
base_field:
|
||||
type: string
|
||||
label: 'Base field'
|
||||
core:
|
||||
type: string
|
||||
label: 'Drupal version'
|
||||
display:
|
||||
type: sequence
|
||||
label: 'Displays'
|
||||
sequence:
|
||||
type: mapping
|
||||
label: 'Display settings'
|
||||
mapping:
|
||||
id:
|
||||
type: string
|
||||
label: 'Machine name'
|
||||
display_title:
|
||||
type: text
|
||||
label: 'Title'
|
||||
display_plugin:
|
||||
type: string
|
||||
label: 'Display plugin'
|
||||
position:
|
||||
type: integer
|
||||
label: 'Position'
|
||||
display_options:
|
||||
type: views.display.[%parent.display_plugin]
|
||||
cache_metadata:
|
||||
type: mapping
|
||||
label: 'Cache metadata'
|
||||
mapping:
|
||||
cacheable:
|
||||
type: boolean
|
||||
label: 'Cacheable'
|
||||
contexts:
|
||||
type: sequence
|
||||
label: 'Cache contexts'
|
||||
sequence:
|
||||
type: string
|
||||
|
||||
views_block:
|
||||
type: block_settings
|
||||
label: 'View block'
|
||||
mapping:
|
||||
views_label:
|
||||
type: label
|
||||
lable: 'Title'
|
||||
items_per_page:
|
||||
type: string
|
||||
label: 'Items per block'
|
||||
|
||||
block.settings.views_block:*:
|
||||
type: views_block
|
||||
|
||||
block.settings.views_exposed_filter_block:*:
|
||||
type: views_block
|
51
core/modules/views/config/schema/views.sort.schema.yml
Normal file
51
core/modules/views/config/schema/views.sort.schema.yml
Normal file
|
@ -0,0 +1,51 @@
|
|||
# Schema for the views sort plugins.
|
||||
|
||||
views.sort.*:
|
||||
type: views_sort
|
||||
label: 'Default sort'
|
||||
|
||||
views.sort.boolean:
|
||||
type: views_sort
|
||||
label: 'Boolean sort'
|
||||
|
||||
views.sort.date:
|
||||
type: views_sort
|
||||
label: 'Date sort'
|
||||
mapping:
|
||||
granularity:
|
||||
type: string
|
||||
label: 'Granularity'
|
||||
|
||||
views.sort.broken:
|
||||
type: views_sort
|
||||
label: 'Broken'
|
||||
|
||||
views.sort.random:
|
||||
type: views_sort
|
||||
label: 'Random'
|
||||
|
||||
views.sort.standard:
|
||||
type: views_sort
|
||||
label: 'Standard'
|
||||
|
||||
# Schema for the views sort expose.
|
||||
|
||||
views.sort_expose.boolean:
|
||||
type: views_sort_expose
|
||||
label: 'Boolean sort expose settings'
|
||||
|
||||
views.sort_expose.date:
|
||||
type: views_sort_expose
|
||||
label: 'Date sort expose settings'
|
||||
|
||||
views.sort_expose.standard:
|
||||
type: views_sort_expose
|
||||
label: 'Standard sort expose settings'
|
||||
mapping:
|
||||
order:
|
||||
type: string
|
||||
label: 'Order'
|
||||
|
||||
views.sort_expose.random:
|
||||
type: views.sort_expose.standard
|
||||
label: 'Random sort expose settings'
|
145
core/modules/views/config/schema/views.style.schema.yml
Normal file
145
core/modules/views/config/schema/views.style.schema.yml
Normal file
|
@ -0,0 +1,145 @@
|
|||
# Schema for the views style plugins.
|
||||
|
||||
views.style.*:
|
||||
type: views_style
|
||||
label: 'Default style'
|
||||
|
||||
views.style.default:
|
||||
type: views_style
|
||||
label: 'Unformatted list'
|
||||
|
||||
views.style.html_list:
|
||||
type: views_style
|
||||
label: 'HTML List'
|
||||
mapping:
|
||||
type:
|
||||
type: string
|
||||
label: 'List type'
|
||||
wrapper_class:
|
||||
type: string
|
||||
label: 'Wrapper class'
|
||||
class:
|
||||
type: string
|
||||
label: 'List class'
|
||||
|
||||
views.style.grid:
|
||||
type: views_style
|
||||
label: 'Grid'
|
||||
mapping:
|
||||
columns:
|
||||
type: integer
|
||||
label: 'Number of columns'
|
||||
automatic_width:
|
||||
type: boolean
|
||||
label: 'Automatic width'
|
||||
alignment:
|
||||
type: string
|
||||
label: 'Alignment'
|
||||
row_class_custom:
|
||||
type: string
|
||||
label: 'Custom row classes'
|
||||
row_class_default:
|
||||
type: boolean
|
||||
label: 'Default views row classes'
|
||||
col_class_custom:
|
||||
type: string
|
||||
label: 'Custom column classes'
|
||||
col_class_default:
|
||||
type: boolean
|
||||
label: 'Default views column classes'
|
||||
|
||||
views.style.table:
|
||||
type: views_style
|
||||
label: 'Table'
|
||||
mapping:
|
||||
columns:
|
||||
type: sequence
|
||||
label: 'Columns'
|
||||
sequence:
|
||||
type: string
|
||||
label: 'Columns name'
|
||||
default:
|
||||
type: string
|
||||
label: 'Default sort'
|
||||
info:
|
||||
type: sequence
|
||||
label: 'Columns info'
|
||||
sequence:
|
||||
type: mapping
|
||||
label: 'Column info'
|
||||
mapping:
|
||||
sortable:
|
||||
type: boolean
|
||||
label: 'Sortable'
|
||||
default_sort_order:
|
||||
type: string
|
||||
label: 'Default order'
|
||||
align:
|
||||
type: string
|
||||
label: 'Align'
|
||||
separator:
|
||||
type: string
|
||||
label: 'Separator'
|
||||
empty_column:
|
||||
type: boolean
|
||||
label: 'Hide empty columns'
|
||||
responsive:
|
||||
type: string
|
||||
label: 'Responsive'
|
||||
override:
|
||||
type: boolean
|
||||
label: 'Override normal sorting if click sorting is used'
|
||||
sticky:
|
||||
type: boolean
|
||||
label: 'Enable Drupal style "sticky" table headers (Javascript)'
|
||||
summary:
|
||||
type: label
|
||||
label: 'Table summary'
|
||||
order:
|
||||
type: string
|
||||
label: 'Default order'
|
||||
empty_table:
|
||||
type: boolean
|
||||
label: 'Show the empty text in the table'
|
||||
caption:
|
||||
type: label
|
||||
label: 'Caption'
|
||||
description:
|
||||
type: text
|
||||
label: 'Caption'
|
||||
|
||||
views.style.default_summary:
|
||||
type: views_style
|
||||
label: 'Summary options'
|
||||
mapping:
|
||||
base_path:
|
||||
type: string
|
||||
label: 'Base path'
|
||||
count:
|
||||
type: boolean
|
||||
label: 'Display record count with link'
|
||||
override:
|
||||
type: boolean
|
||||
label: 'Override number of items to display'
|
||||
items_per_page:
|
||||
type: integer
|
||||
label: 'Items to display'
|
||||
|
||||
views.style.rss:
|
||||
type: views_style
|
||||
label: 'RSS Feed'
|
||||
mapping:
|
||||
description:
|
||||
type: label
|
||||
label: 'RSS description'
|
||||
|
||||
views.style.unformatted_summary:
|
||||
type: views.style.default_summary
|
||||
label: 'Unformatted'
|
||||
mapping:
|
||||
inline:
|
||||
type: boolean
|
||||
label: 'Display items inline'
|
||||
separator:
|
||||
type: string
|
||||
label: 'Separator'
|
19
core/modules/views/css/views.module.css
Normal file
19
core/modules/views/css/views.module.css
Normal file
|
@ -0,0 +1,19 @@
|
|||
/* table style column align */
|
||||
.views-align-left {
|
||||
text-align: left;
|
||||
}
|
||||
.views-align-right {
|
||||
text-align: right;
|
||||
}
|
||||
.views-align-center {
|
||||
text-align: center;
|
||||
}
|
||||
/* Grid style column align. */
|
||||
.views-view-grid .views-col {
|
||||
float: left;
|
||||
}
|
||||
.views-view-grid .views-row {
|
||||
clear: both;
|
||||
float: left;
|
||||
width: 100%;
|
||||
}
|
194
core/modules/views/js/ajax_view.js
Normal file
194
core/modules/views/js/ajax_view.js
Normal file
|
@ -0,0 +1,194 @@
|
|||
/**
|
||||
* @file
|
||||
* Handles AJAX fetching of views, including filter submission and response.
|
||||
*/
|
||||
|
||||
(function ($, Drupal, drupalSettings) {
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Attaches the AJAX behavior to Views exposed filter forms and key View
|
||||
* links.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.ViewsAjaxView = {};
|
||||
Drupal.behaviors.ViewsAjaxView.attach = function () {
|
||||
if (drupalSettings && drupalSettings.views && drupalSettings.views.ajaxViews) {
|
||||
var ajaxViews = drupalSettings.views.ajaxViews;
|
||||
for (var i in ajaxViews) {
|
||||
if (ajaxViews.hasOwnProperty(i)) {
|
||||
Drupal.views.instances[i] = new Drupal.views.ajaxView(ajaxViews[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @namespace
|
||||
*/
|
||||
Drupal.views = {};
|
||||
|
||||
/**
|
||||
* @type {object.<string, Drupal.views.ajaxView>}
|
||||
*/
|
||||
Drupal.views.instances = {};
|
||||
|
||||
/**
|
||||
* Javascript object for a certain view.
|
||||
*
|
||||
* @constructor
|
||||
*
|
||||
* @param {object} settings
|
||||
* @param {string} settings.view_dom_id
|
||||
*/
|
||||
Drupal.views.ajaxView = function (settings) {
|
||||
var selector = '.js-view-dom-id-' + settings.view_dom_id;
|
||||
this.$view = $(selector);
|
||||
|
||||
// Retrieve the path to use for views' ajax.
|
||||
var ajax_path = drupalSettings.views.ajax_path;
|
||||
|
||||
// If there are multiple views this might've ended up showing up multiple
|
||||
// times.
|
||||
if (ajax_path.constructor.toString().indexOf("Array") !== -1) {
|
||||
ajax_path = ajax_path[0];
|
||||
}
|
||||
|
||||
// Check if there are any GET parameters to send to views.
|
||||
var queryString = window.location.search || '';
|
||||
if (queryString !== '') {
|
||||
// Remove the question mark and Drupal path component if any.
|
||||
queryString = queryString.slice(1).replace(/q=[^&]+&?|&?render=[^&]+/, '');
|
||||
if (queryString !== '') {
|
||||
// If there is a '?' in ajax_path, clean url are on and & should be
|
||||
// used to add parameters.
|
||||
queryString = ((/\?/.test(ajax_path)) ? '&' : '?') + queryString;
|
||||
}
|
||||
}
|
||||
|
||||
this.element_settings = {
|
||||
url: ajax_path + queryString,
|
||||
submit: settings,
|
||||
setClick: true,
|
||||
event: 'click',
|
||||
selector: selector,
|
||||
progress: {type: 'fullscreen'}
|
||||
};
|
||||
|
||||
this.settings = settings;
|
||||
|
||||
// Add the ajax to exposed forms.
|
||||
this.$exposed_form = $('form#views-exposed-form-' + settings.view_name.replace(/_/g, '-') + '-' + settings.view_display_id.replace(/_/g, '-'));
|
||||
this.$exposed_form.once('exposed-form').each(jQuery.proxy(this.attachExposedFormAjax, this));
|
||||
|
||||
// Add the ajax to pagers.
|
||||
this.$view
|
||||
// Don't attach to nested views. Doing so would attach multiple behaviors
|
||||
// to a given element.
|
||||
.filter(jQuery.proxy(this.filterNestedViews, this))
|
||||
.once('ajax-pager').each(jQuery.proxy(this.attachPagerAjax, this));
|
||||
|
||||
// Add a trigger to update this view specifically. In order to trigger a
|
||||
// refresh use the following code.
|
||||
//
|
||||
// @code
|
||||
// jQuery('.view-name').trigger('RefreshView');
|
||||
// @endcode
|
||||
var self_settings = $.extend({}, this.element_settings, {
|
||||
event: 'RefreshView',
|
||||
base: this.selector,
|
||||
element: this.$view
|
||||
});
|
||||
this.refreshViewAjax = Drupal.ajax(self_settings);
|
||||
};
|
||||
|
||||
/**
|
||||
* @method
|
||||
*/
|
||||
Drupal.views.ajaxView.prototype.attachExposedFormAjax = function () {
|
||||
var button = $('input[type=submit], input[type=image]', this.$exposed_form);
|
||||
button = button[0];
|
||||
|
||||
var self_settings = $.extend({}, this.element_settings, {
|
||||
base: $(button).attr('id'),
|
||||
element: button
|
||||
});
|
||||
this.exposedFormAjax = Drupal.ajax(self_settings);
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {bool}
|
||||
* If there is at least one parent with a view class return false.
|
||||
*
|
||||
* @todo remove .size() replace with .length.
|
||||
*/
|
||||
Drupal.views.ajaxView.prototype.filterNestedViews = function () {
|
||||
// If there is at least one parent with a view class, this view
|
||||
// is nested (e.g., an attachment). Bail.
|
||||
return !this.$view.parents('.view').size();
|
||||
};
|
||||
|
||||
/**
|
||||
* Attach the ajax behavior to each link.
|
||||
*/
|
||||
Drupal.views.ajaxView.prototype.attachPagerAjax = function () {
|
||||
this.$view.find('ul.js-pager__items > li > a, th.views-field a, .attachment .views-summary a')
|
||||
.each(jQuery.proxy(this.attachPagerLinkAjax, this));
|
||||
};
|
||||
|
||||
/**
|
||||
* Attach the ajax behavior to a singe link.
|
||||
*
|
||||
* @param {string} id
|
||||
* @param {HTMLElement} link
|
||||
*/
|
||||
Drupal.views.ajaxView.prototype.attachPagerLinkAjax = function (id, link) {
|
||||
var $link = $(link);
|
||||
var viewData = {};
|
||||
var href = $link.attr('href');
|
||||
// Construct an object using the settings defaults and then overriding
|
||||
// with data specific to the link.
|
||||
$.extend(
|
||||
viewData,
|
||||
this.settings,
|
||||
Drupal.Views.parseQueryString(href),
|
||||
// Extract argument data from the URL.
|
||||
Drupal.Views.parseViewArgs(href, this.settings.view_base_path)
|
||||
);
|
||||
|
||||
var self_settings = $.extend({}, this.element_settings, {
|
||||
submit: viewData,
|
||||
base: false,
|
||||
element: $link
|
||||
});
|
||||
this.pagerAjax = Drupal.ajax(self_settings);
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Drupal.Ajax} [ajax]
|
||||
* @param {object} response
|
||||
* @param {string} response.selector
|
||||
*/
|
||||
Drupal.AjaxCommands.prototype.viewsScrollTop = function (ajax, response) {
|
||||
// Scroll to the top of the view. This will allow users
|
||||
// to browse newly loaded content after e.g. clicking a pager
|
||||
// link.
|
||||
var offset = $(response.selector).offset();
|
||||
// We can't guarantee that the scrollable object should be
|
||||
// the body, as the view could be embedded in something
|
||||
// more complex such as a modal popup. Recurse up the DOM
|
||||
// and scroll the first element that has a non-zero top.
|
||||
var scrollTarget = response.selector;
|
||||
while ($(scrollTarget).scrollTop() === 0 && $(scrollTarget).parent()) {
|
||||
scrollTarget = $(scrollTarget).parent();
|
||||
}
|
||||
// Only scroll upward.
|
||||
if (offset.top - 10 < $(scrollTarget).scrollTop()) {
|
||||
$(scrollTarget).animate({scrollTop: (offset.top - 10)}, 500);
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal, drupalSettings);
|
100
core/modules/views/js/base.js
Normal file
100
core/modules/views/js/base.js
Normal file
|
@ -0,0 +1,100 @@
|
|||
/**
|
||||
* @file
|
||||
* Some basic behaviors and utility functions for Views.
|
||||
*/
|
||||
|
||||
(function ($, Drupal, drupalSettings) {
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* @namespace
|
||||
*/
|
||||
Drupal.Views = {};
|
||||
|
||||
/**
|
||||
* Helper function to parse a querystring.
|
||||
*
|
||||
* @param {string} query
|
||||
*
|
||||
* @return {object}
|
||||
*/
|
||||
Drupal.Views.parseQueryString = function (query) {
|
||||
var args = {};
|
||||
var pos = query.indexOf('?');
|
||||
if (pos !== -1) {
|
||||
query = query.substring(pos + 1);
|
||||
}
|
||||
var pair;
|
||||
var pairs = query.split('&');
|
||||
for (var i = 0; i < pairs.length; i++) {
|
||||
pair = pairs[i].split('=');
|
||||
// Ignore the 'q' path argument, if present.
|
||||
if (pair[0] !== 'q' && pair[1]) {
|
||||
args[decodeURIComponent(pair[0].replace(/\+/g, ' '))] = decodeURIComponent(pair[1].replace(/\+/g, ' '));
|
||||
}
|
||||
}
|
||||
return args;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to return a view's arguments based on a path.
|
||||
*
|
||||
* @param {string} href
|
||||
* @param {string} viewPath
|
||||
*
|
||||
* @return {object}
|
||||
*/
|
||||
Drupal.Views.parseViewArgs = function (href, viewPath) {
|
||||
var returnObj = {};
|
||||
var path = Drupal.Views.getPath(href);
|
||||
// Ensure we have a correct path.
|
||||
if (viewPath && path.substring(0, viewPath.length + 1) === viewPath + '/') {
|
||||
var args = decodeURIComponent(path.substring(viewPath.length + 1, path.length));
|
||||
returnObj.view_args = args;
|
||||
returnObj.view_path = path;
|
||||
}
|
||||
return returnObj;
|
||||
};
|
||||
|
||||
/**
|
||||
* Strip off the protocol plus domain from an href.
|
||||
*
|
||||
* @param {string} href
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
Drupal.Views.pathPortion = function (href) {
|
||||
// Remove e.g. http://example.com if present.
|
||||
var protocol = window.location.protocol;
|
||||
if (href.substring(0, protocol.length) === protocol) {
|
||||
// 2 is the length of the '//' that normally follows the protocol.
|
||||
href = href.substring(href.indexOf('/', protocol.length + 2));
|
||||
}
|
||||
return href;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the Drupal path portion of an href.
|
||||
*
|
||||
* @param {string} href
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
Drupal.Views.getPath = function (href) {
|
||||
href = Drupal.Views.pathPortion(href);
|
||||
href = href.substring(drupalSettings.path.baseUrl.length, href.length);
|
||||
// 3 is the length of the '?q=' added to the url without clean urls.
|
||||
if (href.substring(0, 3) === '?q=') {
|
||||
href = href.substring(3, href.length);
|
||||
}
|
||||
var chars = ['#', '?', '&'];
|
||||
for (var i = 0; i < chars.length; i++) {
|
||||
if (href.indexOf(chars[i]) > -1) {
|
||||
href = href.substr(0, href.indexOf(chars[i]));
|
||||
}
|
||||
}
|
||||
return href;
|
||||
};
|
||||
|
||||
})(jQuery, Drupal, drupalSettings);
|
24
core/modules/views/js/views-contextual.js
Normal file
24
core/modules/views/js/views-contextual.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript related to contextual links.
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.viewsContextualLinks = {
|
||||
attach: function (context) {
|
||||
var id = $('body').attr('data-views-page-contextual-id');
|
||||
|
||||
$('[data-contextual-id="' + id + '"]')
|
||||
.closest(':has(.view)')
|
||||
.addClass('contextual-region');
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery);
|
46
core/modules/views/src/Ajax/HighlightCommand.php
Normal file
46
core/modules/views/src/Ajax/HighlightCommand.php
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Ajax\HighlightCommand.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Ajax;
|
||||
|
||||
use Drupal\Core\Ajax\CommandInterface;
|
||||
|
||||
/**
|
||||
* Provides an AJAX command for highlighting a certain new piece of html.
|
||||
*
|
||||
* This command is implemented in Drupal.AjaxCommands.prototype.viewsHighlight.
|
||||
*/
|
||||
class HighlightCommand implements CommandInterface {
|
||||
|
||||
/**
|
||||
* A CSS selector string.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $selector;
|
||||
|
||||
/**
|
||||
* Constructs a \Drupal\views\Ajax\HighlightCommand object.
|
||||
*
|
||||
* @param string $selector
|
||||
* A CSS selector.
|
||||
*/
|
||||
public function __construct($selector) {
|
||||
$this->selector = $selector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\Ajax\CommandInterface::render().
|
||||
*/
|
||||
public function render() {
|
||||
return array(
|
||||
'command' => 'viewsHighlight',
|
||||
'selector' => $this->selector,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
46
core/modules/views/src/Ajax/ReplaceTitleCommand.php
Normal file
46
core/modules/views/src/Ajax/ReplaceTitleCommand.php
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Ajax\ReplaceTitleCommand.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Ajax;
|
||||
|
||||
use Drupal\Core\Ajax\CommandInterface;
|
||||
|
||||
/**
|
||||
* Provides an AJAX command for replacing the page title.
|
||||
*
|
||||
* This command is implemented in Drupal.AjaxCommands.prototype.viewsReplaceTitle.
|
||||
*/
|
||||
class ReplaceTitleCommand implements CommandInterface {
|
||||
|
||||
/**
|
||||
* The page title to replace.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $title;
|
||||
|
||||
/**
|
||||
* Constructs a \Drupal\views\Ajax\ReplaceTitleCommand object.
|
||||
*
|
||||
* @param string $title
|
||||
* The title of the page.
|
||||
*/
|
||||
public function __construct($title) {
|
||||
$this->title = $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\Ajax\CommandInterface::render().
|
||||
*/
|
||||
public function render() {
|
||||
return array(
|
||||
'command' => 'viewsReplaceTitle',
|
||||
'selector' => $this->title,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
46
core/modules/views/src/Ajax/ScrollTopCommand.php
Normal file
46
core/modules/views/src/Ajax/ScrollTopCommand.php
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Ajax\ScrollTopCommand.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Ajax;
|
||||
|
||||
use Drupal\Core\Ajax\CommandInterface;
|
||||
|
||||
/**
|
||||
* Provides an AJAX command for scrolling to the top of an element.
|
||||
*
|
||||
* This command is implemented in Drupal.AjaxCommands.prototype.viewsScrollTop.
|
||||
*/
|
||||
class ScrollTopCommand implements CommandInterface {
|
||||
|
||||
/**
|
||||
* A CSS selector string.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $selector;
|
||||
|
||||
/**
|
||||
* Constructs a \Drupal\views\Ajax\ScrollTopCommand object.
|
||||
*
|
||||
* @param string $selector
|
||||
* A CSS selector.
|
||||
*/
|
||||
public function __construct($selector) {
|
||||
$this->selector = $selector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\Ajax\CommandInterface::render().
|
||||
*/
|
||||
public function render() {
|
||||
return array(
|
||||
'command' => 'viewsScrollTop',
|
||||
'selector' => $this->selector,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
47
core/modules/views/src/Ajax/ShowButtonsCommand.php
Normal file
47
core/modules/views/src/Ajax/ShowButtonsCommand.php
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Ajax\ShowButtonsCommand.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Ajax;
|
||||
|
||||
use Drupal\Core\Ajax\CommandInterface;
|
||||
|
||||
/**
|
||||
* Provides an AJAX command for showing the save and cancel buttons.
|
||||
*
|
||||
* This command is implemented in Drupal.AjaxCommands.prototype.viewsShowButtons.
|
||||
*/
|
||||
class ShowButtonsCommand implements CommandInterface {
|
||||
|
||||
|
||||
/**
|
||||
* Whether the view has been changed.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $changed;
|
||||
|
||||
/**
|
||||
* Constructs a \Drupal\views\Ajax\ShowButtonsCommand object.
|
||||
*
|
||||
* @param bool $changed
|
||||
* Whether the view has been changed.
|
||||
*/
|
||||
public function __construct($changed) {
|
||||
$this->changed = $changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\Ajax\CommandInterface::render().
|
||||
*/
|
||||
public function render() {
|
||||
return array(
|
||||
'command' => 'viewsShowButtons',
|
||||
'changed' => $this->changed,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
28
core/modules/views/src/Ajax/TriggerPreviewCommand.php
Normal file
28
core/modules/views/src/Ajax/TriggerPreviewCommand.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Ajax\TriggerPreviewCommand.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Ajax;
|
||||
|
||||
use Drupal\Core\Ajax\CommandInterface;
|
||||
|
||||
/**
|
||||
* Provides an AJAX command for triggering the views live preview.
|
||||
*
|
||||
* This command is implemented in Drupal.AjaxCommands.prototype.viewsTriggerPreview.
|
||||
*/
|
||||
class TriggerPreviewCommand implements CommandInterface {
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\Ajax\CommandInterface::render().
|
||||
*/
|
||||
public function render() {
|
||||
return array(
|
||||
'command' => 'viewsTriggerPreview',
|
||||
);
|
||||
}
|
||||
|
||||
}
|
47
core/modules/views/src/Ajax/ViewAjaxResponse.php
Normal file
47
core/modules/views/src/Ajax/ViewAjaxResponse.php
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Ajax\ViewAjaxResponse.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Ajax;
|
||||
|
||||
use Drupal\Core\Ajax\AjaxResponse;
|
||||
use Drupal\views\ViewExecutable;
|
||||
|
||||
/**
|
||||
* Custom JSON response object for an ajax view response.
|
||||
*
|
||||
* We use a special response object to be able to fire a proper alter hook.
|
||||
*/
|
||||
class ViewAjaxResponse extends AjaxResponse {
|
||||
|
||||
/**
|
||||
* The view executed on this ajax request.
|
||||
*
|
||||
* @var \Drupal\views\ViewExecutable
|
||||
*/
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* Sets the executed view of this response.
|
||||
*
|
||||
* @param \Drupal\views\ViewExecutable $view
|
||||
* The View executed on this ajax request.
|
||||
*/
|
||||
public function setView(ViewExecutable $view) {
|
||||
$this->view = $view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the executed view of this response.
|
||||
*
|
||||
* @return \Drupal\views\ViewExecutable $view
|
||||
* The View executed on this ajax request.
|
||||
*/
|
||||
public function getView() {
|
||||
return $this->view;
|
||||
}
|
||||
|
||||
}
|
128
core/modules/views/src/Analyzer.php
Normal file
128
core/modules/views/src/Analyzer.php
Normal file
|
@ -0,0 +1,128 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Analyzer.
|
||||
*/
|
||||
|
||||
namespace Drupal\views;
|
||||
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\views\ViewExecutable;
|
||||
|
||||
/**
|
||||
* This tool is a small plugin manager to perform analysis on a view and
|
||||
* report results to the user. This tool is meant to let modules that
|
||||
* provide data to Views also help users properly use that data by
|
||||
* detecting invalid configurations. Views itself comes with only a
|
||||
* small amount of analysis tools, but more could easily be added either
|
||||
* by modules or as patches to Views itself.
|
||||
*/
|
||||
class Analyzer {
|
||||
|
||||
/**
|
||||
* A module handler that invokes the 'views_analyze' hook.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* Constructs an Analyzer object.
|
||||
*
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler that invokes the 'views_analyze' hook.
|
||||
*/
|
||||
public function __construct(ModuleHandlerInterface $module_handler) {
|
||||
$this->moduleHandler = $module_handler;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Analyzes a review and return the results.
|
||||
*
|
||||
* @param \Drupal\views\ViewExecutable $view
|
||||
* The view to analyze.
|
||||
*
|
||||
* @return array
|
||||
* An array of analyze results organized into arrays keyed by 'ok',
|
||||
* 'warning' and 'error'.
|
||||
*/
|
||||
public function getMessages(ViewExecutable $view) {
|
||||
$view->initDisplay();
|
||||
$messages = $this->moduleHandler->invokeAll('views_analyze', array($view));
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the analyze result into a message string.
|
||||
*
|
||||
* This is based upon the format of drupal_set_message which uses separate
|
||||
* boxes for "ok", "warning" and "error".
|
||||
*/
|
||||
public function formatMessages(array $messages) {
|
||||
if (empty($messages)) {
|
||||
$messages = array(static::formatMessage(t('View analysis can find nothing to report.'), 'ok'));
|
||||
}
|
||||
|
||||
$types = array('ok' => array(), 'warning' => array(), 'error' => array());
|
||||
foreach ($messages as $message) {
|
||||
if (empty($types[$message['type']])) {
|
||||
$types[$message['type']] = array();
|
||||
}
|
||||
$types[$message['type']][] = $message['message'];
|
||||
}
|
||||
|
||||
$output = '';
|
||||
foreach ($types as $type => $messages) {
|
||||
$type .= ' messages';
|
||||
$message = '';
|
||||
if (count($messages) > 1) {
|
||||
$item_list = array(
|
||||
'#theme' => 'item_list',
|
||||
'#items' => $messages,
|
||||
);
|
||||
$message = drupal_render($item_list);
|
||||
}
|
||||
elseif ($messages) {
|
||||
$message = array_shift($messages);
|
||||
}
|
||||
|
||||
if ($message) {
|
||||
$output .= "<div class=\"$type\">$message</div>";
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an analysis message.
|
||||
*
|
||||
* This tool should be called by any module responding to the analyze hook
|
||||
* to properly format the message. It is usually used in the form:
|
||||
* @code
|
||||
* $ret[] = Analyzer::formatMessage(t('This is the message'), 'ok');
|
||||
* @endcode
|
||||
*
|
||||
* The 'ok' status should be used to provide information about things
|
||||
* that are acceptable. In general analysis isn't interested in 'ok'
|
||||
* messages, but instead the 'warning', which is a category for items
|
||||
* that may be broken unless the user knows what he or she is doing,
|
||||
* and 'error' for items that are definitely broken are much more useful.
|
||||
*
|
||||
* @param string $message
|
||||
* @param string $type
|
||||
* The type of message. This should be "ok", "warning" or "error". Other
|
||||
* values can be used but how they are treated by the output routine
|
||||
* is undefined.
|
||||
*
|
||||
* @return array
|
||||
* A single formatted message, consisting of a key message and a key type.
|
||||
*/
|
||||
static function formatMessage($message, $type = 'error') {
|
||||
return array('message' => $message, 'type' => $type);
|
||||
}
|
||||
|
||||
}
|
85
core/modules/views/src/Annotation/ViewsAccess.php
Normal file
85
core/modules/views/src/Annotation/ViewsAccess.php
Normal file
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Annotation\ViewsAccess.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Annotation;
|
||||
|
||||
use Drupal\views\Annotation\ViewsPluginAnnotationBase;
|
||||
|
||||
/**
|
||||
* Defines a Plugin annotation object for views access plugins.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\access\AccessPluginBase
|
||||
*
|
||||
* @ingroup views_access_plugins
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class ViewsAccess extends ViewsPluginAnnotationBase {
|
||||
|
||||
/**
|
||||
* The plugin ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* The plugin title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $title = '';
|
||||
|
||||
/**
|
||||
* (optional) The short title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $short_title = '';
|
||||
|
||||
/**
|
||||
* A short help string; this is displayed in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $help = '';
|
||||
|
||||
/**
|
||||
* The types of the display this plugin can be used with.
|
||||
*
|
||||
* For example the Feed display defines the type 'feed', so only rss style
|
||||
* and row plugins can be used in the views UI.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $display_types;
|
||||
|
||||
/**
|
||||
* The base tables on which this access plugin can be used.
|
||||
*
|
||||
* If no base table is specified the plugin can be used with all tables.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $base;
|
||||
|
||||
/**
|
||||
* Whether the plugin should be not selectable in the UI.
|
||||
*
|
||||
* If set to TRUE, you can still use it via the API in config files.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $no_ui;
|
||||
|
||||
}
|
21
core/modules/views/src/Annotation/ViewsArea.php
Normal file
21
core/modules/views/src/Annotation/ViewsArea.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Annotation\ViewsArea.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Annotation;
|
||||
|
||||
/**
|
||||
* Defines a Plugin annotation object for views area handlers.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\area\AreaPluginBase
|
||||
*
|
||||
* @ingroup views_area_handlers
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class ViewsArea extends ViewsHandlerAnnotationBase {
|
||||
|
||||
}
|
21
core/modules/views/src/Annotation/ViewsArgument.php
Normal file
21
core/modules/views/src/Annotation/ViewsArgument.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Annotation\ViewsArgument.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Annotation;
|
||||
|
||||
/**
|
||||
* Defines a Plugin annotation object for views argument handlers.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\argument\ArgumentPluginBase
|
||||
*
|
||||
* @ingroup views_argument_handlers
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class ViewsArgument extends ViewsHandlerAnnotationBase {
|
||||
|
||||
}
|
57
core/modules/views/src/Annotation/ViewsArgumentDefault.php
Normal file
57
core/modules/views/src/Annotation/ViewsArgumentDefault.php
Normal file
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Annotation\ViewsArgumentDefault.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Annotation;
|
||||
|
||||
use Drupal\views\Annotation\ViewsPluginAnnotationBase;
|
||||
|
||||
/**
|
||||
* Defines a Plugin annotation object for views argument default plugins.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase
|
||||
*
|
||||
* @ingroup views_argument_default_plugins
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class ViewsArgumentDefault extends ViewsPluginAnnotationBase {
|
||||
|
||||
/**
|
||||
* The plugin ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* The plugin title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $title = '';
|
||||
|
||||
/**
|
||||
* (optional) The short title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $short_title = '';
|
||||
|
||||
/**
|
||||
* Whether the plugin should be not selectable in the UI.
|
||||
*
|
||||
* If it's set to TRUE, you can still use it via the API in config files.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $no_ui;
|
||||
|
||||
}
|
57
core/modules/views/src/Annotation/ViewsArgumentValidator.php
Normal file
57
core/modules/views/src/Annotation/ViewsArgumentValidator.php
Normal file
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Annotation\ViewsArgumentValidator.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Annotation;
|
||||
|
||||
use Drupal\views\Annotation\ViewsPluginAnnotationBase;
|
||||
|
||||
/**
|
||||
* Defines a Plugin annotation object for views argument validator plugins.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\argument_validator\ArgumentValidatorPluginBase
|
||||
*
|
||||
* @ingroup views_argument_validate_plugins
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class ViewsArgumentValidator extends ViewsPluginAnnotationBase {
|
||||
|
||||
/**
|
||||
* The plugin ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* The plugin title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $title = '';
|
||||
|
||||
/**
|
||||
* (optional) The short title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $short_title = '';
|
||||
|
||||
/**
|
||||
* Whether the plugin should be not selectable in the UI.
|
||||
*
|
||||
* If it's set to TRUE, you can still use it via the API in config files.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $no_ui;
|
||||
|
||||
}
|
85
core/modules/views/src/Annotation/ViewsCache.php
Normal file
85
core/modules/views/src/Annotation/ViewsCache.php
Normal file
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Annotation\ViewsCache.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Annotation;
|
||||
|
||||
use Drupal\views\Annotation\ViewsPluginAnnotationBase;
|
||||
|
||||
/**
|
||||
* Defines a Plugin annotation object for views cache plugins.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\cache\CachePluginBase
|
||||
*
|
||||
* @ingroup views_cache_plugins
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class ViewsCache extends ViewsPluginAnnotationBase {
|
||||
|
||||
/**
|
||||
* The plugin ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* The plugin title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $title = '';
|
||||
|
||||
/**
|
||||
* (optional) The short title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $short_title = '';
|
||||
|
||||
/**
|
||||
* A short help string; this is displayed in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $help = '';
|
||||
|
||||
/**
|
||||
* The types of the display this plugin can be used with.
|
||||
*
|
||||
* For example the Feed display defines the type 'feed', so only rss style
|
||||
* and row plugins can be used in the views UI.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $display_types;
|
||||
|
||||
/**
|
||||
* The base tables on which this cache plugin can be used.
|
||||
*
|
||||
* If no base table is specified the plugin can be used with all tables.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $base;
|
||||
|
||||
/**
|
||||
* Whether the plugin should be not selectable in the UI.
|
||||
*
|
||||
* If it's set to TRUE, you can still use it via the API in config files.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $no_ui;
|
||||
|
||||
}
|
141
core/modules/views/src/Annotation/ViewsDisplay.php
Normal file
141
core/modules/views/src/Annotation/ViewsDisplay.php
Normal file
|
@ -0,0 +1,141 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Annotation\ViewsDisplay.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Annotation;
|
||||
|
||||
use Drupal\views\Annotation\ViewsPluginAnnotationBase;
|
||||
|
||||
/**
|
||||
* Defines a Plugin annotation object for views display plugins.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\display\DisplayPluginBase
|
||||
*
|
||||
* @ingroup views_display_plugins
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class ViewsDisplay extends ViewsPluginAnnotationBase {
|
||||
|
||||
/**
|
||||
* The plugin ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* The plugin title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $title = '';
|
||||
|
||||
/**
|
||||
* (optional) The short title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $short_title = '';
|
||||
|
||||
/**
|
||||
* The administrative name of the display.
|
||||
*
|
||||
* The name is displayed on the Views overview and also used as default name
|
||||
* for new displays.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $admin = '';
|
||||
|
||||
/**
|
||||
* A short help string; this is displayed in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $help = '';
|
||||
|
||||
/**
|
||||
* Whether or not to use hook_menu() to register a route.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $uses_menu_links;
|
||||
|
||||
/**
|
||||
* Does the display plugin registers routes to the route.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $uses_route;
|
||||
|
||||
/**
|
||||
* Does the display plugin provide blocks.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $uses_hook_block;
|
||||
|
||||
/**
|
||||
* A list of places where contextual links should be added.
|
||||
* For example:
|
||||
* @code
|
||||
* array(
|
||||
* 'page',
|
||||
* 'block',
|
||||
* )
|
||||
* @endcode
|
||||
*
|
||||
* If you don't specify it there will be contextual links rendered for all
|
||||
* displays of a view. If this is not set or regions have been specified,
|
||||
* views will display an option to 'hide contextual links'. Use an empty
|
||||
* array to disable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $contextual_links_locations;
|
||||
|
||||
/**
|
||||
* The base tables on which this display plugin can be used.
|
||||
*
|
||||
* If no base table is specified the plugin can be used with all tables.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $base;
|
||||
|
||||
/**
|
||||
* The theme function used to render the display's output.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public $theme;
|
||||
|
||||
/**
|
||||
* Whether the plugin should be not selectable in the UI.
|
||||
*
|
||||
* If it's set to TRUE, you can still use it via the API in config files.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $no_ui;
|
||||
|
||||
/**
|
||||
* Whether the display returns a response object.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $returns_response;
|
||||
|
||||
}
|
64
core/modules/views/src/Annotation/ViewsDisplayExtender.php
Normal file
64
core/modules/views/src/Annotation/ViewsDisplayExtender.php
Normal file
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Annotation\ViewsDisplayExtender.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Annotation;
|
||||
|
||||
/**
|
||||
* Defines a Plugin annotation object for views display extender plugins.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\display_extender\DisplayExtenderPluginBase
|
||||
*
|
||||
* @ingroup views_display_extender_plugins
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class ViewsDisplayExtender extends ViewsPluginAnnotationBase {
|
||||
|
||||
/**
|
||||
* The plugin ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* The plugin title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $title = '';
|
||||
|
||||
/**
|
||||
* (optional) The short title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $short_title = '';
|
||||
|
||||
/**
|
||||
* A short help string; this is displayed in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $help = '';
|
||||
|
||||
/**
|
||||
* Whether or not the plugin is selectable in the UI.
|
||||
*
|
||||
* If it's set to TRUE, you can still use it via the API in config files.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $no_ui;
|
||||
|
||||
}
|
85
core/modules/views/src/Annotation/ViewsExposedForm.php
Normal file
85
core/modules/views/src/Annotation/ViewsExposedForm.php
Normal file
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Annotation\ViewsExposedForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Annotation;
|
||||
|
||||
use Drupal\views\Annotation\ViewsPluginAnnotationBase;
|
||||
|
||||
/**
|
||||
* Defines a Plugin annotation object for views exposed form plugins.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase
|
||||
*
|
||||
* @ingroup views_exposed_form_plugins
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class ViewsExposedForm extends ViewsPluginAnnotationBase {
|
||||
|
||||
/**
|
||||
* The plugin ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* The plugin title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $title = '';
|
||||
|
||||
/**
|
||||
* (optional) The short title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $short_title = '';
|
||||
|
||||
/**
|
||||
* A short help string; this is displayed in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $help = '';
|
||||
|
||||
/**
|
||||
* The types of the display this plugin can be used with.
|
||||
*
|
||||
* For example the Feed display defines the type 'feed', so only rss style
|
||||
* and row plugins can be used in the views UI.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $display_types;
|
||||
|
||||
/**
|
||||
* The base tables on which this exposed form plugin can be used.
|
||||
*
|
||||
* If no base table is specified the plugin can be used with all tables.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $base;
|
||||
|
||||
/**
|
||||
* Whether the plugin should be not selectable in the UI.
|
||||
*
|
||||
* If it's set to TRUE, you can still use it via the API in config files.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $no_ui;
|
||||
|
||||
}
|
21
core/modules/views/src/Annotation/ViewsField.php
Normal file
21
core/modules/views/src/Annotation/ViewsField.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Annotation\ViewsField.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Annotation;
|
||||
|
||||
/**
|
||||
* Defines a Plugin annotation object for views field handlers.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\field\FieldPluginBase
|
||||
*
|
||||
* @ingroup views_field_handlers
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class ViewsField extends ViewsHandlerAnnotationBase {
|
||||
|
||||
}
|
21
core/modules/views/src/Annotation/ViewsFilter.php
Normal file
21
core/modules/views/src/Annotation/ViewsFilter.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Annotation\ViewsFilter.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Annotation;
|
||||
|
||||
/**
|
||||
* Defines a Plugin annotation object for views filter handlers.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\filter\FilterPluginBase
|
||||
*
|
||||
* @ingroup views_filter_handlers
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class ViewsFilter extends ViewsHandlerAnnotationBase {
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Annotation\ViewsHandlerAnnotationBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Annotation;
|
||||
|
||||
use Drupal\Component\Annotation\PluginID;
|
||||
|
||||
/**
|
||||
* Defines an abstract base class for all views handler annotations.
|
||||
*/
|
||||
abstract class ViewsHandlerAnnotationBase extends PluginID {
|
||||
|
||||
}
|
21
core/modules/views/src/Annotation/ViewsJoin.php
Normal file
21
core/modules/views/src/Annotation/ViewsJoin.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Annotation\ViewsJoin.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Annotation;
|
||||
|
||||
/**
|
||||
* Defines a Plugin annotation object for views join plugins.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\join\JoinPluginBase
|
||||
*
|
||||
* @ingroup views_join_handlers
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class ViewsJoin extends ViewsHandlerAnnotationBase {
|
||||
|
||||
}
|
92
core/modules/views/src/Annotation/ViewsPager.php
Normal file
92
core/modules/views/src/Annotation/ViewsPager.php
Normal file
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Annotation\ViewsPager.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Annotation;
|
||||
|
||||
use Drupal\views\Annotation\ViewsPluginAnnotationBase;
|
||||
|
||||
/**
|
||||
* Defines a Plugin annotation object for views pager plugins.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\pager\PagerPluginBase
|
||||
*
|
||||
* @ingroup views_pager_plugins
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class ViewsPager extends ViewsPluginAnnotationBase {
|
||||
|
||||
/**
|
||||
* The plugin ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* The plugin title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $title = '';
|
||||
|
||||
/**
|
||||
* (optional) The short title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $short_title = '';
|
||||
|
||||
/**
|
||||
* A short help string; this is displayed in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $help = '';
|
||||
|
||||
/**
|
||||
* The theme function used to render the pager's output.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public $theme;
|
||||
|
||||
/**
|
||||
* The types of the display this plugin can be used with.
|
||||
*
|
||||
* For example the Feed display defines the type 'feed', so only rss style
|
||||
* and row plugins can be used in the views UI.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $display_types;
|
||||
|
||||
/**
|
||||
* The base tables on which this pager plugin can be used.
|
||||
*
|
||||
* If no base table is specified the plugin can be used with all tables.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $base;
|
||||
|
||||
/**
|
||||
* Whether the plugin should be not selectable in the UI.
|
||||
*
|
||||
* If it's set to TRUE, you can still use it via the API in config files.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $no_ui;
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Annotation\ViewsPluginAnnotationBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Annotation;
|
||||
|
||||
use Drupal\Component\Annotation\AnnotationInterface;
|
||||
use Drupal\Component\Annotation\Plugin;
|
||||
|
||||
/**
|
||||
* Defines an abstract base class for all views plugin annotations.
|
||||
*/
|
||||
abstract class ViewsPluginAnnotationBase extends Plugin implements AnnotationInterface {
|
||||
|
||||
/**
|
||||
* A class to make the plugin derivative aware.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @see \Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator
|
||||
*/
|
||||
public $derivative;
|
||||
|
||||
/**
|
||||
* Whether or not to register a theme function automatically.
|
||||
*
|
||||
* @var bool (optional)
|
||||
*/
|
||||
public $register_theme = TRUE;
|
||||
|
||||
}
|
66
core/modules/views/src/Annotation/ViewsQuery.php
Normal file
66
core/modules/views/src/Annotation/ViewsQuery.php
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Annotation\ViewsQuery.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Annotation;
|
||||
|
||||
use Drupal\views\Annotation\ViewsPluginAnnotationBase;
|
||||
|
||||
/**
|
||||
* Defines a Plugin annotation object for views query plugins.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\query\QueryPluginBase
|
||||
*
|
||||
* @ingroup views_query_plugins
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class ViewsQuery extends ViewsPluginAnnotationBase {
|
||||
|
||||
/**
|
||||
* The plugin ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* The plugin title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $title = '';
|
||||
|
||||
/**
|
||||
* (optional) The short title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $short_title = '';
|
||||
|
||||
/**
|
||||
* A short help string; this is displayed in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $help = '';
|
||||
|
||||
/**
|
||||
* Whether the plugin should be not selectable in the UI.
|
||||
*
|
||||
* If it's set to TRUE, you can still use it via the API in config files.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $no_ui;
|
||||
|
||||
}
|
21
core/modules/views/src/Annotation/ViewsRelationship.php
Normal file
21
core/modules/views/src/Annotation/ViewsRelationship.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Annotation\ViewsRelationship.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Annotation;
|
||||
|
||||
/**
|
||||
* Defines a Plugin annotation object for views relationship handlers.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\relationship\RelationshipPluginBase
|
||||
*
|
||||
* @ingroup views_relationship_handlers
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class ViewsRelationship extends ViewsHandlerAnnotationBase {
|
||||
|
||||
}
|
90
core/modules/views/src/Annotation/ViewsRow.php
Normal file
90
core/modules/views/src/Annotation/ViewsRow.php
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Annotation\ViewsRow.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Annotation;
|
||||
|
||||
use Drupal\views\Annotation\ViewsPluginAnnotationBase;
|
||||
|
||||
/**
|
||||
* Defines a Plugin annotation object for views row plugins.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\row\RowPluginBase
|
||||
*
|
||||
* @ingroup views_row_plugins
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class ViewsRow extends ViewsPluginAnnotationBase {
|
||||
|
||||
/**
|
||||
* The plugin ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* The plugin title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $title = '';
|
||||
|
||||
/**
|
||||
* (optional) The short title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $short_title = '';
|
||||
|
||||
/**
|
||||
* A short help string; this is displayed in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $help = '';
|
||||
|
||||
/**
|
||||
* The theme function used to render the row output.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public $theme;
|
||||
|
||||
/**
|
||||
* The base tables on which this row plugin can be used.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $base;
|
||||
|
||||
/**
|
||||
* The types of the display this plugin can be used with.
|
||||
*
|
||||
* For example the Feed display defines the type 'feed', so only rss style
|
||||
* and row plugins can be used in the views UI.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $display_types;
|
||||
|
||||
/**
|
||||
* Whether the plugin should be not selectable in the UI.
|
||||
*
|
||||
* If it's set to TRUE, you can still use it via the API in config files.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $no_ui;
|
||||
|
||||
}
|
21
core/modules/views/src/Annotation/ViewsSort.php
Normal file
21
core/modules/views/src/Annotation/ViewsSort.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Annotation\ViewsSort.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Annotation;
|
||||
|
||||
/**
|
||||
* Defines a Plugin annotation object for views sort handlers.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\sort\SortPluginBase
|
||||
*
|
||||
* @ingroup views_sort_handlers
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class ViewsSort extends ViewsHandlerAnnotationBase {
|
||||
|
||||
}
|
92
core/modules/views/src/Annotation/ViewsStyle.php
Normal file
92
core/modules/views/src/Annotation/ViewsStyle.php
Normal file
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Annotation\ViewsStyle.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Annotation;
|
||||
|
||||
use Drupal\views\Annotation\ViewsPluginAnnotationBase;
|
||||
|
||||
/**
|
||||
* Defines a Plugin annotation object for views style plugins.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\style\StylePluginBase
|
||||
*
|
||||
* @ingroup views_style_plugins
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class ViewsStyle extends ViewsPluginAnnotationBase {
|
||||
|
||||
/**
|
||||
* The plugin ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* The plugin title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $title = '';
|
||||
|
||||
/**
|
||||
* (optional) The short title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $short_title = '';
|
||||
|
||||
/**
|
||||
* A short help string; this is displayed in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $help = '';
|
||||
|
||||
/**
|
||||
* The theme function used to render the style output.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $theme;
|
||||
|
||||
/**
|
||||
* The types of the display this plugin can be used with.
|
||||
*
|
||||
* For example the Feed display defines the type 'feed', so only rss style
|
||||
* and row plugins can be used in the views UI.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $display_types;
|
||||
|
||||
/**
|
||||
* The base tables on which this style plugin can be used.
|
||||
*
|
||||
* If no base table is specified the plugin can be used with all tables.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $base;
|
||||
|
||||
/**
|
||||
* Whether the plugin should be not selectable in the UI.
|
||||
*
|
||||
* If it's set to TRUE, you can still use it via the API in config files.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $no_ui;
|
||||
|
||||
}
|
56
core/modules/views/src/Annotation/ViewsWizard.php
Normal file
56
core/modules/views/src/Annotation/ViewsWizard.php
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Annotation\ViewsWizard.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Annotation;
|
||||
|
||||
use Drupal\views\Annotation\ViewsPluginAnnotationBase;
|
||||
|
||||
/**
|
||||
* Defines a Plugin annotation object for views wizard plugins.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\wizard\WizardPluginBase
|
||||
* @see \Drupal\views\Plugin\views\wizard\WizardInterface
|
||||
*
|
||||
* @ingroup views_wizard_plugins
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class ViewsWizard extends ViewsPluginAnnotationBase {
|
||||
|
||||
/**
|
||||
* The plugin ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* The plugin title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $title = '';
|
||||
|
||||
/**
|
||||
* (optional) The short title used in the views UI.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $short_title = '';
|
||||
|
||||
/**
|
||||
* The base tables on which this wizard is used.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $base_table;
|
||||
|
||||
}
|
191
core/modules/views/src/Controller/ViewAjaxController.php
Normal file
191
core/modules/views/src/Controller/ViewAjaxController.php
Normal file
|
@ -0,0 +1,191 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Controller\ViewAjaxController.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Controller;
|
||||
|
||||
use Drupal\Component\Utility\UrlHelper;
|
||||
use Drupal\Core\Ajax\AjaxResponse;
|
||||
use Drupal\Core\Ajax\ReplaceCommand;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\EventSubscriber\AjaxResponseSubscriber;
|
||||
use Drupal\Core\Path\CurrentPathStack;
|
||||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\Core\Routing\RedirectDestinationInterface;
|
||||
use Drupal\views\Ajax\ScrollTopCommand;
|
||||
use Drupal\views\Ajax\ViewAjaxResponse;
|
||||
use Drupal\views\ViewExecutableFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
|
||||
/**
|
||||
* Defines a controller to load a view via AJAX.
|
||||
*/
|
||||
class ViewAjaxController implements ContainerInjectionInterface {
|
||||
|
||||
/**
|
||||
* The entity storage for views.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* The factory to load a view executable with.
|
||||
*
|
||||
* @var \Drupal\views\ViewExecutableFactory
|
||||
*/
|
||||
protected $executableFactory;
|
||||
|
||||
/**
|
||||
* The renderer.
|
||||
*
|
||||
* @var \Drupal\Core\Render\RendererInterface
|
||||
*/
|
||||
protected $renderer;
|
||||
|
||||
/**
|
||||
* The current path.
|
||||
*
|
||||
* @var \Drupal\Core\Path\CurrentPathStack
|
||||
*/
|
||||
protected $currentPath;
|
||||
|
||||
/**
|
||||
* The redirect destination.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RedirectDestinationInterface
|
||||
*/
|
||||
protected $redirectDestination;
|
||||
|
||||
/**
|
||||
* Constructs a ViewAjaxController object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $storage
|
||||
* The entity storage for views.
|
||||
* @param \Drupal\views\ViewExecutableFactory $executable_factory
|
||||
* The factory to load a view executable with.
|
||||
* @param \Drupal\Core\Render\RendererInterface $renderer
|
||||
* The renderer.
|
||||
* @param \Drupal\Core\Path\CurrentPathStack $current_path
|
||||
* The current path.
|
||||
* @param \Drupal\Core\Routing\RedirectDestinationInterface $redirect_destination
|
||||
* The redirect destination.
|
||||
*/
|
||||
public function __construct(EntityStorageInterface $storage, ViewExecutableFactory $executable_factory, RendererInterface $renderer, CurrentPathStack $current_path, RedirectDestinationInterface $redirect_destination) {
|
||||
$this->storage = $storage;
|
||||
$this->executableFactory = $executable_factory;
|
||||
$this->renderer = $renderer;
|
||||
$this->currentPath = $current_path;
|
||||
$this->redirectDestination = $redirect_destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('entity.manager')->getStorage('view'),
|
||||
$container->get('views.executable'),
|
||||
$container->get('renderer'),
|
||||
$container->get('path.current'),
|
||||
$container->get('redirect.destination')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads and renders a view via AJAX.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request object.
|
||||
*
|
||||
* @return \Drupal\views\Ajax\ViewAjaxResponse
|
||||
* The view response as ajax response.
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
|
||||
* Thrown when the view was not found.
|
||||
*/
|
||||
public function ajaxView(Request $request) {
|
||||
$name = $request->request->get('view_name');
|
||||
$display_id = $request->request->get('view_display_id');
|
||||
if (isset($name) && isset($display_id)) {
|
||||
$args = $request->request->get('view_args');
|
||||
$args = isset($args) && $args !== '' ? explode('/', $args) : array();
|
||||
|
||||
// Arguments can be empty, make sure they are passed on as NULL so that
|
||||
// argument validation is not triggered.
|
||||
$args = array_map(function ($arg) {
|
||||
return ($arg == '' ? NULL : $arg);
|
||||
}, $args);
|
||||
|
||||
$path = $request->request->get('view_path');
|
||||
$dom_id = $request->request->get('view_dom_id');
|
||||
$dom_id = isset($dom_id) ? preg_replace('/[^a-zA-Z0-9_-]+/', '-', $dom_id) : NULL;
|
||||
$pager_element = $request->request->get('pager_element');
|
||||
$pager_element = isset($pager_element) ? intval($pager_element) : NULL;
|
||||
|
||||
$response = new ViewAjaxResponse();
|
||||
|
||||
// Remove all of this stuff from the query of the request so it doesn't
|
||||
// end up in pagers and tablesort URLs.
|
||||
foreach (array('view_name', 'view_display_id', 'view_args', 'view_path', 'view_dom_id', 'pager_element', 'view_base_path', AjaxResponseSubscriber::AJAX_REQUEST_PARAMETER) as $key) {
|
||||
$request->query->remove($key);
|
||||
$request->request->remove($key);
|
||||
}
|
||||
|
||||
// Load the view.
|
||||
if (!$entity = $this->storage->load($name)) {
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
$view = $this->executableFactory->get($entity);
|
||||
if ($view && $view->access($display_id)) {
|
||||
$response->setView($view);
|
||||
// Fix the current path for paging.
|
||||
if (!empty($path)) {
|
||||
$this->currentPath->setPath('/' . $path, $request);
|
||||
}
|
||||
|
||||
// Add all POST data, because AJAX is always a post and many things,
|
||||
// such as tablesorts, exposed filters and paging assume GET.
|
||||
$request_all = $request->request->all();
|
||||
$query_all = $request->query->all();
|
||||
$request->query->replace($request_all + $query_all);
|
||||
|
||||
// Overwrite the destination.
|
||||
// @see the redirect.destination service.
|
||||
$origin_destination = $path;
|
||||
$query = UrlHelper::buildQuery($request->query->all());
|
||||
if ($query != '') {
|
||||
$origin_destination .= '?' . $query;
|
||||
}
|
||||
$this->redirectDestination->set($origin_destination);
|
||||
|
||||
// Override the display's pager_element with the one actually used.
|
||||
if (isset($pager_element)) {
|
||||
$response->addCommand(new ScrollTopCommand(".js-view-dom-id-$dom_id"));
|
||||
$view->displayHandlers->get($display_id)->setOption('pager_element', $pager_element);
|
||||
}
|
||||
// Reuse the same DOM id so it matches that in drupalSettings.
|
||||
$view->dom_id = $dom_id;
|
||||
|
||||
if ($preview = $view->preview($display_id, $args)) {
|
||||
$response->addCommand(new ReplaceCommand(".js-view-dom-id-$dom_id", $preview));
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
else {
|
||||
throw new AccessDeniedHttpException();
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
114
core/modules/views/src/DisplayPluginCollection.php
Normal file
114
core/modules/views/src/DisplayPluginCollection.php
Normal file
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\DisplayPluginCollection.
|
||||
*/
|
||||
|
||||
namespace Drupal\views;
|
||||
|
||||
use Drupal\Component\Plugin\Exception\PluginException;
|
||||
use Drupal\Component\Plugin\PluginManagerInterface;
|
||||
use Drupal\Core\Plugin\DefaultLazyPluginCollection;
|
||||
|
||||
/**
|
||||
* A class which wraps the displays of a view so you can lazy-initialize them.
|
||||
*/
|
||||
class DisplayPluginCollection extends DefaultLazyPluginCollection {
|
||||
|
||||
/**
|
||||
* Stores a reference to the view which has this displays attached.
|
||||
*
|
||||
* @var \Drupal\views\ViewExecutable
|
||||
*/
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $pluginKey = 'display_plugin';
|
||||
|
||||
/**
|
||||
* Constructs a DisplayPluginCollection object.
|
||||
*
|
||||
* @param \Drupal\views\ViewExecutable
|
||||
* The view which has this displays attached.
|
||||
* @param \Drupal\Component\Plugin\PluginManagerInterface $manager
|
||||
* The manager to be used for instantiating plugins.
|
||||
*/
|
||||
public function __construct(ViewExecutable $view, PluginManagerInterface $manager) {
|
||||
parent::__construct($manager, $view->storage->get('display'));
|
||||
|
||||
$this->view = $view;
|
||||
$this->initializePlugin('default');
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructs a DisplayPluginCollection object.
|
||||
*/
|
||||
public function __destruct() {
|
||||
$this->clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return \Drupal\views\Plugin\views\display\DisplayPluginBase
|
||||
*/
|
||||
public function &get($instance_id) {
|
||||
return parent::get($instance_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\Component\Plugin\LazyPluginCollection::clear().
|
||||
*/
|
||||
public function clear() {
|
||||
foreach (array_filter($this->pluginInstances) as $display) {
|
||||
$display->destroy();
|
||||
}
|
||||
|
||||
parent::clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initializePlugin($display_id) {
|
||||
// Retrieve and initialize the new display handler with data.
|
||||
$display = &$this->view->storage->getDisplay($display_id);
|
||||
|
||||
try {
|
||||
$this->configurations[$display_id] = $display;
|
||||
parent::initializePlugin($display_id);
|
||||
}
|
||||
// Catch any plugin exceptions that are thrown. So we can fail nicely if a
|
||||
// display plugin isn't found.
|
||||
catch (PluginException $e) {
|
||||
$message = $e->getMessage();
|
||||
drupal_set_message(t('@message', array('@message' => $message)), 'warning');
|
||||
}
|
||||
|
||||
// If no plugin instance has been created, return NULL.
|
||||
if (empty($this->pluginInstances[$display_id])) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$this->pluginInstances[$display_id]->initDisplay($this->view, $display);
|
||||
// If this is not the default display handler, let it know which is since
|
||||
// it may well use some data from the default.
|
||||
if ($display_id != 'default') {
|
||||
$this->pluginInstances[$display_id]->default_display = $this->pluginInstances['default'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\Component\Plugin\LazyPluginCollection::remove().
|
||||
*/
|
||||
public function remove($instance_id) {
|
||||
$this->get($instance_id)->remove();
|
||||
|
||||
parent::remove($instance_id);
|
||||
}
|
||||
|
||||
|
||||
}
|
100
core/modules/views/src/Element/View.php
Normal file
100
core/modules/views/src/Element/View.php
Normal file
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Element\View.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Element;
|
||||
|
||||
use Drupal\Core\Render\Element\RenderElement;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Provides a render element to display a view.
|
||||
*
|
||||
* @RenderElement("view")
|
||||
*/
|
||||
class View extends RenderElement {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
return array(
|
||||
'#pre_render' => array(
|
||||
array($class, 'preRenderViewElement'),
|
||||
),
|
||||
'#name' => NULL,
|
||||
'#display_id' => 'default',
|
||||
'#arguments' => array(),
|
||||
'#embed' => TRUE,
|
||||
'#cache' => [],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* View element pre render callback.
|
||||
*/
|
||||
public static function preRenderViewElement($element) {
|
||||
if (!isset($element['#view'])) {
|
||||
$view = Views::getView($element['#name']);
|
||||
}
|
||||
else {
|
||||
$view = $element['#view'];
|
||||
}
|
||||
|
||||
$view->element = &$element;
|
||||
// Mark the element as being prerendered, so other code like
|
||||
// \Drupal\views\ViewExecutable::setCurrentPage knows that its no longer
|
||||
// possible to manipulate the $element.
|
||||
$view->element['#pre_rendered'] = TRUE;
|
||||
|
||||
|
||||
if (isset($element['#response'])) {
|
||||
$view->setResponse($element['#response']);
|
||||
}
|
||||
|
||||
if ($view && $view->access($element['#display_id'])) {
|
||||
if (!empty($element['#embed'])) {
|
||||
$element += $view->preview($element['#display_id'], $element['#arguments']);
|
||||
}
|
||||
else {
|
||||
// Add contextual links to the view. We need to attach them to the dummy
|
||||
// $view_array variable, since contextual_preprocess() requires that they
|
||||
// be attached to an array (not an object) in order to process them. For
|
||||
// our purposes, it doesn't matter what we attach them to, since once they
|
||||
// are processed by contextual_preprocess() they will appear in the
|
||||
// $title_suffix variable (which we will then render in
|
||||
// views-view.html.twig).
|
||||
$view->setDisplay($element['#display_id']);
|
||||
// Add the result of the executed view as a child element so any
|
||||
// #pre_render elements for the view will get processed. A #pre_render
|
||||
// element cannot be added to the main element as this is already inside
|
||||
// a #pre_render callback.
|
||||
$element['view_build'] = $view->executeDisplay($element['#display_id'], $element['#arguments']);
|
||||
|
||||
if (isset($element['view_build']['#title'])) {
|
||||
$element['#title'] = &$element['view_build']['#title'];
|
||||
}
|
||||
|
||||
if (empty($view->display_handler->getPluginDefinition()['returns_response'])) {
|
||||
// views_add_contextual_links() needs the following information in
|
||||
// order to be attached to the view.
|
||||
$element['#view_id'] = $view->storage->id();
|
||||
$element['#view_display_show_admin_links'] = $view->getShowAdminLinks();
|
||||
$element['#view_display_plugin_id'] = $view->display_handler->getPluginId();
|
||||
views_add_contextual_links($element, 'view', $view->current_display);
|
||||
}
|
||||
}
|
||||
if (empty($view->display_handler->getPluginDefinition()['returns_response'])) {
|
||||
$element['#attributes']['class'][] = 'views-element-container';
|
||||
$element['#theme_wrappers'] = array('container');
|
||||
}
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Entity\Render\ConfigurableLanguageRenderer.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Entity\Render;
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Drupal\views\ResultRow;
|
||||
use Drupal\views\ViewExecutable;
|
||||
|
||||
/**
|
||||
* Renders entities in a configured language.
|
||||
*/
|
||||
class ConfigurableLanguageRenderer extends EntityTranslationRendererBase {
|
||||
|
||||
/**
|
||||
* A specific language code for rendering if available.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $langcode;
|
||||
|
||||
/**
|
||||
* Constructs a renderer object.
|
||||
*
|
||||
* @param \Drupal\views\ViewExecutable $view
|
||||
* The entity row being rendered.
|
||||
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
|
||||
* The language manager.
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type.
|
||||
* @param string|null $langcode
|
||||
* A specific language code to set, if available.
|
||||
*/
|
||||
public function __construct(ViewExecutable $view, LanguageManagerInterface $language_manager, EntityTypeInterface $entity_type, $langcode) {
|
||||
parent::__construct($view, $language_manager, $entity_type);
|
||||
$this->langcode = $langcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLangcode(ResultRow $row) {
|
||||
return $this->langcode;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Entity\Render\DefaultLanguageRenderer.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Entity\Render;
|
||||
|
||||
use Drupal\views\ResultRow;
|
||||
|
||||
/**
|
||||
* Renders entities in their default language.
|
||||
*/
|
||||
class DefaultLanguageRenderer extends EntityTranslationRendererBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLangcode(ResultRow $row) {
|
||||
return $row->_entity->getUntranslated()->language()->getId();
|
||||
}
|
||||
|
||||
}
|
266
core/modules/views/src/Entity/Render/EntityFieldRenderer.php
Normal file
266
core/modules/views/src/Entity/Render/EntityFieldRenderer.php
Normal file
|
@ -0,0 +1,266 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Entity\Render\EntityFieldRenderer.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Entity\Render;
|
||||
|
||||
use Drupal\Core\Entity\Entity\EntityViewDisplay;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Drupal\views\Plugin\views\field\Field;
|
||||
use Drupal\views\Plugin\views\query\QueryPluginBase;
|
||||
use Drupal\views\ResultRow;
|
||||
use Drupal\views\ViewExecutable;
|
||||
|
||||
/**
|
||||
* Renders entity fields.
|
||||
*
|
||||
* This is used to build render arrays for all entity field values of a view
|
||||
* result set sharing the same relationship. An entity translation renderer is
|
||||
* used internally to handle entity language properly.
|
||||
*/
|
||||
class EntityFieldRenderer extends RendererBase {
|
||||
use EntityTranslationRenderTrait;
|
||||
|
||||
/**
|
||||
* The relationship being handled.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $relationship;
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* A list of indexes of rows whose fields have already been rendered.
|
||||
*
|
||||
* @var int[]
|
||||
*/
|
||||
protected $processedRows = [];
|
||||
|
||||
/**
|
||||
* Constructs an EntityFieldRenderer object.
|
||||
*
|
||||
* @param \Drupal\views\ViewExecutable $view
|
||||
* The view whose fields are being rendered.
|
||||
* @param string $relationship
|
||||
* The relationship to be handled.
|
||||
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
|
||||
* The language manager.
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
*/
|
||||
public function __construct(ViewExecutable $view, $relationship, LanguageManagerInterface $language_manager, EntityTypeInterface $entity_type, EntityManagerInterface $entity_manager) {
|
||||
parent::__construct($view, $language_manager, $entity_type);
|
||||
$this->relationship = $relationship;
|
||||
$this->entityManager = $entity_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheContexts() {
|
||||
return $this->getEntityTranslationRenderer()->getCacheContexts();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getEntityTypeId() {
|
||||
return $this->entityType->id();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEntityManager() {
|
||||
return $this->entityManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
protected function getLanguageManager() {
|
||||
return $this->languageManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getView() {
|
||||
return $this->view;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query(QueryPluginBase $query, $relationship = NULL) {
|
||||
$this->getEntityTranslationRenderer()->query($query, $relationship);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders entity field data.
|
||||
*
|
||||
* @param \Drupal\views\ResultRow $row
|
||||
* A single row of the query result.
|
||||
* @param \Drupal\views\Plugin\views\field\Field $field
|
||||
* (optional) A field to be rendered.
|
||||
*
|
||||
* @return array
|
||||
* A renderable array for the entity data contained in the result row.
|
||||
*/
|
||||
public function render(ResultRow $row, Field $field = NULL) {
|
||||
// The method is called for each field in each result row. In order to
|
||||
// leverage multiple-entity building of formatter output, we build the
|
||||
// render arrays for all fields in all rows on the first call.
|
||||
if (!isset($this->build)) {
|
||||
$this->build = $this->buildFields($this->view->result);
|
||||
}
|
||||
|
||||
if (isset($field)) {
|
||||
$field_id = $field->options['id'];
|
||||
// Pick the render array for the row / field we are being asked to render,
|
||||
// and remove it from $this->build to free memory as we progress.
|
||||
if (isset($this->build[$row->index][$field_id])) {
|
||||
$build = $this->build[$row->index][$field_id];
|
||||
unset($this->build[$row->index][$field_id]);
|
||||
}
|
||||
else {
|
||||
// In the uncommon case where a field gets rendered several times
|
||||
// (typically through direct Views API calls), the pre-computed render
|
||||
// array was removed by the unset() above. We have to manually rebuild
|
||||
// the render array for the row.
|
||||
$build = $this->buildFields([$row])[$row->index][$field_id];
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Same logic as above, in the case where we are being called for a whole
|
||||
// row.
|
||||
if (isset($this->build[$row->index])) {
|
||||
$build = $this->build[$row->index];
|
||||
unset($this->build[$row->index]);
|
||||
}
|
||||
else {
|
||||
$build = $this->buildFields([$row])[$row->index];
|
||||
}
|
||||
}
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the render arrays for all fields of all result rows.
|
||||
*
|
||||
* The output is built using EntityViewDisplay objects to leverage
|
||||
* multiple-entity building and ensure a common code path with regular entity
|
||||
* view.
|
||||
* - Each relationship is handled by a separate EntityFieldRenderer instance,
|
||||
* since it operates on its own set of entities. This also ensures different
|
||||
* entity types are handled separately, as they imply different
|
||||
* relationships.
|
||||
* - Within each relationship, the fields to render are arranged in unique
|
||||
* sets containing each field at most once (an EntityViewDisplay can
|
||||
* only process a field once with given display options, but a View can
|
||||
* contain the same field several times with different display options).
|
||||
* - For each set of fields, entities are processed by bundle, so that
|
||||
* formatters can operate on the proper field definition for the bundle.
|
||||
*
|
||||
* @param \Drupal\views\ResultRow[] $values
|
||||
* An array of all ResultRow objects returned from the query.
|
||||
*
|
||||
* @return array
|
||||
* A renderable array for the fields handled by this renderer.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\Entity\EntityViewDisplay
|
||||
*/
|
||||
protected function buildFields(array $values) {
|
||||
$build = [];
|
||||
|
||||
if ($values && ($field_ids = $this->getRenderableFieldIds())) {
|
||||
$entity_type_id = $this->getEntityTypeId();
|
||||
|
||||
// Collect the entities for the relationship, fetch the right translation,
|
||||
// and group by bundle. For each result row, the corresponding entity can
|
||||
// be obtained from any of the fields handlers, so we arbitrarily use the
|
||||
// first one.
|
||||
$entities_by_bundles = [];
|
||||
$field = $this->view->field[current($field_ids)];
|
||||
foreach ($values as $result_row) {
|
||||
$entity = $field->getEntity($result_row);
|
||||
$entities_by_bundles[$entity->bundle()][$result_row->index] = $this->getEntityTranslation($entity, $result_row);
|
||||
}
|
||||
|
||||
// Determine unique sets of fields that can be processed by the same
|
||||
// display. Fields that appear several times in the View open additional
|
||||
// "overflow" displays.
|
||||
$display_sets = [];
|
||||
foreach ($field_ids as $field_id) {
|
||||
$field = $this->view->field[$field_id];
|
||||
$index = 0;
|
||||
while (isset($display_sets[$index][$field->definition['field_name']])) {
|
||||
$index++;
|
||||
}
|
||||
$display_sets[$index][$field_id] = $field;
|
||||
}
|
||||
|
||||
// For each set of fields, build the output by bundle.
|
||||
foreach ($display_sets as $display_fields) {
|
||||
foreach ($entities_by_bundles as $bundle => $bundle_entities) {
|
||||
// Create the display, and configure the field display options.
|
||||
$display = EntityViewDisplay::create([
|
||||
'targetEntityType' => $entity_type_id,
|
||||
'bundle' => $bundle,
|
||||
'status' => TRUE,
|
||||
]);
|
||||
foreach ($display_fields as $field_id => $field) {
|
||||
$display->setComponent($field->definition['field_name'], [
|
||||
'type' => $field->options['type'],
|
||||
'settings' => $field->options['settings'],
|
||||
]);
|
||||
}
|
||||
// Let the display build the render array for the entities.
|
||||
$display_build = $display->buildMultiple($bundle_entities);
|
||||
// Collect the field render arrays and index them using our internal
|
||||
// row indexes and field IDs.
|
||||
foreach ($display_build as $row_index => $entity_build) {
|
||||
foreach ($display_fields as $field_id => $field) {
|
||||
$build[$row_index][$field_id] = !empty($entity_build[$field->definition['field_name']]) ? $entity_build[$field->definition['field_name']] : [];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of names of entity fields to be rendered.
|
||||
*
|
||||
* @return string[]
|
||||
* An associative array of views fields.
|
||||
*/
|
||||
protected function getRenderableFieldIds() {
|
||||
$field_ids = [];
|
||||
foreach ($this->view->field as $field_id => $field) {
|
||||
if ($field instanceof Field && $field->relationship == $this->relationship) {
|
||||
$field_ids[] = $field_id;
|
||||
}
|
||||
}
|
||||
return $field_ids;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Entity\Render\EntityTranslationRenderTrait.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Entity\Render;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\TypedData\TranslatableInterface;
|
||||
use Drupal\views\Plugin\views\PluginBase;
|
||||
use Drupal\views\ResultRow;
|
||||
|
||||
/**
|
||||
* Trait used to instantiate the view's entity translation renderer.
|
||||
*/
|
||||
trait EntityTranslationRenderTrait {
|
||||
|
||||
/**
|
||||
* The renderer to be used to render the entity row.
|
||||
*
|
||||
* @var \Drupal\views\Entity\Render\EntityTranslationRendererBase
|
||||
*/
|
||||
protected $entityTranslationRenderer;
|
||||
|
||||
/**
|
||||
* Returns the current renderer.
|
||||
*
|
||||
* @return \Drupal\views\Entity\Render\EntityTranslationRendererBase
|
||||
* The configured renderer.
|
||||
*/
|
||||
protected function getEntityTranslationRenderer() {
|
||||
if (!isset($this->entityTranslationRenderer)) {
|
||||
$view = $this->getView();
|
||||
$rendering_language = $view->display_handler->getOption('rendering_language');
|
||||
$langcode = NULL;
|
||||
$dynamic_renderers = array(
|
||||
'***LANGUAGE_entity_translation***' => 'TranslationLanguageRenderer',
|
||||
'***LANGUAGE_entity_default***' => 'DefaultLanguageRenderer',
|
||||
);
|
||||
if (isset($dynamic_renderers[$rendering_language])) {
|
||||
// Dynamic language set based on result rows or instance defaults.
|
||||
$renderer = $dynamic_renderers[$rendering_language];
|
||||
}
|
||||
else {
|
||||
if (strpos($rendering_language, '***LANGUAGE_') !== FALSE) {
|
||||
$langcode = PluginBase::queryLanguageSubstitutions()[$rendering_language];
|
||||
}
|
||||
else {
|
||||
// Specific langcode set.
|
||||
$langcode = $rendering_language;
|
||||
}
|
||||
$renderer = 'ConfigurableLanguageRenderer';
|
||||
}
|
||||
$class = '\Drupal\views\Entity\Render\\' . $renderer;
|
||||
$entity_type = $this->getEntityManager()->getDefinition($this->getEntityTypeId());
|
||||
$this->entityTranslationRenderer = new $class($view, $this->getLanguageManager(), $entity_type, $langcode);
|
||||
}
|
||||
return $this->entityTranslationRenderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entity translation matching the configured row language.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The entity object the field value being processed is attached to.
|
||||
* @param \Drupal\views\ResultRow $row
|
||||
* The result row the field value being processed belongs to.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\FieldableEntityInterface
|
||||
* The entity translation object for the specified row.
|
||||
*/
|
||||
public function getEntityTranslation(EntityInterface $entity, ResultRow $row) {
|
||||
// We assume the same language should be used for all entity fields
|
||||
// belonging to a single row, even if they are attached to different entity
|
||||
// types. Below we apply language fallback to ensure a valid value is always
|
||||
// picked.
|
||||
$translation = $entity;
|
||||
if ($entity instanceof TranslatableInterface && count($entity->getTranslationLanguages()) > 1) {
|
||||
$langcode = $this->getEntityTranslationRenderer()->getLangcode($row);
|
||||
$translation = $this->getEntityManager()->getTranslationFromContext($entity, $langcode);
|
||||
}
|
||||
return $translation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entity type identifier.
|
||||
*
|
||||
* @return string
|
||||
* The entity type identifier.
|
||||
*/
|
||||
abstract public function getEntityTypeId();
|
||||
|
||||
/**
|
||||
* Returns the entity manager.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\EntityManagerInterface
|
||||
* The entity manager.
|
||||
*/
|
||||
abstract protected function getEntityManager();
|
||||
|
||||
/**
|
||||
* Returns the language manager.
|
||||
*
|
||||
* @return \Drupal\Core\Language\LanguageManagerInterface
|
||||
* The language manager.
|
||||
*/
|
||||
abstract protected function getLanguageManager();
|
||||
|
||||
/**
|
||||
* Returns the top object of a view.
|
||||
*
|
||||
* @return \Drupal\views\ViewExecutable
|
||||
* The view object.
|
||||
*/
|
||||
abstract protected function getView();
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Entity\Render\EntityTranslationRendererBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Entity\Render;
|
||||
|
||||
use Drupal\views\Plugin\views\query\QueryPluginBase;
|
||||
use Drupal\views\ResultRow;
|
||||
|
||||
/**
|
||||
* Defines a base class for entity translation renderers.
|
||||
*/
|
||||
abstract class EntityTranslationRendererBase extends RendererBase {
|
||||
|
||||
/**
|
||||
* Returns the language code associated to the given row.
|
||||
*
|
||||
* @param \Drupal\views\ResultRow $row
|
||||
* The result row.
|
||||
*
|
||||
* @return string
|
||||
* A language code.
|
||||
*/
|
||||
abstract public function getLangcode(ResultRow $row);
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query(QueryPluginBase $query, $relationship = NULL) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function preRender(array $result) {
|
||||
$view_builder = $this->view->rowPlugin->entityManager->getViewBuilder($this->entityType->id());
|
||||
|
||||
/** @var \Drupal\views\ResultRow $row */
|
||||
foreach ($result as $row) {
|
||||
// @todo Take relationships into account.
|
||||
// See https://www.drupal.org/node/2457999.
|
||||
$entity = $row->_entity;
|
||||
$entity->view = $this->view;
|
||||
$this->build[$entity->id()] = $view_builder->view($entity, $this->view->rowPlugin->options['view_mode'], $this->getLangcode($row));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(ResultRow $row) {
|
||||
$entity_id = $row->_entity->id();
|
||||
return $this->build[$entity_id];
|
||||
}
|
||||
|
||||
}
|
110
core/modules/views/src/Entity/Render/RendererBase.php
Normal file
110
core/modules/views/src/Entity/Render/RendererBase.php
Normal file
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Entity\Render\RendererBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Entity\Render;
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Drupal\views\Plugin\CacheablePluginInterface;
|
||||
use Drupal\views\Plugin\views\query\QueryPluginBase;
|
||||
use Drupal\views\ResultRow;
|
||||
use Drupal\views\ViewExecutable;
|
||||
|
||||
/**
|
||||
* Defines a base class for entity renderers.
|
||||
*/
|
||||
abstract class RendererBase implements CacheablePluginInterface {
|
||||
|
||||
/**
|
||||
* The view executable wrapping the view storage entity.
|
||||
*
|
||||
* @var \Drupal\views\ViewExecutable
|
||||
*/
|
||||
public $view;
|
||||
|
||||
/**
|
||||
* The language manager.
|
||||
*
|
||||
* @var \Drupal\Core\Language\LanguageManagerInterface
|
||||
*/
|
||||
protected $languageManager;
|
||||
|
||||
/**
|
||||
* The type of the entity being rendered.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $entityType;
|
||||
|
||||
/**
|
||||
* Contains an array of render arrays, one for each rendered entity.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $build;
|
||||
|
||||
/**
|
||||
* Constructs a renderer object.
|
||||
*
|
||||
* @param \Drupal\views\ViewExecutable $view
|
||||
* The entity row being rendered.
|
||||
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
|
||||
* The language manager.
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type.
|
||||
*/
|
||||
public function __construct(ViewExecutable $view, LanguageManagerInterface $language_manager, EntityTypeInterface $entity_type) {
|
||||
$this->view = $view;
|
||||
$this->languageManager = $language_manager;
|
||||
$this->entityType = $entity_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCacheable() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheContexts() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Alters the query if needed.
|
||||
*
|
||||
* @param \Drupal\views\Plugin\views\query\QueryPluginBase $query
|
||||
* The query to alter.
|
||||
* @param string $relationship
|
||||
* (optional) The relationship, used by a field.
|
||||
*/
|
||||
abstract public function query(QueryPluginBase $query, $relationship = NULL);
|
||||
|
||||
/**
|
||||
* Runs before each entity is rendered.
|
||||
*
|
||||
* @param $result
|
||||
* The full array of results from the query.
|
||||
*/
|
||||
public function preRender(array $result) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders entity data.
|
||||
*
|
||||
* @param \Drupal\views\ResultRow $row
|
||||
* A single row of the query result.
|
||||
*
|
||||
* @return array
|
||||
* A renderable array for the entity data contained in the result row.
|
||||
*/
|
||||
abstract public function render(ResultRow $row);
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Entity\Render\TranslationLanguageRenderer.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Entity\Render;
|
||||
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\views\Plugin\views\query\QueryPluginBase;
|
||||
use Drupal\views\ResultRow;
|
||||
|
||||
/**
|
||||
* Renders entity translations in their row language.
|
||||
*/
|
||||
class TranslationLanguageRenderer extends EntityTranslationRendererBase {
|
||||
|
||||
/**
|
||||
* Stores the field alias of the langcode column.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $langcodeAlias;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query(QueryPluginBase $query, $relationship = NULL) {
|
||||
// There is no point in getting the language, in case the site is not
|
||||
// multilingual.
|
||||
if (!$this->languageManager->isMultilingual()) {
|
||||
return;
|
||||
}
|
||||
// If the data table is defined, we use the translation language as render
|
||||
// language, otherwise we fall back to the default entity language, which is
|
||||
// stored in the revision table for revisionable entity types.
|
||||
$langcode_key = $this->entityType->getKey('langcode');
|
||||
foreach (array('data_table', 'revision_table', 'base_table') as $key) {
|
||||
if ($table = $this->entityType->get($key)) {
|
||||
$table_alias = $query->ensureTable($table, $relationship);
|
||||
$this->langcodeAlias = $query->addField($table_alias, $langcode_key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function preRender(array $result) {
|
||||
$view_builder = $this->view->rowPlugin->entityManager->getViewBuilder($this->entityType->id());
|
||||
|
||||
/** @var \Drupal\views\ResultRow $row */
|
||||
foreach ($result as $row) {
|
||||
$entity = $row->_entity;
|
||||
$entity->view = $this->view;
|
||||
$langcode = $this->getLangcode($row);
|
||||
$this->build[$entity->id()][$langcode] = $view_builder->view($entity, $this->view->rowPlugin->options['view_mode'], $this->getLangcode($row));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(ResultRow $row) {
|
||||
$entity_id = $row->_entity->id();
|
||||
$langcode = $this->getLangcode($row);
|
||||
return $this->build[$entity_id][$langcode];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLangcode(ResultRow $row) {
|
||||
return isset($row->{$this->langcodeAlias}) ? $row->{$this->langcodeAlias} : $this->languageManager->getDefaultLanguage()->getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheContexts() {
|
||||
return ['languages:' . LanguageInterface::TYPE_CONTENT];
|
||||
}
|
||||
}
|
472
core/modules/views/src/Entity/View.php
Normal file
472
core/modules/views/src/Entity/View.php
Normal file
|
@ -0,0 +1,472 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Entity\View.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Entity;
|
||||
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Config\Entity\ConfigEntityBase;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\views\ViewEntityInterface;
|
||||
|
||||
/**
|
||||
* Defines a View configuration entity class.
|
||||
*
|
||||
* @ConfigEntityType(
|
||||
* id = "view",
|
||||
* label = @Translation("View", context = "View entity type"),
|
||||
* handlers = {
|
||||
* "access" = "Drupal\views\ViewAccessControlHandler"
|
||||
* },
|
||||
* admin_permission = "administer views",
|
||||
* entity_keys = {
|
||||
* "id" = "id",
|
||||
* "label" = "label",
|
||||
* "status" = "status"
|
||||
* },
|
||||
* config_export = {
|
||||
* "id",
|
||||
* "label",
|
||||
* "module",
|
||||
* "description",
|
||||
* "tag",
|
||||
* "base_table",
|
||||
* "base_field",
|
||||
* "core",
|
||||
* "display",
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class View extends ConfigEntityBase implements ViewEntityInterface {
|
||||
|
||||
/**
|
||||
* The name of the base table this view will use.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $base_table = 'node';
|
||||
|
||||
/**
|
||||
* The unique ID of the view.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $id = NULL;
|
||||
|
||||
/**
|
||||
* The label of the view.
|
||||
*/
|
||||
protected $label;
|
||||
|
||||
/**
|
||||
* The description of the view, which is used only in the interface.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '';
|
||||
|
||||
/**
|
||||
* The "tags" of a view.
|
||||
*
|
||||
* The tags are stored as a single string, though it is used as multiple tags
|
||||
* for example in the views overview.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $tag = '';
|
||||
|
||||
/**
|
||||
* The core version the view was created for.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $core = \Drupal::CORE_COMPATIBILITY;
|
||||
|
||||
/**
|
||||
* Stores all display handlers of this view.
|
||||
*
|
||||
* An array containing Drupal\views\Plugin\views\display\DisplayPluginBase
|
||||
* objects.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $display = array();
|
||||
|
||||
/**
|
||||
* The name of the base field to use.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $base_field = 'nid';
|
||||
|
||||
/**
|
||||
* Stores a reference to the executable version of this view.
|
||||
*
|
||||
* @var \Drupal\views\ViewExecutable
|
||||
*/
|
||||
protected $executable;
|
||||
|
||||
/**
|
||||
* The module implementing this view.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $module = 'views';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getExecutable() {
|
||||
// Ensure that an executable View is available.
|
||||
if (!isset($this->executable)) {
|
||||
$this->executable = Views::executableFactory()->get($this);
|
||||
}
|
||||
|
||||
return $this->executable;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createDuplicate() {
|
||||
$duplicate = parent::createDuplicate();
|
||||
unset($duplicate->executable);
|
||||
return $duplicate;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function label() {
|
||||
if (!$label = $this->get('label')) {
|
||||
$label = $this->id();
|
||||
}
|
||||
return $label;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addDisplay($plugin_id = 'page', $title = NULL, $id = NULL) {
|
||||
if (empty($plugin_id)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$plugin = Views::pluginManager('display')->getDefinition($plugin_id);
|
||||
|
||||
if (empty($plugin)) {
|
||||
$plugin['title'] = t('Broken');
|
||||
}
|
||||
|
||||
if (empty($id)) {
|
||||
$id = $this->generateDisplayId($plugin_id);
|
||||
|
||||
// Generate a unique human-readable name by inspecting the counter at the
|
||||
// end of the previous display ID, e.g., 'page_1'.
|
||||
if ($id !== 'default') {
|
||||
preg_match("/[0-9]+/", $id, $count);
|
||||
$count = $count[0];
|
||||
}
|
||||
else {
|
||||
$count = '';
|
||||
}
|
||||
|
||||
if (empty($title)) {
|
||||
// If there is no title provided, use the plugin title, and if there are
|
||||
// multiple displays, append the count.
|
||||
$title = $plugin['title'];
|
||||
if ($count > 1) {
|
||||
$title .= ' ' . $count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$display_options = array(
|
||||
'display_plugin' => $plugin_id,
|
||||
'id' => $id,
|
||||
// Cast the display title to a string since it is an object.
|
||||
// @see \Drupal\Core\StringTranslation\TranslationWrapper
|
||||
'display_title' => (string) $title,
|
||||
'position' => $id === 'default' ? 0 : count($this->display),
|
||||
'display_options' => array(),
|
||||
);
|
||||
|
||||
// Add the display options to the view.
|
||||
$this->display[$id] = $display_options;
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a display ID of a certain plugin type.
|
||||
*
|
||||
* @param string $plugin_id
|
||||
* Which plugin should be used for the new display ID.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generateDisplayId($plugin_id) {
|
||||
// 'default' is singular and is unique, so just go with 'default'
|
||||
// for it. For all others, start counting.
|
||||
if ($plugin_id == 'default') {
|
||||
return 'default';
|
||||
}
|
||||
// Initial ID.
|
||||
$id = $plugin_id . '_1';
|
||||
$count = 1;
|
||||
|
||||
// Loop through IDs based upon our style plugin name until
|
||||
// we find one that is unused.
|
||||
while (!empty($this->display[$id])) {
|
||||
$id = $plugin_id . '_' . ++$count;
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function &getDisplay($display_id) {
|
||||
return $this->display[$display_id];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function duplicateDisplayAsType($old_display_id, $new_display_type) {
|
||||
$executable = $this->getExecutable();
|
||||
$display = $executable->newDisplay($new_display_type);
|
||||
$new_display_id = $display->display['id'];
|
||||
$displays = $this->get('display');
|
||||
|
||||
// Let the display title be generated by the addDisplay method and set the
|
||||
// right display plugin, but keep the rest from the original display.
|
||||
$display_duplicate = $displays[$old_display_id];
|
||||
unset($display_duplicate['display_title']);
|
||||
unset($display_duplicate['display_plugin']);
|
||||
|
||||
$displays[$new_display_id] = NestedArray::mergeDeep($displays[$new_display_id], $display_duplicate);
|
||||
$displays[$new_display_id]['id'] = $new_display_id;
|
||||
|
||||
// First set the displays.
|
||||
$this->set('display', $displays);
|
||||
|
||||
// Ensure that we just copy display options, which are provided by the new
|
||||
// display plugin.
|
||||
$executable->setDisplay($new_display_id);
|
||||
|
||||
$executable->display_handler->filterByDefinedOptions($displays[$new_display_id]['display_options']);
|
||||
// Update the display settings.
|
||||
$this->set('display', $displays);
|
||||
|
||||
return $new_display_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function calculateDependencies() {
|
||||
parent::calculateDependencies();
|
||||
|
||||
// Ensure that the view is dependant on the module that implements the view.
|
||||
$this->addDependency('module', $this->module);
|
||||
|
||||
$executable = $this->getExecutable();
|
||||
$executable->initDisplay();
|
||||
$executable->initStyle();
|
||||
|
||||
foreach ($executable->displayHandlers as $display) {
|
||||
// Calculate the dependencies each display has.
|
||||
$this->calculatePluginDependencies($display);
|
||||
}
|
||||
|
||||
return $this->dependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function preSave(EntityStorageInterface $storage) {
|
||||
parent::preSave($storage);
|
||||
|
||||
// Sort the displays.
|
||||
$display = $this->get('display');
|
||||
ksort($display);
|
||||
$this->set('display', array('default' => $display['default']) + $display);
|
||||
|
||||
// @todo Check whether isSyncing is needed.
|
||||
if (!$this->isSyncing()) {
|
||||
$this->addCacheMetadata();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills in the cache metadata of this view.
|
||||
*
|
||||
* Cache metadata is set per view and per display, and ends up being stored in
|
||||
* the view's configuration. This allows Views to determine very efficiently:
|
||||
* - whether a view is cacheable at all
|
||||
* - what the cache key for a given view should be
|
||||
*
|
||||
* In other words: this allows us to do the (expensive) work of initializing
|
||||
* Views plugins and handlers to determine their effect on the cacheability of
|
||||
* a view at save time rather than at runtime.
|
||||
*/
|
||||
protected function addCacheMetadata() {
|
||||
$executable = $this->getExecutable();
|
||||
|
||||
$current_display = $executable->current_display;
|
||||
$displays = $this->get('display');
|
||||
foreach (array_keys($displays) as $display_id) {
|
||||
$display =& $this->getDisplay($display_id);
|
||||
$executable->setDisplay($display_id);
|
||||
|
||||
list($display['cache_metadata']['cacheable'], $display['cache_metadata']['contexts']) = $executable->getDisplay()->calculateCacheMetadata();
|
||||
// Always include at least the 'languages:' context as there will most
|
||||
// probably be translatable strings in the view output.
|
||||
$display['cache_metadata']['contexts'] = Cache::mergeContexts($display['cache_metadata']['contexts'], ['languages:' . LanguageInterface::TYPE_INTERFACE]);
|
||||
}
|
||||
// Restore the previous active display.
|
||||
$executable->setDisplay($current_display);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function postSave(EntityStorageInterface $storage, $update = TRUE) {
|
||||
parent::postSave($storage, $update);
|
||||
|
||||
// @todo Remove if views implements a view_builder controller.
|
||||
views_invalidate_cache();
|
||||
$this->invalidateCaches();
|
||||
|
||||
// Rebuild the router if this is a new view, or it's status changed.
|
||||
if (!isset($this->original) || ($this->status() != $this->original->status())) {
|
||||
\Drupal::service('router.builder')->setRebuildNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function postLoad(EntityStorageInterface $storage, array &$entities) {
|
||||
parent::postLoad($storage, $entities);
|
||||
foreach ($entities as $entity) {
|
||||
$entity->mergeDefaultDisplaysOptions();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function preCreate(EntityStorageInterface $storage, array &$values) {
|
||||
parent::preCreate($storage, $values);
|
||||
|
||||
// If there is no information about displays available add at least the
|
||||
// default display.
|
||||
$values += array(
|
||||
'display' => array(
|
||||
'default' => array(
|
||||
'display_plugin' => 'default',
|
||||
'id' => 'default',
|
||||
'display_title' => 'Master',
|
||||
'position' => 0,
|
||||
'display_options' => array(),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function postCreate(EntityStorageInterface $storage) {
|
||||
parent::postCreate($storage);
|
||||
|
||||
$this->mergeDefaultDisplaysOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function preDelete(EntityStorageInterface $storage, array $entities) {
|
||||
parent::preDelete($storage, $entities);
|
||||
|
||||
// Call the remove() hook on the individual displays.
|
||||
/** @var \Drupal\views\ViewEntityInterface $entity */
|
||||
foreach ($entities as $entity) {
|
||||
$executable = Views::executableFactory()->get($entity);
|
||||
foreach ($entity->get('display') as $display_id => $display) {
|
||||
$executable->setDisplay($display_id);
|
||||
$executable->getDisplay()->remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function postDelete(EntityStorageInterface $storage, array $entities) {
|
||||
parent::postDelete($storage, $entities);
|
||||
|
||||
$tempstore = \Drupal::service('user.shared_tempstore')->get('views');
|
||||
foreach ($entities as $entity) {
|
||||
$tempstore->delete($entity->id());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function mergeDefaultDisplaysOptions() {
|
||||
$displays = array();
|
||||
foreach ($this->get('display') as $key => $options) {
|
||||
$options += array(
|
||||
'display_options' => array(),
|
||||
'display_plugin' => NULL,
|
||||
'id' => NULL,
|
||||
'display_title' => '',
|
||||
'position' => NULL,
|
||||
);
|
||||
// Add the defaults for the display.
|
||||
$displays[$key] = $options;
|
||||
}
|
||||
$this->set('display', $displays);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isInstallable() {
|
||||
$table_definition = \Drupal::service('views.views_data')->get($this->base_table);
|
||||
// Check whether the base table definition exists and contains a base table
|
||||
// definition. For example, taxonomy_views_data_alter() defines
|
||||
// node_field_data even if it doesn't exist as a base table.
|
||||
return $table_definition && isset($table_definition['table']['base']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __sleep() {
|
||||
$keys = parent::__sleep();
|
||||
unset($keys[array_search('executable', $keys)]);
|
||||
return $keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates cache tags.
|
||||
*/
|
||||
public function invalidateCaches() {
|
||||
// Invalidate cache tags for cached rows.
|
||||
$tags = $this->getCacheTags();
|
||||
\Drupal::service('cache_tags.invalidator')->invalidateTags($tags);
|
||||
}
|
||||
|
||||
}
|
559
core/modules/views/src/EntityViewsData.php
Normal file
559
core/modules/views/src/EntityViewsData.php
Normal file
|
@ -0,0 +1,559 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\EntityViewsData.
|
||||
*/
|
||||
|
||||
namespace Drupal\views;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityType;
|
||||
use Drupal\Core\Entity\EntityHandlerInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Entity\Sql\SqlEntityStorageInterface;
|
||||
use Drupal\Core\Entity\Sql\TableMappingInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\Core\StringTranslation\TranslationInterface;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides generic views integration for entities.
|
||||
*/
|
||||
class EntityViewsData implements EntityHandlerInterface, EntityViewsDataInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* Entity type for this views controller instance.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeInterface
|
||||
*/
|
||||
protected $entityType;
|
||||
|
||||
/**
|
||||
* The storage used for this entity type.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\Sql\SqlEntityStorageInterface
|
||||
*/
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The translation manager.
|
||||
*
|
||||
* @var \Drupal\Core\StringTranslation\TranslationInterface
|
||||
*/
|
||||
protected $translationManager;
|
||||
|
||||
/**
|
||||
* The field storage definitions for all base fields of the entity type.
|
||||
*
|
||||
* @var \Drupal\Core\Field\FieldStorageDefinitionInterface[]
|
||||
*/
|
||||
protected $fieldStorageDefinitions;
|
||||
|
||||
/**
|
||||
* Constructs an EntityViewsData object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type to provide views integration for.
|
||||
* @param \Drupal\Core\Entity\Sql\SqlEntityStorageInterface $storage_controller
|
||||
* The storage controller used for this entity type.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
* @param \Drupal\Core\StringTranslation\TranslationInterface $translation_manager
|
||||
* The translation manager.
|
||||
*/
|
||||
function __construct(EntityTypeInterface $entity_type, SqlEntityStorageInterface $storage_controller, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, TranslationInterface $translation_manager) {
|
||||
$this->entityType = $entity_type;
|
||||
$this->entityManager = $entity_manager;
|
||||
$this->storage = $storage_controller;
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->setStringTranslation($translation_manager);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
|
||||
return new static(
|
||||
$entity_type,
|
||||
$container->get('entity.manager')->getStorage($entity_type->id()),
|
||||
$container->get('entity.manager'),
|
||||
$container->get('module_handler'),
|
||||
$container->get('string_translation'),
|
||||
$container->get('typed_data_manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the field storage definitions.
|
||||
*
|
||||
* @return \Drupal\Core\Field\FieldStorageDefinitionInterface[]
|
||||
*/
|
||||
protected function getFieldStorageDefinitions() {
|
||||
if (!isset($this->fieldStorageDefinitions)) {
|
||||
$this->fieldStorageDefinitions = $this->entityManager->getFieldStorageDefinitions($this->entityType->id());
|
||||
}
|
||||
return $this->fieldStorageDefinitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getViewsData() {
|
||||
$data = [];
|
||||
|
||||
$base_table = $this->entityType->getBaseTable();
|
||||
$base_field = $this->entityType->getKey('id');
|
||||
$data_table = $this->entityType->getDataTable();
|
||||
$revision_table = $this->entityType->getRevisionTable();
|
||||
$revision_data_table = $this->entityType->getRevisionDataTable();
|
||||
$revision_field = $this->entityType->getKey('revision');
|
||||
|
||||
// Setup base information of the views data.
|
||||
$data[$base_table]['table']['group'] = $this->entityType->getLabel();
|
||||
$data[$base_table]['table']['provider'] = $this->entityType->getProvider();
|
||||
|
||||
$views_base_table = $base_table;
|
||||
if ($data_table) {
|
||||
$views_base_table = $data_table;
|
||||
}
|
||||
$data[$views_base_table]['table']['base'] = [
|
||||
'field' => $base_field,
|
||||
'title' => $this->entityType->getLabel(),
|
||||
'cache_contexts' => $this->entityType->getListCacheContexts(),
|
||||
];
|
||||
$data[$base_table]['table']['entity revision'] = FALSE;
|
||||
|
||||
if ($label_key = $this->entityType->getKey('label')) {
|
||||
if ($data_table) {
|
||||
$data[$views_base_table]['table']['base']['defaults'] = array(
|
||||
'field' => $label_key,
|
||||
'table' => $data_table,
|
||||
);
|
||||
}
|
||||
else {
|
||||
$data[$views_base_table]['table']['base']['defaults'] = array(
|
||||
'field' => $label_key,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$data[$base_table]['operations'] = array(
|
||||
'field' => array(
|
||||
'title' => $this->t('Operations links'),
|
||||
'help' => $this->t('Provides links to perform entity operations.'),
|
||||
'id' => 'entity_operations',
|
||||
),
|
||||
);
|
||||
|
||||
// Setup relations to the revisions/property data.
|
||||
if ($data_table) {
|
||||
$data[$base_table]['table']['join'][$data_table] = [
|
||||
'left_field' => $base_field,
|
||||
'field' => $base_field,
|
||||
'type' => 'INNER'
|
||||
];
|
||||
$data[$data_table]['table']['group'] = $this->entityType->getLabel();
|
||||
$data[$data_table]['table']['provider'] = $this->entityType->getProvider();
|
||||
$data[$data_table]['table']['entity revision'] = FALSE;
|
||||
}
|
||||
if ($revision_table) {
|
||||
$data[$revision_table]['table']['group'] = $this->t('@entity_type revision', ['@entity_type' => $this->entityType->getLabel()]);
|
||||
$data[$revision_table]['table']['provider'] = $this->entityType->getProvider();
|
||||
|
||||
$views_revision_base_table = $revision_table;
|
||||
if ($revision_data_table) {
|
||||
$views_revision_base_table = $revision_data_table;
|
||||
}
|
||||
$data[$views_revision_base_table]['table']['entity revision'] = TRUE;
|
||||
$data[$views_revision_base_table]['table']['base'] = array(
|
||||
'field' => $revision_field,
|
||||
'title' => $this->t('@entity_type revisions', array('@entity_type' => $this->entityType->getLabel())),
|
||||
);
|
||||
// Join the revision table to the base table.
|
||||
$data[$views_revision_base_table]['table']['join'][$views_base_table] = array(
|
||||
'left_field' => $revision_field,
|
||||
'field' => $revision_field,
|
||||
'type' => 'INNER',
|
||||
);
|
||||
|
||||
if ($revision_data_table) {
|
||||
$data[$revision_data_table]['table']['group'] = $this->t('@entity_type revision', ['@entity_type' => $this->entityType->getLabel()]);
|
||||
$data[$revision_data_table]['table']['entity revision'] = TRUE;
|
||||
|
||||
$data[$revision_data_table]['table']['join'][$revision_table] = array(
|
||||
'left_field' => $revision_field,
|
||||
'field' => $revision_field,
|
||||
'type' => 'INNER',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->addEntityLinks($data[$base_table]);
|
||||
|
||||
// Load all typed data definitions of all fields. This should cover each of
|
||||
// the entity base, revision, data tables.
|
||||
$field_definitions = $this->entityManager->getBaseFieldDefinitions($this->entityType->id());
|
||||
if ($table_mapping = $this->storage->getTableMapping()) {
|
||||
// Iterate over each table we have so far and collect field data for each.
|
||||
// Based on whether the field is in the field_definitions provided by the
|
||||
// entity manager.
|
||||
// @todo We should better just rely on information coming from the entity
|
||||
// storage.
|
||||
// @todo https://www.drupal.org/node/2337511
|
||||
foreach ($table_mapping->getTableNames() as $table) {
|
||||
foreach ($table_mapping->getFieldNames($table) as $field_name) {
|
||||
$this->mapFieldDefinition($table, $field_name, $field_definitions[$field_name], $table_mapping, $data[$table]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the entity type key to each table generated.
|
||||
$entity_type_id = $this->entityType->id();
|
||||
array_walk($data, function(&$table_data) use ($entity_type_id){
|
||||
$table_data['table']['entity type'] = $entity_type_id;
|
||||
});
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the entity links in case corresponding link templates exist.
|
||||
*
|
||||
* @param array $data
|
||||
* The views data of the base table.
|
||||
*/
|
||||
protected function addEntityLinks(array &$data) {
|
||||
$entity_type_id = $this->entityType->id();
|
||||
$t_arguments = ['@entity_type_label' => $this->entityType->getLabel()];
|
||||
if ($this->entityType->hasLinkTemplate('canonical')) {
|
||||
$data['view_' . $entity_type_id] = [
|
||||
'field' => [
|
||||
'title' => $this->t('Link to @entity_type_label', $t_arguments),
|
||||
'help' => $this->t('Provide a view link to the @entity_type_label.', $t_arguments),
|
||||
'id' => 'entity_link',
|
||||
],
|
||||
];
|
||||
}
|
||||
if ($this->entityType->hasLinkTemplate('edit-form')) {
|
||||
$data['edit_' . $entity_type_id] = [
|
||||
'field' => [
|
||||
'title' => $this->t('Link to edit @entity_type_label', $t_arguments),
|
||||
'help' => $this->t('Provide an edit link to the @entity_type_label.', $t_arguments),
|
||||
'id' => 'entity_link_edit',
|
||||
],
|
||||
];
|
||||
}
|
||||
if ($this->entityType->hasLinkTemplate('delete-form')) {
|
||||
$data['delete_' . $entity_type_id] = [
|
||||
'field' => [
|
||||
'title' => $this->t('Link to delete @entity_type_label', $t_arguments),
|
||||
'help' => $this->t('Provide a delete link to the @entity_type_label.', $t_arguments),
|
||||
'id' => 'entity_link_delete',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the views data for a single field onto the views data.
|
||||
*
|
||||
* @param string $table
|
||||
* The table of the field to handle.
|
||||
* @param string $field_name
|
||||
* The name of the field to handle.
|
||||
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
|
||||
* The field definition defined in Entity::baseFieldDefinitions()
|
||||
* @param \Drupal\Core\Entity\Sql\TableMappingInterface $table_mapping
|
||||
* The table mapping information
|
||||
* @param array $table_data
|
||||
* A reference to a specific entity table (for example data_table) inside
|
||||
* the views data.
|
||||
*/
|
||||
protected function mapFieldDefinition($table, $field_name, FieldDefinitionInterface $field_definition, TableMappingInterface $table_mapping, &$table_data) {
|
||||
// Create a dummy instance to retrieve property definitions.
|
||||
$field_column_mapping = $table_mapping->getColumnNames($field_name);
|
||||
$field_schema = $this->getFieldStorageDefinitions()[$field_name]->getSchema();
|
||||
|
||||
$field_definition_type = $field_definition->getType();
|
||||
// Add all properties to views table data. We need an entry for each
|
||||
// column of each field, with the first one given special treatment.
|
||||
// @todo Introduce concept of the "main" column for a field, rather than
|
||||
// assuming the first one is the main column. See also what the
|
||||
// mapSingleFieldViewsData() method does with $first.
|
||||
$multiple = (count($field_column_mapping) > 1);
|
||||
$first = TRUE;
|
||||
foreach ($field_column_mapping as $field_column_name => $schema_field_name) {
|
||||
$views_field_name = ($multiple) ? $field_name . '__' . $field_column_name : $field_name;
|
||||
$table_data[$views_field_name] = $this->mapSingleFieldViewsData($table, $field_name, $field_definition_type, $field_column_name, $field_schema['columns'][$field_column_name]['type'], $first, $field_definition);
|
||||
|
||||
$table_data[$views_field_name]['entity field'] = $field_name;
|
||||
$first = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the views data for a given data type and schema field.
|
||||
*
|
||||
* @param string $table
|
||||
* The table of the field to handle.
|
||||
* @param string $field_name
|
||||
* The machine name of the field being processed.
|
||||
* @param string $field_type
|
||||
* The type of field being handled.
|
||||
* @param string $column_name
|
||||
* For fields containing multiple columns, the column name being processed.
|
||||
* @param string $column_type
|
||||
* Within the field, the column type being handled.
|
||||
* @param bool $first
|
||||
* TRUE if this is the first column within the field.
|
||||
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
|
||||
* The field definition.
|
||||
*
|
||||
* @return array
|
||||
* The modified views data field definition.
|
||||
*/
|
||||
protected function mapSingleFieldViewsData($table, $field_name, $field_type, $column_name, $column_type, $first, FieldDefinitionInterface $field_definition) {
|
||||
$views_field = array();
|
||||
|
||||
// Provide a nicer, less verbose label for the first column within a field.
|
||||
// @todo Introduce concept of the "main" column for a field, rather than
|
||||
// assuming the first one is the main column.
|
||||
if ($first) {
|
||||
$views_field['title'] = $field_definition->getLabel();
|
||||
}
|
||||
else {
|
||||
$views_field['title'] = $field_definition->getLabel() . " ($column_name)";
|
||||
}
|
||||
|
||||
if ($description = $field_definition->getDescription()) {
|
||||
$views_field['help'] = $description;
|
||||
}
|
||||
|
||||
// Set up the field, sort, argument, and filters, based on
|
||||
// the column and/or field data type.
|
||||
// @todo Allow field types to customize this.
|
||||
// @see https://www.drupal.org/node/2337515
|
||||
switch ($field_type) {
|
||||
// Special case a few field types.
|
||||
case 'timestamp':
|
||||
case 'created':
|
||||
case 'changed':
|
||||
$views_field['field']['id'] = 'date';
|
||||
$views_field['argument']['id'] = 'date';
|
||||
$views_field['filter']['id'] = 'date';
|
||||
$views_field['sort']['id'] = 'date';
|
||||
break;
|
||||
|
||||
case 'language':
|
||||
$views_field['field']['id'] = 'field';
|
||||
$views_field['argument']['id'] = 'language';
|
||||
$views_field['filter']['id'] = 'language';
|
||||
$views_field['sort']['id'] = 'standard';
|
||||
break;
|
||||
|
||||
case 'boolean':
|
||||
$views_field['field']['id'] = 'field';
|
||||
$views_field['argument']['id'] = 'numeric';
|
||||
$views_field['filter']['id'] = 'boolean';
|
||||
$views_field['sort']['id'] = 'standard';
|
||||
break;
|
||||
|
||||
case 'uri':
|
||||
// Let's render URIs as URIs by default, not links.
|
||||
$views_field['field']['id'] = 'field';
|
||||
$views_field['field']['default_formatter'] = 'string';
|
||||
|
||||
$views_field['argument']['id'] = 'string';
|
||||
$views_field['filter']['id'] = 'string';
|
||||
$views_field['sort']['id'] = 'standard';
|
||||
break;
|
||||
|
||||
case 'text':
|
||||
case 'text_with_summary':
|
||||
// Treat these three long text fields the same.
|
||||
$field_type = 'text_long';
|
||||
// Intentional fall-through here to the default processing!
|
||||
|
||||
default:
|
||||
// For most fields, the field type is generic enough to just use
|
||||
// the column type to determine the filters etc.
|
||||
switch ($column_type) {
|
||||
|
||||
case 'int':
|
||||
case 'integer':
|
||||
case 'smallint':
|
||||
case 'tinyint':
|
||||
case 'mediumint':
|
||||
case 'float':
|
||||
case 'double':
|
||||
case 'decimal':
|
||||
$views_field['field']['id'] = 'field';
|
||||
$views_field['argument']['id'] = 'numeric';
|
||||
$views_field['filter']['id'] = 'numeric';
|
||||
$views_field['sort']['id'] = 'standard';
|
||||
break;
|
||||
|
||||
case 'char':
|
||||
case 'string':
|
||||
case 'varchar':
|
||||
case 'varchar_ascii':
|
||||
case 'tinytext':
|
||||
case 'text':
|
||||
case 'mediumtext':
|
||||
case 'longtext':
|
||||
$views_field['field']['id'] = 'field';
|
||||
$views_field['argument']['id'] = 'string';
|
||||
$views_field['filter']['id'] = 'string';
|
||||
$views_field['sort']['id'] = 'standard';
|
||||
break;
|
||||
|
||||
default:
|
||||
$views_field['field']['id'] = 'field';
|
||||
$views_field['argument']['id'] = 'standard';
|
||||
$views_field['filter']['id'] = 'standard';
|
||||
$views_field['sort']['id'] = 'standard';
|
||||
}
|
||||
}
|
||||
|
||||
// Do post-processing for a few field types.
|
||||
|
||||
$process_method = 'processViewsDataFor' . Container::camelize($field_type);
|
||||
if (method_exists($this, $process_method)) {
|
||||
$this->{$process_method}($table, $field_definition, $views_field, $column_name);
|
||||
}
|
||||
|
||||
return $views_field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the views data for a language field.
|
||||
*
|
||||
* @param string $table
|
||||
* The table the language field is added to.
|
||||
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
|
||||
* The field definition.
|
||||
* @param array $views_field
|
||||
* The views field data.
|
||||
* @param string $field_column_name
|
||||
* The field column being processed.
|
||||
*/
|
||||
protected function processViewsDataForLanguage($table, FieldDefinitionInterface $field_definition, array &$views_field, $field_column_name) {
|
||||
// Apply special titles for the langcode field.
|
||||
if ($field_definition->getName() == $this->entityType->getKey('langcode')) {
|
||||
if ($table == $this->entityType->getDataTable() || $table == $this->entityType->getRevisionDataTable()) {
|
||||
$views_field['title'] = $this->t('Translation language');
|
||||
}
|
||||
if ($table == $this->entityType->getBaseTable() || $table == $this->entityType->getRevisionTable()) {
|
||||
$views_field['title'] = $this->t('Original language');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the views data for an entity reference field.
|
||||
*
|
||||
* @param string $table
|
||||
* The table the language field is added to.
|
||||
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
|
||||
* The field definition.
|
||||
* @param array $views_field
|
||||
* The views field data.
|
||||
* @param string $field_column_name
|
||||
* The field column being processed.
|
||||
*/
|
||||
protected function processViewsDataForEntityReference($table, FieldDefinitionInterface $field_definition, array &$views_field, $field_column_name) {
|
||||
|
||||
// @todo Should the actual field handler respect that this just renders a
|
||||
// number?
|
||||
// @todo Create an optional entity field handler, that can render the
|
||||
// entity.
|
||||
// @see https://www.drupal.org/node/2322949
|
||||
|
||||
if ($entity_type_id = $field_definition->getItemDefinition()->getSetting('target_type')) {
|
||||
$entity_type = $this->entityManager->getDefinition($entity_type_id);
|
||||
if ($entity_type instanceof ContentEntityType) {
|
||||
$views_field['relationship'] = [
|
||||
'base' => $this->getViewsTableForEntityType($entity_type),
|
||||
'base field' => $entity_type->getKey('id'),
|
||||
'label' => $entity_type->getLabel(),
|
||||
'title' => $entity_type->getLabel(),
|
||||
'id' => 'standard',
|
||||
];
|
||||
$views_field['field']['id'] = 'field';
|
||||
$views_field['argument']['id'] = 'numeric';
|
||||
$views_field['filter']['id'] = 'numeric';
|
||||
$views_field['sort']['id'] = 'standard';
|
||||
}
|
||||
else {
|
||||
$views_field['field']['id'] = 'field';
|
||||
$views_field['argument']['id'] = 'string';
|
||||
$views_field['filter']['id'] = 'string';
|
||||
$views_field['sort']['id'] = 'standard';
|
||||
}
|
||||
}
|
||||
|
||||
if ($field_definition->getName() == $this->entityType->getKey('bundle')) {
|
||||
$views_field['filter']['id'] = 'bundle';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the views data for a text field with formatting.
|
||||
*
|
||||
* @param string $table
|
||||
* The table the field is added to.
|
||||
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
|
||||
* The field definition.
|
||||
* @param array $views_field
|
||||
* The views field data.
|
||||
* @param string $field_column_name
|
||||
* The field column being processed.
|
||||
*/
|
||||
protected function processViewsDataForTextLong($table, FieldDefinitionInterface $field_definition, array &$views_field, $field_column_name) {
|
||||
// Connect the text field to its formatter.
|
||||
if ($field_column_name == 'value') {
|
||||
$views_field['field']['format'] = $field_definition->getName() . '__format';
|
||||
$views_field['field']['id'] = 'field';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the views data for a UUID field.
|
||||
*
|
||||
* @param string $table
|
||||
* The table the field is added to.
|
||||
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
|
||||
* The field definition.
|
||||
* @param array $views_field
|
||||
* The views field data.
|
||||
* @param string $field_column_name
|
||||
* The field column being processed.
|
||||
*/
|
||||
protected function processViewsDataForUuid($table, FieldDefinitionInterface $field_definition, array &$views_field, $field_column_name) {
|
||||
// It does not make sense for UUID fields to be click sortable.
|
||||
$views_field['field']['click sortable'] = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getViewsTableForEntityType(EntityTypeInterface $entity_type) {
|
||||
return $entity_type->getDataTable() ?: $entity_type->getBaseTable();
|
||||
}
|
||||
|
||||
}
|
36
core/modules/views/src/EntityViewsDataInterface.php
Normal file
36
core/modules/views/src/EntityViewsDataInterface.php
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\EntityViewsDataInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\views;
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface to integrate an entity type with views.
|
||||
*/
|
||||
interface EntityViewsDataInterface {
|
||||
|
||||
/**
|
||||
* Returns views data for the entity type.
|
||||
*
|
||||
* @return array
|
||||
* Views data in the format of hook_views_data().
|
||||
*/
|
||||
public function getViewsData();
|
||||
|
||||
/**
|
||||
* Gets the table of an entity type to be used as base table in views.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type.
|
||||
*
|
||||
* @return string
|
||||
* The name of the base table in views.
|
||||
*/
|
||||
public function getViewsTableForEntityType(EntityTypeInterface $entity_type);
|
||||
|
||||
}
|
182
core/modules/views/src/EventSubscriber/RouteSubscriber.php
Normal file
182
core/modules/views/src/EventSubscriber/RouteSubscriber.php
Normal file
|
@ -0,0 +1,182 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\EventSubscriber\RouteSubscriber.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\EventSubscriber;
|
||||
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\State\StateInterface;
|
||||
use Drupal\Core\Routing\RouteSubscriberBase;
|
||||
use Drupal\Core\Routing\RoutingEvents;
|
||||
use Drupal\views\Plugin\views\display\DisplayRouterInterface;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\views\Views;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
|
||||
/**
|
||||
* Builds up the routes of all views.
|
||||
*
|
||||
* The general idea is to execute first all alter hooks to determine which
|
||||
* routes are overridden by views. This information is used to determine which
|
||||
* views have to be added by views in the dynamic event.
|
||||
*
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\display\PathPluginBase
|
||||
*/
|
||||
class RouteSubscriber extends RouteSubscriberBase {
|
||||
|
||||
/**
|
||||
* Stores a list of view,display IDs which haven't be used in the alter event.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $viewsDisplayPairs;
|
||||
|
||||
/**
|
||||
* The view storage.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
protected $viewStorage;
|
||||
|
||||
/**
|
||||
* The state key value store.
|
||||
*
|
||||
* @var \Drupal\Core\State\StateInterface
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* Stores an array of route names keyed by view_id.display_id.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $viewRouteNames = array();
|
||||
|
||||
/**
|
||||
* Constructs a \Drupal\views\EventSubscriber\RouteSubscriber instance.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
* @param \Drupal\Core\State\StateInterface $state
|
||||
* The state key value store.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $entity_manager, StateInterface $state) {
|
||||
$this->viewStorage = $entity_manager->getStorage('view');
|
||||
$this->state = $state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the internal state of the route subscriber.
|
||||
*/
|
||||
public function reset() {
|
||||
$this->viewsDisplayPairs = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents() {
|
||||
$events = parent::getSubscribedEvents();
|
||||
$events[RoutingEvents::FINISHED] = array('routeRebuildFinished');
|
||||
// Ensure to run after the entity resolver subscriber
|
||||
// @see \Drupal\Core\EventSubscriber\EntityRouteAlterSubscriber
|
||||
$events[RoutingEvents::ALTER] = ['onAlterRoutes', -175];
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the views and display IDs using a route.
|
||||
*/
|
||||
protected function getViewsDisplayIDsWithRoute() {
|
||||
if (!isset($this->viewsDisplayPairs)) {
|
||||
$this->viewsDisplayPairs = array();
|
||||
|
||||
// @todo Convert this method to some service.
|
||||
$views = $this->getApplicableViews();
|
||||
foreach ($views as $data) {
|
||||
list($view_id, $display_id) = $data;
|
||||
$this->viewsDisplayPairs[] = $view_id . '.' . $display_id;
|
||||
}
|
||||
$this->viewsDisplayPairs = array_combine($this->viewsDisplayPairs, $this->viewsDisplayPairs);
|
||||
}
|
||||
return $this->viewsDisplayPairs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set of route objects.
|
||||
*
|
||||
* @return \Symfony\Component\Routing\RouteCollection
|
||||
* A route collection.
|
||||
*/
|
||||
public function routes() {
|
||||
$collection = new RouteCollection();
|
||||
foreach ($this->getViewsDisplayIDsWithRoute() as $pair) {
|
||||
list($view_id, $display_id) = explode('.', $pair);
|
||||
$view = $this->viewStorage->load($view_id);
|
||||
// @todo This should have an executable factory injected.
|
||||
if (($view = $view->getExecutable()) && $view instanceof ViewExecutable) {
|
||||
if ($view->setDisplay($display_id) && $display = $view->displayHandlers->get($display_id)) {
|
||||
if ($display instanceof DisplayRouterInterface) {
|
||||
$this->viewRouteNames += (array) $display->collectRoutes($collection);
|
||||
}
|
||||
}
|
||||
$view->destroy();
|
||||
}
|
||||
}
|
||||
|
||||
$this->state->set('views.view_route_names', $this->viewRouteNames);
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function alterRoutes(RouteCollection $collection) {
|
||||
foreach ($this->getViewsDisplayIDsWithRoute() as $pair) {
|
||||
list($view_id, $display_id) = explode('.', $pair);
|
||||
$view = $this->viewStorage->load($view_id);
|
||||
// @todo This should have an executable factory injected.
|
||||
if (($view = $view->getExecutable()) && $view instanceof ViewExecutable) {
|
||||
if ($view->setDisplay($display_id) && $display = $view->displayHandlers->get($display_id)) {
|
||||
if ($display instanceof DisplayRouterInterface) {
|
||||
// If the display returns TRUE a route item was found, so it does not
|
||||
// have to be added.
|
||||
$view_route_names = $display->alterRoutes($collection);
|
||||
$this->viewRouteNames = $view_route_names + $this->viewRouteNames;
|
||||
foreach ($view_route_names as $id_display => $route_name) {
|
||||
$view_route_name = $this->viewsDisplayPairs[$id_display];
|
||||
unset($this->viewsDisplayPairs[$id_display]);
|
||||
$collection->remove("views.$view_route_name");
|
||||
}
|
||||
}
|
||||
}
|
||||
$view->destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function routeRebuildFinished() {
|
||||
$this->reset();
|
||||
$this->state->set('views.view_route_names', $this->viewRouteNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all views/display combinations with routes.
|
||||
*
|
||||
* @see \Drupal\views\Views::getApplicableViews()
|
||||
*/
|
||||
protected function getApplicableViews() {
|
||||
return Views::getApplicableViews('uses_route');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,377 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\EventSubscriber\ViewsEntitySchemaSubscriber.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\EventSubscriber;
|
||||
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeEventSubscriberTrait;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Entity\EntityTypeListenerInterface;
|
||||
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
|
||||
use Drupal\views\Views;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
/**
|
||||
* Reacts to changes on entity types to update all views entities.
|
||||
*/
|
||||
class ViewsEntitySchemaSubscriber implements EntityTypeListenerInterface, EventSubscriberInterface {
|
||||
|
||||
use EntityTypeEventSubscriberTrait;
|
||||
|
||||
/**
|
||||
* Indicates that a base table got renamed.
|
||||
*/
|
||||
const BASE_TABLE_RENAME = 0;
|
||||
|
||||
/**
|
||||
* Indicates that a data table got renamed.
|
||||
*/
|
||||
const DATA_TABLE_RENAME = 1;
|
||||
|
||||
/**
|
||||
* Indicates that a data table got added.
|
||||
*/
|
||||
const DATA_TABLE_ADDITION = 2;
|
||||
|
||||
/**
|
||||
* Indicates that a data table got removed.
|
||||
*/
|
||||
const DATA_TABLE_REMOVAL = 3;
|
||||
|
||||
/**
|
||||
* Indicates that a revision table got renamed.
|
||||
*/
|
||||
const REVISION_TABLE_RENAME = 4;
|
||||
|
||||
/**
|
||||
* Indicates that a revision table got added.
|
||||
*/
|
||||
const REVISION_TABLE_ADDITION = 5;
|
||||
|
||||
/**
|
||||
* Indicates that a revision table got removed.
|
||||
*/
|
||||
const REVISION_TABLE_REMOVAL = 6;
|
||||
|
||||
/**
|
||||
* Indicates that a revision data table got renamed.
|
||||
*/
|
||||
const REVISION_DATA_TABLE_RENAME = 7;
|
||||
|
||||
/**
|
||||
* Indicates that a revision data table got added.
|
||||
*/
|
||||
const REVISION_DATA_TABLE_ADDITION = 8;
|
||||
|
||||
/**
|
||||
* Indicates that a revision data table got removed.
|
||||
*/
|
||||
const REVISION_DATA_TABLE_REMOVAL = 9;
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* Constructs a ViewsEntitySchemaSubscriber.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $entity_manager) {
|
||||
$this->entityManager = $entity_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents() {
|
||||
return static::getEntityTypeEvents();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onEntityTypeUpdate(EntityTypeInterface $entity_type, EntityTypeInterface $original) {
|
||||
$changes = [];
|
||||
|
||||
// We implement a specific logic for table updates, which is bound to the
|
||||
// default sql content entity storage.
|
||||
if (!$this->entityManager->getStorage($entity_type->id()) instanceof SqlContentEntityStorage) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($entity_type->getBaseTable() != $original->getBaseTable()) {
|
||||
$changes[] = static::BASE_TABLE_RENAME;
|
||||
}
|
||||
|
||||
$revision_add = $entity_type->isRevisionable() && !$original->isRevisionable();
|
||||
$revision_remove = !$entity_type->isRevisionable() && $original->isRevisionable();
|
||||
$translation_add = $entity_type->isTranslatable() && !$original->isTranslatable();
|
||||
$translation_remove = !$entity_type->isTranslatable() && $original->isTranslatable();
|
||||
|
||||
if ($revision_add) {
|
||||
$changes[] = static::REVISION_TABLE_ADDITION;
|
||||
}
|
||||
elseif ($revision_remove) {
|
||||
$changes[] = static::REVISION_TABLE_REMOVAL;
|
||||
}
|
||||
elseif ($entity_type->isRevisionable() && $entity_type->getRevisionTable() != $original->getRevisionTable()) {
|
||||
$changes[] = static::REVISION_TABLE_RENAME;
|
||||
}
|
||||
|
||||
if ($translation_add) {
|
||||
$changes[] = static::DATA_TABLE_ADDITION;
|
||||
}
|
||||
elseif ($translation_remove) {
|
||||
$changes[] = static::DATA_TABLE_REMOVAL;
|
||||
}
|
||||
elseif ($entity_type->isTranslatable() && $entity_type->getDataTable() != $original->getDataTable()) {
|
||||
$changes[] = static::DATA_TABLE_RENAME;
|
||||
}
|
||||
|
||||
if ($entity_type->isRevisionable() && $entity_type->isTranslatable()) {
|
||||
if ($revision_add || $translation_add) {
|
||||
$changes[] = static::REVISION_DATA_TABLE_ADDITION;
|
||||
}
|
||||
elseif ($entity_type->getRevisionDataTable() != $original->getRevisionDataTable()) {
|
||||
$changes[] = static::REVISION_DATA_TABLE_RENAME;
|
||||
}
|
||||
}
|
||||
elseif ($original->isRevisionable() && $original->isTranslatable() && ($revision_remove || $translation_remove)) {
|
||||
$changes[] = static::REVISION_DATA_TABLE_REMOVAL;
|
||||
}
|
||||
|
||||
/** @var \Drupal\views\Entity\View[] $all_views */
|
||||
$all_views = $this->entityManager->getStorage('view')->loadMultiple(NULL);
|
||||
|
||||
foreach ($changes as $change) {
|
||||
switch ($change) {
|
||||
case static::BASE_TABLE_RENAME:
|
||||
$this->baseTableRename($all_views, $entity_type->id(), $original->getBaseTable(), $entity_type->getBaseTable());
|
||||
break;
|
||||
case static::DATA_TABLE_RENAME:
|
||||
$this->dataTableRename($all_views, $entity_type->id(), $original->getDataTable(), $entity_type->getDataTable());
|
||||
break;
|
||||
case static::DATA_TABLE_ADDITION:
|
||||
$this->dataTableAddition($all_views, $entity_type, $entity_type->getDataTable(), $entity_type->getBaseTable());
|
||||
break;
|
||||
case static::DATA_TABLE_REMOVAL:
|
||||
$this->dataTableRemoval($all_views, $entity_type->id(), $original->getDataTable(), $entity_type->getBaseTable());
|
||||
break;
|
||||
case static::REVISION_TABLE_RENAME:
|
||||
$this->baseTableRename($all_views, $entity_type->id(), $original->getRevisionTable(), $entity_type->getRevisionTable());
|
||||
break;
|
||||
case static::REVISION_TABLE_ADDITION:
|
||||
// If we add revision support we don't have to do anything.
|
||||
break;
|
||||
case static::REVISION_TABLE_REMOVAL:
|
||||
$this->revisionRemoval($all_views, $original);
|
||||
break;
|
||||
case static::REVISION_DATA_TABLE_RENAME:
|
||||
$this->dataTableRename($all_views, $entity_type->id(), $original->getRevisionDataTable(), $entity_type->getRevisionDataTable());
|
||||
break;
|
||||
case static::REVISION_DATA_TABLE_ADDITION:
|
||||
$this->dataTableAddition($all_views, $entity_type, $entity_type->getRevisionDataTable(), $entity_type->getRevisionTable());
|
||||
break;
|
||||
case static::REVISION_DATA_TABLE_REMOVAL:
|
||||
$this->dataTableRemoval($all_views, $entity_type->id(), $original->getRevisionDataTable(), $entity_type->getRevisionTable());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($all_views as $view) {
|
||||
$view->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onEntityTypeDelete(EntityTypeInterface $entity_type) {
|
||||
$tables = [
|
||||
$entity_type->getBaseTable(),
|
||||
$entity_type->getDataTable(),
|
||||
$entity_type->getRevisionTable(),
|
||||
$entity_type->getRevisionDataTable(),
|
||||
];
|
||||
|
||||
$all_views = $this->entityManager->getStorage('view')->loadMultiple(NULL);
|
||||
/** @var \Drupal\views\Entity\View $view */
|
||||
foreach ($all_views as $id => $view) {
|
||||
|
||||
// First check just the base table.
|
||||
if (in_array($view->get('base_table'), $tables)) {
|
||||
$view->disable();
|
||||
$view->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a callable onto all handlers of all passed in views.
|
||||
*
|
||||
* @param \Drupal\views\Entity\View[] $all_views
|
||||
* All views entities.
|
||||
* @param callable $process
|
||||
* A callable which retrieves a handler config array.
|
||||
*/
|
||||
protected function processHandlers(array $all_views, callable $process) {
|
||||
foreach ($all_views as $view) {
|
||||
foreach (array_keys($view->get('display')) as $display_id) {
|
||||
$display = &$view->getDisplay($display_id);
|
||||
foreach (Views::getHandlerTypes() as $handler_type) {
|
||||
$handler_type = $handler_type['plural'];
|
||||
if (!isset($display['display_options'][$handler_type])) {
|
||||
continue;
|
||||
}
|
||||
foreach ($display['display_options'][$handler_type] as $id => &$handler_config) {
|
||||
$process($handler_config);
|
||||
if ($handler_config === NULL) {
|
||||
unset($display['display_options'][$handler_type][$id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates views if a base table is renamed.
|
||||
*
|
||||
* @param \Drupal\views\Entity\View[] $all_views
|
||||
* All views.
|
||||
* @param string $entity_type_id
|
||||
* The entity type ID.
|
||||
* @param string $old_base_table
|
||||
* The old base table name.
|
||||
* @param string $new_base_table
|
||||
* The new base table name.
|
||||
*/
|
||||
protected function baseTableRename($all_views, $entity_type_id, $old_base_table, $new_base_table) {
|
||||
foreach ($all_views as $view) {
|
||||
if ($view->get('base_table') == $old_base_table) {
|
||||
$view->set('base_table', $new_base_table);
|
||||
}
|
||||
}
|
||||
|
||||
$this->processHandlers($all_views, function (array &$handler_config) use ($entity_type_id, $old_base_table, $new_base_table) {
|
||||
if (isset($handler_config['entity_type']) && $handler_config['entity_type'] == $entity_type_id && $handler_config['table'] == $old_base_table) {
|
||||
$handler_config['table'] = $new_base_table;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Updates views if a data table is renamed.
|
||||
*
|
||||
* @param \Drupal\views\Entity\View[] $all_views
|
||||
* All views.
|
||||
* @param string $entity_type_id
|
||||
* The entity type ID.
|
||||
* @param string $old_data_table
|
||||
* The old data table name.
|
||||
* @param string $new_data_table
|
||||
* The new data table name.
|
||||
*/
|
||||
protected function dataTableRename($all_views, $entity_type_id, $old_data_table, $new_data_table) {
|
||||
foreach ($all_views as $view) {
|
||||
if ($view->get('base_table') == $old_data_table) {
|
||||
$view->set('base_table', $new_data_table);
|
||||
}
|
||||
}
|
||||
|
||||
$this->processHandlers($all_views, function (array &$handler_config) use ($entity_type_id, $old_data_table, $new_data_table) {
|
||||
if (isset($handler_config['entity_type']) && $handler_config['entity_type'] == $entity_type_id && $handler_config['table'] == $old_data_table) {
|
||||
$handler_config['table'] = $new_data_table;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates views if a data table is added.
|
||||
*
|
||||
* @param \Drupal\views\Entity\View[] $all_views
|
||||
* All views.
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type.
|
||||
* @param string $new_data_table
|
||||
* The new data table.
|
||||
* @param string $base_table
|
||||
* The base table.
|
||||
*/
|
||||
protected function dataTableAddition($all_views, EntityTypeInterface $entity_type, $new_data_table, $base_table) {
|
||||
/** @var \Drupal\Core\Entity\Sql\SqlContentEntityStorage $storage */
|
||||
$entity_type_id = $entity_type->id();
|
||||
$storage = $this->entityManager->getStorage($entity_type_id);
|
||||
$storage->setEntityType($entity_type);
|
||||
$table_mapping = $storage->getTableMapping();
|
||||
$data_table_fields = $table_mapping->getFieldNames($new_data_table);
|
||||
$base_table_fields = $table_mapping->getFieldNames($base_table);
|
||||
|
||||
$data_table = $new_data_table;
|
||||
|
||||
$this->processHandlers($all_views, function (array &$handler_config) use ($entity_type_id, $base_table, $data_table, $base_table_fields, $data_table_fields) {
|
||||
if (isset($handler_config['entity_type']) && isset($handler_config['entity_field']) && $handler_config['entity_type'] == $entity_type_id) {
|
||||
// Move all fields which just exists on the data table.
|
||||
if ($handler_config['table'] == $base_table && in_array($handler_config['entity_field'], $data_table_fields) && !in_array($handler_config['entity_field'], $base_table_fields)) {
|
||||
$handler_config['table'] = $data_table;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates views if a data table is removed.
|
||||
*
|
||||
* @param \Drupal\views\Entity\View[] $all_views
|
||||
* All views.
|
||||
* @param string $entity_type_id
|
||||
* The entity type ID.
|
||||
* @param string $old_data_table
|
||||
* The name of the previous existing data table.
|
||||
* @param string $base_table
|
||||
* The name of the base table.
|
||||
*/
|
||||
protected function dataTableRemoval($all_views, $entity_type_id, $old_data_table, $base_table) {
|
||||
// We move back the data table back to the base table.
|
||||
$this->processHandlers($all_views, function (array &$handler_config) use ($entity_type_id, $old_data_table, $base_table) {
|
||||
if (isset($handler_config['entity_type']) && $handler_config['entity_type'] == $entity_type_id) {
|
||||
if ($handler_config['table'] == $old_data_table) {
|
||||
$handler_config['table'] = $base_table;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates views if revision support is removed
|
||||
*
|
||||
* @param \Drupal\views\Entity\View[] $all_views
|
||||
* All views.
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $original
|
||||
* The origin entity type.
|
||||
*/
|
||||
protected function revisionRemoval($all_views, EntityTypeInterface $original) {
|
||||
$revision_base_table = $original->getRevisionTable();
|
||||
$revision_data_table = $original->getRevisionDataTable();
|
||||
|
||||
foreach ($all_views as $view) {
|
||||
if (in_array($view->get('base_table'), [$revision_base_table, $revision_data_table])) {
|
||||
// Let's disable the views as we no longer support revisions.
|
||||
$view->setStatus(FALSE);
|
||||
}
|
||||
|
||||
// For any kind of field, let's rely on the broken handler functionality.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
67
core/modules/views/src/ExposedFormCache.php
Normal file
67
core/modules/views/src/ExposedFormCache.php
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\ExposedFormCache.
|
||||
*/
|
||||
|
||||
namespace Drupal\views;
|
||||
|
||||
/**
|
||||
* Caches exposed forms, as they are heavy to generate.
|
||||
*
|
||||
* @see \Drupal\views\Form\ViewsExposedForm
|
||||
*/
|
||||
class ExposedFormCache {
|
||||
|
||||
/**
|
||||
* Stores the exposed form data.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $cache = array();
|
||||
|
||||
/**
|
||||
* Save the Views exposed form for later use.
|
||||
*
|
||||
* @param string $view_id
|
||||
* The views ID.
|
||||
* @param string $display_id
|
||||
* The current view display name.
|
||||
* @param array $form_output
|
||||
* The form structure. Only needed when inserting the value.
|
||||
*/
|
||||
public function setForm($view_id, $display_id, array $form_output) {
|
||||
// Save the form output.
|
||||
$views_exposed[$view_id][$display_id] = $form_output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the views exposed form from cache.
|
||||
*
|
||||
* @param string $view_id
|
||||
* The views ID.
|
||||
* @param string $display_id
|
||||
* The current view display name.
|
||||
*
|
||||
* @return array|bool
|
||||
* The form structure, if any, otherwise FALSE.
|
||||
*/
|
||||
public function getForm($view_id, $display_id) {
|
||||
// Return the form output, if any.
|
||||
if (empty($this->cache[$view_id][$display_id])) {
|
||||
return FALSE;
|
||||
}
|
||||
else {
|
||||
return $this->cache[$view_id][$display_id];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rests the form cache.
|
||||
*/
|
||||
public function reset() {
|
||||
$this->cache = array();
|
||||
}
|
||||
|
||||
}
|
79
core/modules/views/src/FieldAPIHandlerTrait.php
Normal file
79
core/modules/views/src/FieldAPIHandlerTrait.php
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\FieldAPIHandlerTrait.
|
||||
*/
|
||||
|
||||
namespace Drupal\views;
|
||||
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
|
||||
/**
|
||||
* A trait containing helper methods for field definitions.
|
||||
*/
|
||||
trait FieldAPIHandlerTrait {
|
||||
|
||||
/**
|
||||
* The field definition.
|
||||
*
|
||||
* @var \Drupal\Core\Field\FieldDefinitionInterface
|
||||
*/
|
||||
protected $fieldDefinition;
|
||||
|
||||
/**
|
||||
* The field storage definition.
|
||||
*
|
||||
* @var \Drupal\field\FieldStorageConfigInterface
|
||||
*/
|
||||
protected $fieldStorageDefinition;
|
||||
|
||||
/**
|
||||
* Gets the field definition.
|
||||
*
|
||||
* A View works on an entity type across bundles, and thus only has access to
|
||||
* field storage definitions. In order to be able to use widgets and
|
||||
* formatters, we create a generic field definition out of that storage
|
||||
* definition.
|
||||
*
|
||||
* @see BaseFieldDefinition::createFromFieldStorageDefinition()
|
||||
*
|
||||
* @return \Drupal\Core\Field\FieldDefinitionInterface
|
||||
* The field definition used by this handler.
|
||||
*/
|
||||
protected function getFieldDefinition() {
|
||||
if (!$this->fieldDefinition) {
|
||||
$field_storage_config = $this->getFieldStorageDefinition();
|
||||
$this->fieldDefinition = BaseFieldDefinition::createFromFieldStorageDefinition($field_storage_config);
|
||||
}
|
||||
return $this->fieldDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the field storage configuration.
|
||||
*
|
||||
* @return \Drupal\field\FieldStorageConfigInterface
|
||||
* The field storage definition used by this handler
|
||||
*/
|
||||
protected function getFieldStorageDefinition() {
|
||||
if (!$this->fieldStorageDefinition) {
|
||||
$field_storage_definitions = $this->getEntityManager()->getFieldStorageDefinitions($this->definition['entity_type']);
|
||||
$this->fieldStorageDefinition = $field_storage_definitions[$this->definition['field_name']];
|
||||
}
|
||||
return $this->fieldStorageDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entity manager.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\EntityManagerInterface
|
||||
* The entity manager service.
|
||||
*/
|
||||
protected function getEntityManager() {
|
||||
if (!isset($this->entityManager)) {
|
||||
$this->entityManager = \Drupal::entityManager();
|
||||
}
|
||||
return $this->entityManager;
|
||||
}
|
||||
|
||||
}
|
179
core/modules/views/src/Form/ViewsExposedForm.php
Normal file
179
core/modules/views/src/Form/ViewsExposedForm.php
Normal file
|
@ -0,0 +1,179 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Form\ViewsExposedForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Form;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\views\ExposedFormCache;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides the views exposed form.
|
||||
*/
|
||||
class ViewsExposedForm extends FormBase {
|
||||
|
||||
/**
|
||||
* The exposed form cache.
|
||||
*
|
||||
* @var \Drupal\views\ExposedFormCache
|
||||
*/
|
||||
protected $exposedFormCache;
|
||||
|
||||
/**
|
||||
* Constructs a new ViewsExposedForm
|
||||
*
|
||||
* @param \Drupal\views\ExposedFormCache $exposed_form_cache
|
||||
* The exposed form cache.
|
||||
*/
|
||||
public function __construct(ExposedFormCache $exposed_form_cache) {
|
||||
$this->exposedFormCache = $exposed_form_cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static($container->get('views.exposed_form_cache'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'views_exposed_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
// Don't show the form when batch operations are in progress.
|
||||
if ($batch = batch_get() && isset($batch['current_set'])) {
|
||||
return array(
|
||||
// Set the theme callback to be nothing to avoid errors in template_preprocess_views_exposed_form().
|
||||
'#theme' => '',
|
||||
);
|
||||
}
|
||||
|
||||
// Make sure that we validate because this form might be submitted
|
||||
// multiple times per page.
|
||||
$form_state->setValidationEnforced();
|
||||
/** @var \Drupal\views\ViewExecutable $view */
|
||||
$view = $form_state->get('view');
|
||||
$display = &$form_state->get('display');
|
||||
|
||||
$form_state->setUserInput($view->getExposedInput());
|
||||
|
||||
// Let form plugins know this is for exposed widgets.
|
||||
$form_state->set('exposed', TRUE);
|
||||
// Check if the form was already created
|
||||
if ($cache = $this->exposedFormCache->getForm($view->storage->id(), $view->current_display)) {
|
||||
return $cache;
|
||||
}
|
||||
|
||||
$form['#info'] = array();
|
||||
|
||||
// Go through each handler and let it generate its exposed widget.
|
||||
foreach ($view->display_handler->handlers as $type => $value) {
|
||||
/** @var \Drupal\views\Plugin\views\ViewsHandlerInterface $handler */
|
||||
foreach ($view->$type as $id => $handler) {
|
||||
if ($handler->canExpose() && $handler->isExposed()) {
|
||||
// Grouped exposed filters have their own forms.
|
||||
// Instead of render the standard exposed form, a new Select or
|
||||
// Radio form field is rendered with the available groups.
|
||||
// When an user choose an option the selected value is split
|
||||
// into the operator and value that the item represents.
|
||||
if ($handler->isAGroup()) {
|
||||
$handler->groupForm($form, $form_state);
|
||||
$id = $handler->options['group_info']['identifier'];
|
||||
}
|
||||
else {
|
||||
$handler->buildExposedForm($form, $form_state);
|
||||
}
|
||||
if ($info = $handler->exposedInfo()) {
|
||||
$form['#info']["$type-$id"] = $info;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$form['actions'] = array(
|
||||
'#type' => 'actions'
|
||||
);
|
||||
$form['actions']['submit'] = array(
|
||||
// Prevent from showing up in \Drupal::request()->query.
|
||||
'#name' => '',
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Apply'),
|
||||
'#id' => Html::getUniqueId('edit-submit-' . $view->storage->id()),
|
||||
);
|
||||
|
||||
$form['#action'] = $view->hasUrl() ? $view->getUrl()->toString() : Url::fromRoute('<current>')->toString();
|
||||
$form['#theme'] = $view->buildThemeFunctions('views_exposed_form');
|
||||
$form['#id'] = Html::cleanCssIdentifier('views_exposed_form-' . $view->storage->id() . '-' . $display['id']);
|
||||
|
||||
/** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase $exposed_form_plugin */
|
||||
$exposed_form_plugin = $view->display_handler->getPlugin('exposed_form');
|
||||
$exposed_form_plugin->exposedFormAlter($form, $form_state);
|
||||
|
||||
// Save the form.
|
||||
$this->exposedFormCache->setForm($view->storage->id(), $view->current_display, $form);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
$view = $form_state->get('view');
|
||||
|
||||
foreach (array('field', 'filter') as $type) {
|
||||
/** @var \Drupal\views\Plugin\views\ViewsHandlerInterface[] $handlers */
|
||||
$handlers = &$view->$type;
|
||||
foreach ($handlers as $key => $handler) {
|
||||
$handlers[$key]->validateExposed($form, $form_state);
|
||||
}
|
||||
}
|
||||
/** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase $exposed_form_plugin */
|
||||
$exposed_form_plugin = $view->display_handler->getPlugin('exposed_form');
|
||||
$exposed_form_plugin->exposedFormValidate($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
foreach (array('field', 'filter') as $type) {
|
||||
/** @var \Drupal\views\Plugin\views\ViewsHandlerInterface[] $handlers */
|
||||
$handlers = &$form_state->get('view')->$type;
|
||||
foreach ($handlers as $key => $info) {
|
||||
$handlers[$key]->submitExposed($form, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
$view = $form_state->get('view');
|
||||
$view->exposed_data = $form_state->getValues();
|
||||
$view->exposed_raw_input = [];
|
||||
|
||||
$exclude = array('submit', 'form_build_id', 'form_id', 'form_token', 'exposed_form_plugin', 'reset');
|
||||
/** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase $exposed_form_plugin */
|
||||
$exposed_form_plugin = $view->display_handler->getPlugin('exposed_form');
|
||||
$exposed_form_plugin->exposedFormSubmit($form, $form_state, $exclude);
|
||||
|
||||
foreach ($form_state->getValues() as $key => $value) {
|
||||
if (!in_array($key, $exclude)) {
|
||||
$view->exposed_raw_input[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
177
core/modules/views/src/Form/ViewsForm.php
Normal file
177
core/modules/views/src/Form/ViewsForm.php
Normal file
|
@ -0,0 +1,177 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Form\ViewsForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Form;
|
||||
|
||||
use Drupal\Component\Utility\UrlHelper;
|
||||
use Drupal\Core\DependencyInjection\ClassResolverInterface;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
|
||||
use Drupal\Core\Form\FormInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Routing\UrlGeneratorInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
||||
/**
|
||||
* Provides a base class for single- or multistep view forms.
|
||||
*
|
||||
* This class only dispatches logic to the form for the current step. The form
|
||||
* is always assumed to be multistep, even if it has only one step (which by
|
||||
* default is \Drupal\views\Form\ViewsFormMainForm). That way it is actually
|
||||
* possible for modules to have a multistep form if they need to.
|
||||
*/
|
||||
class ViewsForm implements FormInterface, ContainerInjectionInterface {
|
||||
use DependencySerializationTrait;
|
||||
|
||||
/**
|
||||
* The class resolver to get the subform form objects.
|
||||
*
|
||||
* @var \Drupal\Core\DependencyInjection\ClassResolverInterface
|
||||
*/
|
||||
protected $classResolver;
|
||||
|
||||
/**
|
||||
* The request stack.
|
||||
*
|
||||
* @var \Symfony\Component\HttpFoundation\RequestStack
|
||||
*/
|
||||
protected $requestStack;
|
||||
|
||||
/**
|
||||
* The url generator to generate the form action.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\UrlGeneratorInterface
|
||||
*/
|
||||
protected $urlGenerator;
|
||||
|
||||
/**
|
||||
* The ID of the view.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $viewId;
|
||||
|
||||
/**
|
||||
* The ID of the active view's display.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $viewDisplayId;
|
||||
|
||||
/**
|
||||
* Constructs a ViewsForm object.
|
||||
*
|
||||
* @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
|
||||
* The class resolver to get the subform form objects.
|
||||
* @param \Drupal\Core\Routing\UrlGeneratorInterface $url_generator
|
||||
* The url generator to generate the form action.
|
||||
* @param \Symfony\Component\HttpFoundation\RequestStack $requestStack
|
||||
* The request stack.
|
||||
* @param string $view_id
|
||||
* The ID of the view.
|
||||
* @param string $view_display_id
|
||||
* The ID of the active view's display.
|
||||
*/
|
||||
public function __construct(ClassResolverInterface $class_resolver, UrlGeneratorInterface $url_generator, RequestStack $requestStack, $view_id, $view_display_id) {
|
||||
$this->classResolver = $class_resolver;
|
||||
$this->urlGenerator = $url_generator;
|
||||
$this->requestStack = $requestStack;
|
||||
$this->viewId = $view_id;
|
||||
$this->viewDisplayId = $view_display_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, $view_id = NULL, $view_display_id = NULL) {
|
||||
return new static(
|
||||
$container->get('class_resolver'),
|
||||
$container->get('url_generator'),
|
||||
$container->get('request_stack'),
|
||||
$view_id,
|
||||
$view_display_id
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
$parts = array(
|
||||
'views_form',
|
||||
$this->viewId,
|
||||
$this->viewDisplayId,
|
||||
);
|
||||
|
||||
return implode('_', $parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, ViewExecutable $view = NULL, $output = []) {
|
||||
if (!$step = $form_state->get('step')) {
|
||||
$step = 'views_form_views_form';
|
||||
$form_state->set('step', $step);
|
||||
}
|
||||
$form_state->set(['step_controller', 'views_form_views_form'], 'Drupal\views\Form\ViewsFormMainForm');
|
||||
|
||||
$form = array();
|
||||
|
||||
$query = $this->requestStack->getCurrentRequest()->query->all();
|
||||
$query = UrlHelper::filterQueryParameters($query, array(), '');
|
||||
|
||||
$options = array('query' => $query);
|
||||
$form['#action'] = $view->hasUrl() ? $view->getUrl()->setOptions($options)->toString() : Url::fromRoute('<current>')->setOptions($options)->toString();
|
||||
// Tell the preprocessor whether it should hide the header, footer, pager,
|
||||
// etc.
|
||||
$form['show_view_elements'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => ($step == 'views_form_views_form') ? TRUE : FALSE,
|
||||
);
|
||||
|
||||
$form_object = $this->getFormObject($form_state);
|
||||
$form += $form_object->buildForm($form, $form_state, $view, $output);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
$form_object = $this->getFormObject($form_state);
|
||||
$form_object->validateForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$form_object = $this->getFormObject($form_state);
|
||||
$form_object->submitForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object used to build the step form.
|
||||
*
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The form_state of the current form.
|
||||
*
|
||||
* @return \Drupal\Core\Form\FormInterface
|
||||
* The form object to use.
|
||||
*/
|
||||
protected function getFormObject(FormStateInterface $form_state) {
|
||||
// If this is a class, instantiate it.
|
||||
$form_step_class = $form_state->get(['step_controller', $form_state->get('step')]) ?: 'Drupal\views\Form\ViewsFormMainForm';
|
||||
return $this->classResolver->getInstanceFromDefinition($form_step_class);
|
||||
}
|
||||
|
||||
}
|
151
core/modules/views/src/Form/ViewsFormMainForm.php
Normal file
151
core/modules/views/src/Form/ViewsFormMainForm.php
Normal file
|
@ -0,0 +1,151 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Form\ViewsFormMainForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Form;
|
||||
|
||||
use Drupal\Core\Form\FormInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\ViewExecutable;
|
||||
|
||||
class ViewsFormMainForm implements FormInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, ViewExecutable $view = NULL, $output = []) {
|
||||
$form['#prefix'] = '<div class="views-form">';
|
||||
$form['#suffix'] = '</div>';
|
||||
$form['#theme'] = 'form';
|
||||
$form['#pre_render'][] = 'views_pre_render_views_form_views_form';
|
||||
|
||||
// Add the output markup to the form array so that it's included when the form
|
||||
// array is passed to the theme function.
|
||||
$form['output'] = $output;
|
||||
// This way any additional form elements will go before the view
|
||||
// (below the exposed widgets).
|
||||
$form['output']['#weight'] = 50;
|
||||
|
||||
$form['actions'] = array(
|
||||
'#type' => 'actions',
|
||||
);
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Save'),
|
||||
);
|
||||
|
||||
$substitutions = array();
|
||||
foreach ($view->field as $field_name => $field) {
|
||||
$form_element_name = $field_name;
|
||||
if (method_exists($field, 'form_element_name')) {
|
||||
$form_element_name = $field->form_element_name();
|
||||
}
|
||||
$method_form_element_row_id_exists = FALSE;
|
||||
if (method_exists($field, 'form_element_row_id')) {
|
||||
$method_form_element_row_id_exists = TRUE;
|
||||
}
|
||||
|
||||
// If the field provides a views form, allow it to modify the $form array.
|
||||
$has_form = FALSE;
|
||||
if (property_exists($field, 'views_form_callback')) {
|
||||
$callback = $field->views_form_callback;
|
||||
$callback($view, $field, $form, $form_state);
|
||||
$has_form = TRUE;
|
||||
}
|
||||
elseif (method_exists($field, 'viewsForm')) {
|
||||
$field->viewsForm($form, $form_state);
|
||||
$has_form = TRUE;
|
||||
}
|
||||
|
||||
// Build the substitutions array for use in the theme function.
|
||||
if ($has_form) {
|
||||
foreach ($view->result as $row_id => $row) {
|
||||
if ($method_form_element_row_id_exists) {
|
||||
$form_element_row_id = $field->form_element_row_id($row_id);
|
||||
}
|
||||
else {
|
||||
$form_element_row_id = $row_id;
|
||||
}
|
||||
|
||||
$substitutions[] = array(
|
||||
'placeholder' => '<!--form-item-' . $form_element_name . '--' . $form_element_row_id . '-->',
|
||||
'field_name' => $form_element_name,
|
||||
'row_id' => $form_element_row_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Give the area handlers a chance to extend the form.
|
||||
$area_handlers = array_merge(array_values($view->header), array_values($view->footer));
|
||||
$empty = empty($view->result);
|
||||
foreach ($area_handlers as $area) {
|
||||
if (method_exists($area, 'viewsForm') && !$area->viewsFormEmpty($empty)) {
|
||||
$area->viewsForm($form, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
$form['#substitutions'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $substitutions,
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
$view = $form_state->getBuildInfo()['args'][0];
|
||||
|
||||
// Call the validation method on every field handler that has it.
|
||||
foreach ($view->field as $field) {
|
||||
if (method_exists($field, 'viewsFormValidate')) {
|
||||
$field->viewsFormValidate($form, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
// Call the validate method on every area handler that has it.
|
||||
foreach (array('header', 'footer') as $area) {
|
||||
foreach ($view->{$area} as $area_handler) {
|
||||
if (method_exists($area_handler, 'viewsFormValidate')) {
|
||||
$area_handler->viewsFormValidate($form, $form_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$view = $form_state->getBuildInfo()['args'][0];
|
||||
|
||||
// Call the submit method on every field handler that has it.
|
||||
foreach ($view->field as $field) {
|
||||
if (method_exists($field, 'viewsFormSubmit')) {
|
||||
$field->viewsFormSubmit($form, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
// Call the submit method on every area handler that has it.
|
||||
foreach (array('header', 'footer') as $area) {
|
||||
foreach ($view->{$area} as $area_handler) {
|
||||
if (method_exists($area_handler, 'viewsFormSubmit')) {
|
||||
$area_handler->viewsFormSubmit($form, $form_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
334
core/modules/views/src/ManyToOneHelper.php
Normal file
334
core/modules/views/src/ManyToOneHelper.php
Normal file
|
@ -0,0 +1,334 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\ManyToOneHelper.
|
||||
*/
|
||||
|
||||
namespace Drupal\views;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\Plugin\views\HandlerBase;
|
||||
|
||||
/**
|
||||
* This many to one helper object is used on both arguments and filters.
|
||||
*
|
||||
* @todo This requires extensive documentation on how this class is to
|
||||
* be used. For now, look at the arguments and filters that use it. Lots
|
||||
* of stuff is just pass-through but there are definitely some interesting
|
||||
* areas where they interact.
|
||||
*
|
||||
* Any handler that uses this can have the following possibly additional
|
||||
* definition terms:
|
||||
* - numeric: If true, treat this field as numeric, using %d instead of %s in
|
||||
* queries.
|
||||
*
|
||||
*/
|
||||
class ManyToOneHelper {
|
||||
|
||||
function __construct($handler) {
|
||||
$this->handler = $handler;
|
||||
}
|
||||
|
||||
public static function defineOptions(&$options) {
|
||||
$options['reduce_duplicates'] = array('default' => FALSE);
|
||||
}
|
||||
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
$form['reduce_duplicates'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Reduce duplicates'),
|
||||
'#description' => t("This filter can cause items that have more than one of the selected options to appear as duplicate results. If this filter causes duplicate results to occur, this checkbox can reduce those duplicates; however, the more terms it has to search for, the less performant the query will be, so use this with caution. Shouldn't be set on single-value fields, as it may cause values to disappear from display, if used on an incompatible field."),
|
||||
'#default_value' => !empty($this->handler->options['reduce_duplicates']),
|
||||
'#weight' => 4,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sometimes the handler might want us to use some kind of formula, so give
|
||||
* it that option. If it wants us to do this, it must set $helper->formula = TRUE
|
||||
* and implement handler->getFormula();
|
||||
*/
|
||||
public function getField() {
|
||||
if (!empty($this->formula)) {
|
||||
return $this->handler->getFormula();
|
||||
}
|
||||
else {
|
||||
return $this->handler->tableAlias . '.' . $this->handler->realField;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a table to the query.
|
||||
*
|
||||
* This is an advanced concept; not only does it add a new instance of the table,
|
||||
* but it follows the relationship path all the way down to the relationship
|
||||
* link point and adds *that* as a new relationship and then adds the table to
|
||||
* the relationship, if necessary.
|
||||
*/
|
||||
public function addTable($join = NULL, $alias = NULL) {
|
||||
// This is used for lookups in the many_to_one table.
|
||||
$field = $this->handler->relationship . '_' . $this->handler->table . '.' . $this->handler->field;
|
||||
|
||||
if (empty($join)) {
|
||||
$join = $this->getJoin();
|
||||
}
|
||||
|
||||
// See if there's a chain between us and the base relationship. If so, we need
|
||||
// to create a new relationship to use.
|
||||
$relationship = $this->handler->relationship;
|
||||
|
||||
// Determine the primary table to seek
|
||||
if (empty($this->handler->query->relationships[$relationship])) {
|
||||
$base_table = $this->handler->view->storage->get('base_table');
|
||||
}
|
||||
else {
|
||||
$base_table = $this->handler->query->relationships[$relationship]['base'];
|
||||
}
|
||||
|
||||
// Cycle through the joins. This isn't as error-safe as the normal
|
||||
// ensurePath logic. Perhaps it should be.
|
||||
$r_join = clone $join;
|
||||
while ($r_join->leftTable != $base_table) {
|
||||
$r_join = HandlerBase::getTableJoin($r_join->leftTable, $base_table);
|
||||
}
|
||||
// If we found that there are tables in between, add the relationship.
|
||||
if ($r_join->table != $join->table) {
|
||||
$relationship = $this->handler->query->addRelationship($this->handler->table . '_' . $r_join->table, $r_join, $r_join->table, $this->handler->relationship);
|
||||
}
|
||||
|
||||
// And now add our table, using the new relationship if one was used.
|
||||
$alias = $this->handler->query->addTable($this->handler->table, $relationship, $join, $alias);
|
||||
|
||||
// Store what values are used by this table chain so that other chains can
|
||||
// automatically discard those values.
|
||||
if (empty($this->handler->view->many_to_one_tables[$field])) {
|
||||
$this->handler->view->many_to_one_tables[$field] = $this->handler->value;
|
||||
}
|
||||
else {
|
||||
$this->handler->view->many_to_one_tables[$field] = array_merge($this->handler->view->many_to_one_tables[$field], $this->handler->value);
|
||||
}
|
||||
|
||||
return $alias;
|
||||
}
|
||||
|
||||
public function getJoin() {
|
||||
return $this->handler->getJoin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide the proper join for summary queries. This is important in part because
|
||||
* it will cooperate with other arguments if possible.
|
||||
*/
|
||||
public function summaryJoin() {
|
||||
$field = $this->handler->relationship . '_' . $this->handler->table . '.' . $this->handler->field;
|
||||
$join = $this->getJoin();
|
||||
|
||||
// shortcuts
|
||||
$options = $this->handler->options;
|
||||
$view = $this->handler->view;
|
||||
$query = $this->handler->query;
|
||||
|
||||
if (!empty($options['require_value'])) {
|
||||
$join->type = 'INNER';
|
||||
}
|
||||
|
||||
if (empty($options['add_table']) || empty($view->many_to_one_tables[$field])) {
|
||||
return $query->ensureTable($this->handler->table, $this->handler->relationship, $join);
|
||||
}
|
||||
else {
|
||||
if (!empty($view->many_to_one_tables[$field])) {
|
||||
foreach ($view->many_to_one_tables[$field] as $value) {
|
||||
$join->extra = array(
|
||||
array(
|
||||
'field' => $this->handler->realField,
|
||||
'operator' => '!=',
|
||||
'value' => $value,
|
||||
'numeric' => !empty($this->definition['numeric']),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
return $this->addTable($join);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override ensureMyTable so we can control how this joins in.
|
||||
* The operator actually has influence over joining.
|
||||
*/
|
||||
public function ensureMyTable() {
|
||||
if (!isset($this->handler->tableAlias)) {
|
||||
// Case 1: Operator is an 'or' and we're not reducing duplicates.
|
||||
// We hence get the absolute simplest:
|
||||
$field = $this->handler->relationship . '_' . $this->handler->table . '.' . $this->handler->field;
|
||||
if ($this->handler->operator == 'or' && empty($this->handler->options['reduce_duplicates'])) {
|
||||
if (empty($this->handler->options['add_table']) && empty($this->handler->view->many_to_one_tables[$field])) {
|
||||
// query optimization, INNER joins are slightly faster, so use them
|
||||
// when we know we can.
|
||||
$join = $this->getJoin();
|
||||
if (isset($join)) {
|
||||
$join->type = 'INNER';
|
||||
}
|
||||
$this->handler->tableAlias = $this->handler->query->ensureTable($this->handler->table, $this->handler->relationship, $join);
|
||||
$this->handler->view->many_to_one_tables[$field] = $this->handler->value;
|
||||
}
|
||||
else {
|
||||
$join = $this->getJoin();
|
||||
$join->type = 'LEFT';
|
||||
if (!empty($this->handler->view->many_to_one_tables[$field])) {
|
||||
foreach ($this->handler->view->many_to_one_tables[$field] as $value) {
|
||||
$join->extra = array(
|
||||
array(
|
||||
'field' => $this->handler->realField,
|
||||
'operator' => '!=',
|
||||
'value' => $value,
|
||||
'numeric' => !empty($this->handler->definition['numeric']),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->handler->tableAlias = $this->addTable($join);
|
||||
}
|
||||
|
||||
return $this->handler->tableAlias;
|
||||
}
|
||||
|
||||
// Case 2: it's an 'and' or an 'or'.
|
||||
// We do one join per selected value.
|
||||
if ($this->handler->operator != 'not') {
|
||||
// Clone the join for each table:
|
||||
$this->handler->tableAliases = array();
|
||||
foreach ($this->handler->value as $value) {
|
||||
$join = $this->getJoin();
|
||||
if ($this->handler->operator == 'and') {
|
||||
$join->type = 'INNER';
|
||||
}
|
||||
$join->extra = array(
|
||||
array(
|
||||
'field' => $this->handler->realField,
|
||||
'value' => $value,
|
||||
'numeric' => !empty($this->handler->definition['numeric']),
|
||||
),
|
||||
);
|
||||
|
||||
// The table alias needs to be unique to this value across the
|
||||
// multiple times the filter or argument is called by the view.
|
||||
if (!isset($this->handler->view->many_to_one_aliases[$field][$value])) {
|
||||
if (!isset($this->handler->view->many_to_one_count[$this->handler->table])) {
|
||||
$this->handler->view->many_to_one_count[$this->handler->table] = 0;
|
||||
}
|
||||
$this->handler->view->many_to_one_aliases[$field][$value] = $this->handler->table . '_value_' . ($this->handler->view->many_to_one_count[$this->handler->table]++);
|
||||
}
|
||||
|
||||
$this->handler->tableAliases[$value] = $this->addTable($join, $this->handler->view->many_to_one_aliases[$field][$value]);
|
||||
// Set tableAlias to the first of these.
|
||||
if (empty($this->handler->tableAlias)) {
|
||||
$this->handler->tableAlias = $this->handler->tableAliases[$value];
|
||||
}
|
||||
}
|
||||
}
|
||||
// Case 3: it's a 'not'.
|
||||
// We just do one join. We'll add a where clause during
|
||||
// the query phase to ensure that $table.$field IS NULL.
|
||||
else {
|
||||
$join = $this->getJoin();
|
||||
$join->type = 'LEFT';
|
||||
$join->extra = array();
|
||||
$join->extra_type = 'OR';
|
||||
foreach ($this->handler->value as $value) {
|
||||
$join->extra[] = array(
|
||||
'field' => $this->handler->realField,
|
||||
'value' => $value,
|
||||
'numeric' => !empty($this->handler->definition['numeric']),
|
||||
);
|
||||
}
|
||||
|
||||
$this->handler->tableAlias = $this->addTable($join);
|
||||
}
|
||||
}
|
||||
return $this->handler->tableAlias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a unique placeholders for handlers.
|
||||
*/
|
||||
protected function placeholder() {
|
||||
return $this->handler->query->placeholder($this->handler->options['table'] . '_' . $this->handler->options['field']);
|
||||
}
|
||||
|
||||
public function addFilter() {
|
||||
if (empty($this->handler->value)) {
|
||||
return;
|
||||
}
|
||||
$this->handler->ensureMyTable();
|
||||
|
||||
// Shorten some variables:
|
||||
$field = $this->getField();
|
||||
$options = $this->handler->options;
|
||||
$operator = $this->handler->operator;
|
||||
$formula = !empty($this->formula);
|
||||
$value = $this->handler->value;
|
||||
if (empty($options['group'])) {
|
||||
$options['group'] = 0;
|
||||
}
|
||||
|
||||
// add_condition determines whether a single expression is enough(FALSE) or the
|
||||
// conditions should be added via an db_or()/db_and() (TRUE).
|
||||
$add_condition = TRUE;
|
||||
if ($operator == 'not') {
|
||||
$value = NULL;
|
||||
$operator = 'IS NULL';
|
||||
$add_condition = FALSE;
|
||||
}
|
||||
elseif ($operator == 'or' && empty($options['reduce_duplicates'])) {
|
||||
if (count($value) > 1) {
|
||||
$operator = 'IN';
|
||||
}
|
||||
else {
|
||||
$value = is_array($value) ? array_pop($value) : $value;
|
||||
$operator = '=';
|
||||
}
|
||||
$add_condition = FALSE;
|
||||
}
|
||||
|
||||
if (!$add_condition) {
|
||||
if ($formula) {
|
||||
$placeholder = $this->placeholder();
|
||||
if ($operator == 'IN') {
|
||||
$operator = "$operator IN($placeholder)";
|
||||
}
|
||||
else {
|
||||
$operator = "$operator $placeholder";
|
||||
}
|
||||
$placeholders = array(
|
||||
$placeholder => $value,
|
||||
) + $this->placeholders;
|
||||
$this->handler->query->addWhereExpression($options['group'], "$field $operator", $placeholders);
|
||||
}
|
||||
else {
|
||||
$placeholder = $this->placeholder();
|
||||
if (count($this->handler->value) > 1) {
|
||||
$placeholder .= '[]';
|
||||
$this->handler->query->addWhereExpression(0, "$field $operator($placeholder)", array($placeholder => $value));
|
||||
}
|
||||
else {
|
||||
$this->handler->query->addWhereExpression(0, "$field $operator $placeholder", array($placeholder => $value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($add_condition) {
|
||||
$field = $this->handler->realField;
|
||||
$clause = $operator == 'or' ? db_or() : db_and();
|
||||
foreach ($this->handler->tableAliases as $value => $alias) {
|
||||
$clause->condition("$alias.$field", $value);
|
||||
}
|
||||
|
||||
// implode on either AND or OR.
|
||||
$this->handler->query->addWhere($options['group'], $clause);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
117
core/modules/views/src/Plugin/Block/ViewsBlock.php
Normal file
117
core/modules/views/src/Plugin/Block/ViewsBlock.php
Normal file
|
@ -0,0 +1,117 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\Block\ViewsBlock.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Config\Entity\Query\Query;
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a generic Views block.
|
||||
*
|
||||
* @Block(
|
||||
* id = "views_block",
|
||||
* admin_label = @Translation("Views Block"),
|
||||
* deriver = "Drupal\views\Plugin\Derivative\ViewsBlock"
|
||||
* )
|
||||
*/
|
||||
class ViewsBlock extends ViewsBlockBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
$this->view->display_handler->preBlockBuild($this);
|
||||
|
||||
if ($output = $this->view->buildRenderable($this->displayID, [], FALSE)) {
|
||||
// Override the label to the dynamic title configured in the view.
|
||||
if (empty($this->configuration['views_label']) && $this->view->getTitle()) {
|
||||
$output['#title'] = Xss::filterAdmin($this->view->getTitle());
|
||||
}
|
||||
|
||||
// Before returning the block output, convert it to a renderable array
|
||||
// with contextual links.
|
||||
$this->addContextualLinks($output);
|
||||
return $output;
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfiguration() {
|
||||
$configuration = parent::getConfiguration();
|
||||
|
||||
// Set the label to the static title configured in the view.
|
||||
if (!empty($configuration['views_label'])) {
|
||||
$configuration['label'] = $configuration['views_label'];
|
||||
}
|
||||
|
||||
return $configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultConfiguration() {
|
||||
$settings = parent::defaultConfiguration();
|
||||
|
||||
if ($this->displaySet) {
|
||||
$settings += $this->view->display_handler->blockSettings($settings);
|
||||
}
|
||||
|
||||
// Set custom cache settings.
|
||||
if (isset($this->pluginDefinition['cache'])) {
|
||||
$settings['cache'] = $this->pluginDefinition['cache'];
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockForm($form, FormStateInterface $form_state) {
|
||||
if ($this->displaySet) {
|
||||
return $this->view->display_handler->blockForm($this, $form, $form_state);
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockValidate($form, FormStateInterface $form_state) {
|
||||
if ($this->displaySet) {
|
||||
$this->view->display_handler->blockValidate($this, $form, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockSubmit($form, FormStateInterface $form_state) {
|
||||
parent::blockSubmit($form, $form_state);
|
||||
if ($this->displaySet) {
|
||||
$this->view->display_handler->blockSubmit($this, $form, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMachineNameSuggestion() {
|
||||
$this->view->setDisplay($this->displayID);
|
||||
return 'views_block__' . $this->view->storage->id() . '_' . $this->view->current_display;
|
||||
}
|
||||
|
||||
}
|
214
core/modules/views/src/Plugin/Block/ViewsBlockBase.php
Normal file
214
core/modules/views/src/Plugin/Block/ViewsBlockBase.php
Normal file
|
@ -0,0 +1,214 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\Block\ViewsBlockBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\views\ViewExecutableFactory;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Base class for Views block plugins.
|
||||
*/
|
||||
abstract class ViewsBlockBase extends BlockBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The View executable object.
|
||||
*
|
||||
* @var \Drupal\views\ViewExecutable
|
||||
*/
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* The display ID being used for this View.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $displayID;
|
||||
|
||||
/**
|
||||
* Indicates whether the display was successfully set.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $displaySet;
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* Constructs a \Drupal\views\Plugin\Block\ViewsBlockBase object.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\views\ViewExecutableFactory $executable_factory
|
||||
* The view executable factory.
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $storage
|
||||
* The views storage.
|
||||
* @param \Drupal\Core\Session\AccountInterface $user
|
||||
* The current user.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, ViewExecutableFactory $executable_factory, EntityStorageInterface $storage, AccountInterface $user) {
|
||||
$this->pluginId = $plugin_id;
|
||||
$delta = $this->getDerivativeId();
|
||||
list($name, $this->displayID) = explode('-', $delta, 2);
|
||||
// Load the view.
|
||||
$view = $storage->load($name);
|
||||
$this->view = $executable_factory->get($view);
|
||||
$this->displaySet = $this->view->setDisplay($this->displayID);
|
||||
$this->user = $user;
|
||||
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration, $plugin_id, $plugin_definition,
|
||||
$container->get('views.executable'),
|
||||
$container->get('entity.manager')->getStorage('view'),
|
||||
$container->get('current_user')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function blockAccess(AccountInterface $account) {
|
||||
if ($this->view->access($this->displayID)) {
|
||||
$access = AccessResult::allowed();
|
||||
}
|
||||
else {
|
||||
$access = AccessResult::forbidden();
|
||||
}
|
||||
return $access;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultConfiguration() {
|
||||
return array('views_label' => '');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
$form = parent::buildConfigurationForm($form, $form_state);
|
||||
|
||||
// Set the default label to '' so the views internal title is used.
|
||||
$form['label']['#default_value'] = '';
|
||||
$form['label']['#access'] = FALSE;
|
||||
|
||||
// Unset the machine_name provided by BlockForm.
|
||||
unset($form['id']['#machine_name']['source']);
|
||||
// Prevent users from changing the auto-generated block machine_name.
|
||||
$form['id']['#access'] = FALSE;
|
||||
$form['#pre_render'][] = '\Drupal\views\Plugin\views\PluginBase::preRenderAddFieldsetMarkup';
|
||||
|
||||
// Allow to override the label on the actual page.
|
||||
$form['views_label_checkbox'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Override title'),
|
||||
'#default_value' => !empty($this->configuration['views_label']),
|
||||
);
|
||||
|
||||
$form['views_label_fieldset'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
array(
|
||||
':input[name="settings[views_label_checkbox]"]' => array('checked' => TRUE),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$form['views_label'] = array(
|
||||
'#title' => $this->t('Title'),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $this->configuration['views_label'] ?: $this->view->getTitle(),
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
array(
|
||||
':input[name="settings[views_label_checkbox]"]' => array('checked' => TRUE),
|
||||
),
|
||||
),
|
||||
),
|
||||
'#fieldset' => 'views_label_fieldset',
|
||||
);
|
||||
|
||||
if ($this->view->storage->access('edit') && \Drupal::moduleHandler()->moduleExists('views_ui')) {
|
||||
$form['views_label']['#description'] = $this->t('Changing the title here means it cannot be dynamically altered anymore. (Try changing it directly in <a href="@url">@name</a>.)', array('@url' => \Drupal::url('entity.view.edit_display_form', array('view' => $this->view->storage->id(), 'display_id' => $this->displayID)), '@name' => $this->view->storage->label()));
|
||||
}
|
||||
else {
|
||||
$form['views_label']['#description'] = $this->t('Changing the title here means it cannot be dynamically altered anymore.');
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockSubmit($form, FormStateInterface $form_state) {
|
||||
if (!$form_state->isValueEmpty('views_label_checkbox')) {
|
||||
$this->configuration['views_label'] = $form_state->getValue('views_label');
|
||||
}
|
||||
else {
|
||||
$this->configuration['views_label'] = '';
|
||||
}
|
||||
$form_state->unsetValue('views_label_checkbox');
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts Views block content to a renderable array with contextual links.
|
||||
*
|
||||
* @param string|array $output
|
||||
* An string|array representing the block. This will be modified to be a
|
||||
* renderable array, containing the optional '#contextual_links' property (if
|
||||
* there are any contextual links associated with the block).
|
||||
* @param string $block_type
|
||||
* The type of the block. If it's 'block' it's a regular views display,
|
||||
* but 'exposed_filter' exist as well.
|
||||
*/
|
||||
protected function addContextualLinks(&$output, $block_type = 'block') {
|
||||
// Do not add contextual links to an empty block.
|
||||
if (!empty($output)) {
|
||||
// Contextual links only work on blocks whose content is a renderable
|
||||
// array, so if the block contains a string of already-rendered markup,
|
||||
// convert it to an array.
|
||||
if (is_string($output)) {
|
||||
$output = array('#markup' => $output);
|
||||
}
|
||||
|
||||
// views_add_contextual_links() needs the following information in
|
||||
// order to be attached to the view.
|
||||
$output['#view_id'] = $this->view->storage->id();
|
||||
$output['#view_display_show_admin_links'] = $this->view->getShowAdminLinks();
|
||||
$output['#view_display_plugin_id'] = $this->view->display_handler->getPluginId();
|
||||
views_add_contextual_links($output, $block_type, $this->displayID);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\Block\ViewsExposedFilterBlock.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\Block;
|
||||
|
||||
/**
|
||||
* Provides a 'Views Exposed Filter' block.
|
||||
*
|
||||
* @Block(
|
||||
* id = "views_exposed_filter_block",
|
||||
* admin_label = @Translation("Views Exposed Filter Block"),
|
||||
* deriver = "Drupal\views\Plugin\Derivative\ViewsExposedFilterBlock"
|
||||
* )
|
||||
*/
|
||||
class ViewsExposedFilterBlock extends ViewsBlockBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
$output = $this->view->display_handler->viewExposedFormBlocks();
|
||||
// Before returning the block output, convert it to a renderable array with
|
||||
// contextual links.
|
||||
$this->addContextualLinks($output, 'exposed_filter');
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
}
|
35
core/modules/views/src/Plugin/CacheablePluginInterface.php
Normal file
35
core/modules/views/src/Plugin/CacheablePluginInterface.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\CacheablePluginInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin;
|
||||
|
||||
/**
|
||||
* Provides caching information about the result cacheability of views plugins.
|
||||
*
|
||||
* For caching on the render level, we rely on bubbling of the cache contexts.
|
||||
*/
|
||||
interface CacheablePluginInterface {
|
||||
|
||||
/**
|
||||
* Returns TRUE if this plugin is cacheable at all.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isCacheable();
|
||||
|
||||
/**
|
||||
* Returns an array of cache contexts, this plugin varies by.
|
||||
*
|
||||
* Note: This method is called on views safe time, so you do have the
|
||||
* configuration available. For example an exposed filter changes its
|
||||
* cacheability depending on the URL.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getCacheContexts();
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\Derivative\DefaultWizardDeriver.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\Derivative;
|
||||
|
||||
use Drupal\Component\Plugin\Derivative\DeriverBase;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* A derivative class which provides automatic wizards for all base tables.
|
||||
*
|
||||
* The derivatives store all base table plugin information.
|
||||
*/
|
||||
class DefaultWizardDeriver extends DeriverBase {
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||
$views_data = Views::viewsData();
|
||||
$base_tables = array_keys($views_data->fetchBaseTables());
|
||||
$this->derivatives = array();
|
||||
foreach ($base_tables as $table) {
|
||||
$views_info = $views_data->get($table);
|
||||
if (empty($views_info['table']['wizard_id'])) {
|
||||
$this->derivatives[$table] = array(
|
||||
'id' => 'standard',
|
||||
'base_table' => $table,
|
||||
'title' => $views_info['table']['base']['title'],
|
||||
'class' => 'Drupal\views\Plugin\views\wizard\Standard'
|
||||
);
|
||||
}
|
||||
}
|
||||
return parent::getDerivativeDefinitions($base_plugin_definition);
|
||||
}
|
||||
}
|
118
core/modules/views/src/Plugin/Derivative/ViewsBlock.php
Normal file
118
core/modules/views/src/Plugin/Derivative/ViewsBlock.php
Normal file
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\Derivative\ViewsBlock.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\Derivative;
|
||||
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides block plugin definitions for all Views block displays.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\block\block\ViewsBlock
|
||||
*/
|
||||
class ViewsBlock implements ContainerDeriverInterface {
|
||||
|
||||
/**
|
||||
* List of derivative definitions.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $derivatives = array();
|
||||
|
||||
/**
|
||||
* The base plugin ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $basePluginId;
|
||||
|
||||
/**
|
||||
* The view storage.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
protected $viewStorage;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, $base_plugin_id) {
|
||||
return new static(
|
||||
$base_plugin_id,
|
||||
$container->get('entity.manager')->getStorage('view')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a ViewsBlock object.
|
||||
*
|
||||
* @param string $base_plugin_id
|
||||
* The base plugin ID.
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $view_storage
|
||||
* The entity storage to load views.
|
||||
*/
|
||||
public function __construct($base_plugin_id, EntityStorageInterface $view_storage) {
|
||||
$this->basePluginId = $base_plugin_id;
|
||||
$this->viewStorage = $view_storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinition($derivative_id, $base_plugin_definition) {
|
||||
if (!empty($this->derivatives) && !empty($this->derivatives[$derivative_id])) {
|
||||
return $this->derivatives[$derivative_id];
|
||||
}
|
||||
$this->getDerivativeDefinitions($base_plugin_definition);
|
||||
return $this->derivatives[$derivative_id];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||
// Check all Views for block displays.
|
||||
foreach ($this->viewStorage->loadMultiple() as $view) {
|
||||
// Do not return results for disabled views.
|
||||
if (!$view->status()) {
|
||||
continue;
|
||||
}
|
||||
$executable = $view->getExecutable();
|
||||
$executable->initDisplay();
|
||||
foreach ($executable->displayHandlers as $display) {
|
||||
// Add a block plugin definition for each block display.
|
||||
if (isset($display) && !empty($display->definition['uses_hook_block'])) {
|
||||
$delta = $view->id() . '-' . $display->display['id'];
|
||||
$desc = $display->getOption('block_description');
|
||||
|
||||
if (empty($desc)) {
|
||||
if ($display->display['display_title'] == $display->definition['title']) {
|
||||
$desc = t('!view', array('!view' => $view->label()));
|
||||
}
|
||||
else {
|
||||
$desc = t('!view: !display', array('!view' => $view->label(), '!display' => $display->display['display_title']));
|
||||
}
|
||||
}
|
||||
$this->derivatives[$delta] = array(
|
||||
'category' => $display->getOption('block_category'),
|
||||
'admin_label' => $desc,
|
||||
'config_dependencies' => array(
|
||||
'config' => array(
|
||||
$view->getConfigDependencyName(),
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->derivatives[$delta] += $base_plugin_definition;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->derivatives;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\Derivative\ViewsEntityArgumentValidator.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\Derivative;
|
||||
|
||||
use Drupal\Component\Plugin\Derivative\DeriverBase;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\Core\StringTranslation\TranslationInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides views argument validator plugin definitions for all entity types.
|
||||
*
|
||||
* @ingroup views_argument_validator_plugins
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\argument_validator\Entity
|
||||
*/
|
||||
class ViewsEntityArgumentValidator extends DeriverBase implements ContainerDeriverInterface {
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* The base plugin ID this derivative is for.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $basePluginId;
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* List of derivative definitions.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $derivatives = array();
|
||||
|
||||
/**
|
||||
* Constructs an ViewsEntityArgumentValidator object.
|
||||
*
|
||||
* @param string $base_plugin_id
|
||||
* The base plugin ID.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
* @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
|
||||
* The string translation.
|
||||
*/
|
||||
public function __construct($base_plugin_id, EntityManagerInterface $entity_manager, TranslationInterface $string_translation) {
|
||||
$this->basePluginId = $base_plugin_id;
|
||||
$this->entityManager = $entity_manager;
|
||||
$this->stringTranslation = $string_translation;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, $base_plugin_id) {
|
||||
return new static(
|
||||
$base_plugin_id,
|
||||
$container->get('entity.manager'),
|
||||
$container->get('string_translation')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||
$entity_types = $this->entityManager->getDefinitions();
|
||||
$this->derivatives = array();
|
||||
foreach ($entity_types as $entity_type_id => $entity_type) {
|
||||
$this->derivatives[$entity_type_id] = array(
|
||||
'id' => 'entity:' . $entity_type_id,
|
||||
'provider' => 'views',
|
||||
'title' => $entity_type->getLabel(),
|
||||
'help' => $this->t('Validate @label', array('@label' => $entity_type->getLabel())),
|
||||
'entity_type' => $entity_type_id,
|
||||
'class' => $base_plugin_definition['class'],
|
||||
);
|
||||
}
|
||||
|
||||
return $this->derivatives;
|
||||
}
|
||||
|
||||
}
|
113
core/modules/views/src/Plugin/Derivative/ViewsEntityRow.php
Normal file
113
core/modules/views/src/Plugin/Derivative/ViewsEntityRow.php
Normal file
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\Derivative\ViewsEntityRow.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\Derivative;
|
||||
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
||||
use Drupal\views\ViewsData;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides views row plugin definitions for all non-special entity types.
|
||||
*
|
||||
* @ingroup views_row_plugins
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\row\EntityRow
|
||||
*/
|
||||
class ViewsEntityRow implements ContainerDeriverInterface {
|
||||
|
||||
/**
|
||||
* Stores all entity row plugin information.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $derivatives = array();
|
||||
|
||||
/**
|
||||
* The base plugin ID that the derivative is for.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $basePluginId;
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* The views data service.
|
||||
*
|
||||
* @var \Drupal\views\ViewsData
|
||||
*/
|
||||
protected $viewsData;
|
||||
|
||||
/**
|
||||
* Constructs a ViewsEntityRow object.
|
||||
*
|
||||
* @param string $base_plugin_id
|
||||
* The base plugin ID.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
* @param \Drupal\views\ViewsData $views_data
|
||||
* The views data service.
|
||||
*/
|
||||
public function __construct($base_plugin_id, EntityManagerInterface $entity_manager, ViewsData $views_data) {
|
||||
$this->basePluginId = $base_plugin_id;
|
||||
$this->entityManager = $entity_manager;
|
||||
$this->viewsData = $views_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, $base_plugin_id) {
|
||||
return new static(
|
||||
$base_plugin_id,
|
||||
$container->get('entity.manager'),
|
||||
$container->get('views.views_data')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinition($derivative_id, $base_plugin_definition) {
|
||||
if (!empty($this->derivatives) && !empty($this->derivatives[$derivative_id])) {
|
||||
return $this->derivatives[$derivative_id];
|
||||
}
|
||||
$this->getDerivativeDefinitions($base_plugin_definition);
|
||||
return $this->derivatives[$derivative_id];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||
foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) {
|
||||
// Just add support for entity types which have a views integration.
|
||||
if (($base_table = $entity_type->getBaseTable()) && $this->viewsData->get($base_table) && $this->entityManager->hasHandler($entity_type_id, 'view_builder')) {
|
||||
$this->derivatives[$entity_type_id] = array(
|
||||
'id' => 'entity:' . $entity_type_id,
|
||||
'provider' => 'views',
|
||||
'title' => $entity_type->getLabel(),
|
||||
'help' => t('Display the @label', array('@label' => $entity_type->getLabel())),
|
||||
'base' => array($entity_type->getDataTable() ?: $entity_type->getBaseTable()),
|
||||
'entity_type' => $entity_type_id,
|
||||
'display_types' => array('normal'),
|
||||
'class' => $base_plugin_definition['class'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->derivatives;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\Derivative\ViewsExposedFilterBlock.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\Derivative;
|
||||
|
||||
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides block plugin definitions for all Views exposed filters.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\block\block\ViewsExposedFilterBlock
|
||||
*/
|
||||
class ViewsExposedFilterBlock implements ContainerDeriverInterface {
|
||||
|
||||
/**
|
||||
* List of derivative definitions.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $derivatives = array();
|
||||
|
||||
/**
|
||||
* The view storage.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
protected $viewStorage;
|
||||
|
||||
/**
|
||||
* The base plugin ID that the derivative is for.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $basePluginId;
|
||||
|
||||
/**
|
||||
* Constructs a ViewsExposedFilterBlock object.
|
||||
*
|
||||
* @param string $base_plugin_id
|
||||
* The base plugin ID.
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $view_storage
|
||||
* The entity storage to load views.
|
||||
*/
|
||||
public function __construct($base_plugin_id, EntityStorageInterface $view_storage) {
|
||||
$this->basePluginId = $base_plugin_id;
|
||||
$this->viewStorage = $view_storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, $base_plugin_id) {
|
||||
return new static(
|
||||
$base_plugin_id,
|
||||
$container->get('entity.manager')->getStorage('view')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinition($derivative_id, $base_plugin_definition) {
|
||||
if (!empty($this->derivatives) && !empty($this->derivatives[$derivative_id])) {
|
||||
return $this->derivatives[$derivative_id];
|
||||
}
|
||||
$this->getDerivativeDefinitions($base_plugin_definition);
|
||||
return $this->derivatives[$derivative_id];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||
// Check all Views for displays with an exposed filter block.
|
||||
foreach ($this->viewStorage->loadMultiple() as $view) {
|
||||
// Do not return results for disabled views.
|
||||
if (!$view->status()) {
|
||||
continue;
|
||||
}
|
||||
$executable = $view->getExecutable();
|
||||
$executable->initDisplay();
|
||||
foreach ($executable->displayHandlers as $display) {
|
||||
if (isset($display) && $display->getOption('exposed_block')) {
|
||||
// Add a block definition for the block.
|
||||
if ($display->usesExposedFormInBlock()) {
|
||||
$delta = $view->id() . '-' . $display->display['id'];
|
||||
$desc = t('Exposed form: @view-@display_id', array('@view' => $view->id(), '@display_id' => $display->display['id']));
|
||||
$this->derivatives[$delta] = array(
|
||||
'admin_label' => $desc,
|
||||
'config_dependencies' => array(
|
||||
'config' => array(
|
||||
$view->getConfigDependencyName(),
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->derivatives[$delta] += $base_plugin_definition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->derivatives;
|
||||
}
|
||||
|
||||
}
|
171
core/modules/views/src/Plugin/Derivative/ViewsLocalTask.php
Normal file
171
core/modules/views/src/Plugin/Derivative/ViewsLocalTask.php
Normal file
|
@ -0,0 +1,171 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\Derivative\ViewsLocalTask.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\Derivative;
|
||||
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\State\StateInterface;
|
||||
use Drupal\Component\Plugin\Derivative\DeriverBase;
|
||||
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
||||
use Drupal\Core\Routing\RouteProviderInterface;
|
||||
use Drupal\views\ViewEntityInterface;
|
||||
use Drupal\views\Views;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides local task definitions for all views configured as local tasks.
|
||||
*/
|
||||
class ViewsLocalTask extends DeriverBase implements ContainerDeriverInterface {
|
||||
|
||||
/**
|
||||
* The route provider.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RouteProviderInterface
|
||||
*/
|
||||
protected $routeProvider;
|
||||
|
||||
/**
|
||||
* The state key value store.
|
||||
*
|
||||
* @var \Drupal\Core\State\StateInterface
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* The view storage.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
protected $viewStorage;
|
||||
|
||||
/**
|
||||
* Constructs a \Drupal\views\Plugin\Derivative\ViewsLocalTask instance.
|
||||
*
|
||||
* @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
|
||||
* The route provider.
|
||||
* @param \Drupal\Core\State\StateInterface $state
|
||||
* The state key value store.
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $view_storage
|
||||
* The view storage.
|
||||
*/
|
||||
public function __construct(RouteProviderInterface $route_provider, StateInterface $state, EntityStorageInterface $view_storage) {
|
||||
$this->routeProvider = $route_provider;
|
||||
$this->state = $state;
|
||||
$this->viewStorage = $view_storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, $base_plugin_id) {
|
||||
return new static(
|
||||
$container->get('router.route_provider'),
|
||||
$container->get('state'),
|
||||
$container->get('entity.manager')->getStorage('view')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||
$this->derivatives = array();
|
||||
|
||||
$view_route_names = $this->state->get('views.view_route_names');
|
||||
foreach ($this->getApplicableMenuViews() as $pair) {
|
||||
/** @var $executable \Drupal\views\ViewExecutable */
|
||||
list($view_id, $display_id) = $pair;
|
||||
$executable = $this->viewStorage->load($view_id)->getExecutable();
|
||||
|
||||
$executable->setDisplay($display_id);
|
||||
$menu = $executable->display_handler->getOption('menu');
|
||||
if (in_array($menu['type'], array('tab', 'default tab'))) {
|
||||
$plugin_id = 'view.' . $executable->storage->id() . '.' . $display_id;
|
||||
$route_name = $view_route_names[$executable->storage->id() . '.' . $display_id];
|
||||
|
||||
// Don't add a local task for views which override existing routes.
|
||||
// @todo Alternative it could just change the existing entry.
|
||||
if ($route_name != $plugin_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->derivatives[$plugin_id] = array(
|
||||
'route_name' => $route_name,
|
||||
'weight' => $menu['weight'],
|
||||
'title' => $menu['title'],
|
||||
) + $base_plugin_definition;
|
||||
|
||||
// Default local tasks have themselves as root tab.
|
||||
if ($menu['type'] == 'default tab') {
|
||||
$this->derivatives[$plugin_id]['base_route'] = $route_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->derivatives;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alters base_route and parent_id into the views local tasks.
|
||||
*/
|
||||
public function alterLocalTasks(&$local_tasks) {
|
||||
$view_route_names = $this->state->get('views.view_route_names');
|
||||
|
||||
foreach ($this->getApplicableMenuViews() as $pair) {
|
||||
list($view_id, $display_id) = $pair;
|
||||
/** @var $executable \Drupal\views\ViewExecutable */
|
||||
$executable = $this->viewStorage->load($view_id)->getExecutable();
|
||||
|
||||
$executable->setDisplay($display_id);
|
||||
$menu = $executable->display_handler->getOption('menu');
|
||||
|
||||
// We already have set the base_route for default tabs.
|
||||
if (in_array($menu['type'], array('tab'))) {
|
||||
$plugin_id = 'view.' . $executable->storage->id() . '.' . $display_id;
|
||||
$view_route_name = $view_route_names[$executable->storage->id() . '.' . $display_id];
|
||||
|
||||
// Don't add a local task for views which override existing routes.
|
||||
if ($view_route_name != $plugin_id) {
|
||||
unset($local_tasks[$plugin_id]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find out the parent route.
|
||||
// @todo Find out how to find both the root and parent tab.
|
||||
$path = $executable->display_handler->getPath();
|
||||
$split = explode('/', $path);
|
||||
array_pop($split);
|
||||
$path = implode('/', $split);
|
||||
|
||||
$pattern = '/' . str_replace('%', '{}', $path);
|
||||
if ($routes = $this->routeProvider->getRoutesByPattern($pattern)) {
|
||||
foreach ($routes->all() as $name => $route) {
|
||||
$local_tasks['views_view:' . $plugin_id]['base_route'] = $name;
|
||||
// Skip after the first found route.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of all views and display IDs that have a menu entry.
|
||||
*
|
||||
* @return array
|
||||
* A list of arrays containing the $view and $display_id.
|
||||
* @code
|
||||
* array(
|
||||
* array($view, $display_id),
|
||||
* array($view, $display_id),
|
||||
* );
|
||||
* @endcode
|
||||
*/
|
||||
protected function getApplicableMenuViews() {
|
||||
return Views::getApplicableViews('uses_menu_links');
|
||||
}
|
||||
|
||||
}
|
71
core/modules/views/src/Plugin/Derivative/ViewsMenuLink.php
Normal file
71
core/modules/views/src/Plugin/Derivative/ViewsMenuLink.php
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\Derivative\ViewsMenuLink.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\Derivative;
|
||||
|
||||
use Drupal\Component\Plugin\Derivative\DeriverBase;
|
||||
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides menu links for Views.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\Menu\ViewsMenuLink
|
||||
*/
|
||||
class ViewsMenuLink extends DeriverBase implements ContainerDeriverInterface {
|
||||
|
||||
/**
|
||||
* The view storage.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
protected $viewStorage;
|
||||
|
||||
/**
|
||||
* Constructs a \Drupal\views\Plugin\Derivative\ViewsLocalTask instance.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $view_storage
|
||||
* The view storage.
|
||||
*/
|
||||
public function __construct(EntityStorageInterface $view_storage) {
|
||||
$this->viewStorage = $view_storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, $base_plugin_id) {
|
||||
return new static(
|
||||
$container->get('entity.manager')->getStorage('view')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||
$links = array();
|
||||
$views = Views::getApplicableViews('uses_menu_links');
|
||||
|
||||
foreach ($views as $data) {
|
||||
list($view_id, $display_id) = $data;
|
||||
/** @var \Drupal\views\ViewExecutable $executable */
|
||||
$executable = $this->viewStorage->load($view_id)->getExecutable();
|
||||
|
||||
if ($result = $executable->getMenuLinks($display_id)) {
|
||||
foreach ($result as $link_id => $link) {
|
||||
$links[$link_id] = $link + $base_plugin_definition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,303 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\EntityReferenceSelection\ViewsSelection.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\EntityReferenceSelection;
|
||||
|
||||
use Drupal\Core\Database\Query\SelectInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Plugin\PluginBase;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\views\Views;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Plugin implementation of the 'selection' entity_reference.
|
||||
*
|
||||
* @EntityReferenceSelection(
|
||||
* id = "views",
|
||||
* label = @Translation("Views: Filter by an entity reference view"),
|
||||
* group = "views",
|
||||
* weight = 0
|
||||
* )
|
||||
*/
|
||||
class ViewsSelection extends PluginBase implements SelectionInterface, ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* The module handler service.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* The loaded View object.
|
||||
*
|
||||
* @var \Drupal\views\ViewExecutable;
|
||||
*/
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* Constructs a new ViewsSelection object.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager service.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler service.
|
||||
* @param \Drupal\Core\Session\AccountInterface $current_user
|
||||
* The current user.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, AccountInterface $current_user) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
|
||||
$this->entityManager = $entity_manager;
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->currentUser = $current_user;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('entity.manager'),
|
||||
$container->get('module_handler'),
|
||||
$container->get('current_user')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
$selection_handler_settings = $this->configuration['handler_settings'];
|
||||
$view_settings = !empty($selection_handler_settings['view']) ? $selection_handler_settings['view'] : array();
|
||||
$displays = Views::getApplicableViews('entity_reference_display');
|
||||
// Filter views that list the entity type we want, and group the separate
|
||||
// displays by view.
|
||||
$entity_type = $this->entityManager->getDefinition($this->configuration['target_type']);
|
||||
$view_storage = $this->entityManager->getStorage('view');
|
||||
|
||||
$options = array();
|
||||
foreach ($displays as $data) {
|
||||
list($view_id, $display_id) = $data;
|
||||
$view = $view_storage->load($view_id);
|
||||
if (in_array($view->get('base_table'), [$entity_type->getBaseTable(), $entity_type->getDataTable()])) {
|
||||
$display = $view->get('display');
|
||||
$options[$view_id . ':' . $display_id] = $view_id . ' - ' . $display[$display_id]['display_title'];
|
||||
}
|
||||
}
|
||||
|
||||
// The value of the 'view_and_display' select below will need to be split
|
||||
// into 'view_name' and 'view_display' in the final submitted values, so
|
||||
// we massage the data at validate time on the wrapping element (not
|
||||
// ideal).
|
||||
$form['view']['#element_validate'] = array(array(get_called_class(), 'settingsFormValidate'));
|
||||
|
||||
if ($options) {
|
||||
$default = !empty($view_settings['view_name']) ? $view_settings['view_name'] . ':' . $view_settings['display_name'] : NULL;
|
||||
$form['view']['view_and_display'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('View used to select the entities'),
|
||||
'#required' => TRUE,
|
||||
'#options' => $options,
|
||||
'#default_value' => $default,
|
||||
'#description' => '<p>' . $this->t('Choose the view and display that select the entities that can be referenced.<br />Only views with a display of type "Entity Reference" are eligible.') . '</p>',
|
||||
);
|
||||
|
||||
$default = !empty($view_settings['arguments']) ? implode(', ', $view_settings['arguments']) : '';
|
||||
$form['view']['arguments'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('View arguments'),
|
||||
'#default_value' => $default,
|
||||
'#required' => FALSE,
|
||||
'#description' => $this->t('Provide a comma separated list of arguments to pass to the view.'),
|
||||
);
|
||||
}
|
||||
else {
|
||||
if ($this->currentUser->hasPermission('administer views') && $this->moduleHandler->moduleExists('views_ui')) {
|
||||
$form['view']['no_view_help'] = array(
|
||||
'#markup' => '<p>' . $this->t('No eligible views were found. <a href="@create">Create a view</a> with an <em>Entity Reference</em> display, or add such a display to an <a href="@existing">existing view</a>.', array(
|
||||
'@create' => Url::fromRoute('views_ui.add')->toString(),
|
||||
'@existing' => Url::fromRoute('entity.view.collection')->toString(),
|
||||
)) . '</p>',
|
||||
);
|
||||
}
|
||||
else {
|
||||
$form['view']['no_view_help']['#markup'] = '<p>' . $this->t('No eligible views were found.') . '</p>';
|
||||
}
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) { }
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { }
|
||||
|
||||
/**
|
||||
* Initializes a view.
|
||||
*
|
||||
* @param string|null $match
|
||||
* (Optional) Text to match the label against. Defaults to NULL.
|
||||
* @param string $match_operator
|
||||
* (Optional) The operation the matching should be done with. Defaults
|
||||
* to "CONTAINS".
|
||||
* @param int $limit
|
||||
* Limit the query to a given number of items. Defaults to 0, which
|
||||
* indicates no limiting.
|
||||
* @param array|null $ids
|
||||
* Array of entity IDs. Defaults to NULL.
|
||||
*
|
||||
* @return bool
|
||||
* Return TRUE if the view was initialized, FALSE otherwise.
|
||||
*/
|
||||
protected function initializeView($match = NULL, $match_operator = 'CONTAINS', $limit = 0, $ids = NULL) {
|
||||
$handler_settings = $this->configuration['handler_settings'];
|
||||
$view_name = $handler_settings['view']['view_name'];
|
||||
$display_name = $handler_settings['view']['display_name'];
|
||||
|
||||
// Check that the view is valid and the display still exists.
|
||||
$this->view = Views::getView($view_name);
|
||||
if (!$this->view || !$this->view->access($display_name)) {
|
||||
drupal_set_message(t('The reference view %view_name cannot be found.', array('%view_name' => $view_name)), 'warning');
|
||||
return FALSE;
|
||||
}
|
||||
$this->view->setDisplay($display_name);
|
||||
|
||||
// Pass options to the display handler to make them available later.
|
||||
$entity_reference_options = array(
|
||||
'match' => $match,
|
||||
'match_operator' => $match_operator,
|
||||
'limit' => $limit,
|
||||
'ids' => $ids,
|
||||
);
|
||||
$this->view->displayHandlers->get($display_name)->setOption('entity_reference_options', $entity_reference_options);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getReferenceableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
|
||||
$handler_settings = $this->configuration['handler_settings'];
|
||||
$display_name = $handler_settings['view']['display_name'];
|
||||
$arguments = $handler_settings['view']['arguments'];
|
||||
$result = array();
|
||||
if ($this->initializeView($match, $match_operator, $limit)) {
|
||||
// Get the results.
|
||||
$result = $this->view->executeDisplay($display_name, $arguments);
|
||||
}
|
||||
|
||||
$return = array();
|
||||
if ($result) {
|
||||
foreach($this->view->result as $row) {
|
||||
$entity = $row->_entity;
|
||||
$return[$entity->bundle()][$entity->id()] = $entity->label();
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function countReferenceableEntities($match = NULL, $match_operator = 'CONTAINS') {
|
||||
$this->getReferenceableEntities($match, $match_operator);
|
||||
return $this->view->pager->getTotalItems();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateReferenceableEntities(array $ids) {
|
||||
$handler_settings = $this->configuration['handler_settings'];
|
||||
$display_name = $handler_settings['view']['display_name'];
|
||||
$arguments = $handler_settings['view']['arguments'];
|
||||
$result = array();
|
||||
if ($this->initializeView(NULL, 'CONTAINS', 0, $ids)) {
|
||||
// Get the results.
|
||||
$entities = $this->view->executeDisplay($display_name, $arguments);
|
||||
$result = array_keys($entities);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateAutocompleteInput($input, &$element, FormStateInterface $form_state, $form, $strict = TRUE) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function entityQueryAlter(SelectInterface $query) {}
|
||||
|
||||
/**
|
||||
* Element validate; Check View is valid.
|
||||
*/
|
||||
public static function settingsFormValidate($element, FormStateInterface $form_state, $form) {
|
||||
// Split view name and display name from the 'view_and_display' value.
|
||||
if (!empty($element['view_and_display']['#value'])) {
|
||||
list($view, $display) = explode(':', $element['view_and_display']['#value']);
|
||||
}
|
||||
else {
|
||||
$form_state->setError($element, t('The views entity selection mode requires a view.'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Explode the 'arguments' string into an actual array. Beware, explode()
|
||||
// turns an empty string into an array with one empty string. We'll need an
|
||||
// empty array instead.
|
||||
$arguments_string = trim($element['arguments']['#value']);
|
||||
if ($arguments_string === '') {
|
||||
$arguments = array();
|
||||
}
|
||||
else {
|
||||
// array_map() is called to trim whitespaces from the arguments.
|
||||
$arguments = array_map('trim', explode(',', $arguments_string));
|
||||
}
|
||||
|
||||
$value = array('view_name' => $view, 'display_name' => $display, 'arguments' => $arguments);
|
||||
$form_state->setValueForElement($element, $value);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\Menu\Form\ViewsMenuLinkForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\Menu\Form;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Menu\Form\MenuLinkDefaultForm;
|
||||
|
||||
/**
|
||||
* Provides a form to edit Views menu links.
|
||||
*
|
||||
* This provides the feature to edit the title and description, in contrast to
|
||||
* the default menu link form.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\Menu\ViewsMenuLink
|
||||
*/
|
||||
class ViewsMenuLinkForm extends MenuLinkDefaultForm {
|
||||
|
||||
/**
|
||||
* The edited views menu link.
|
||||
*
|
||||
* @var \Drupal\views\Plugin\Menu\ViewsMenuLink
|
||||
*/
|
||||
protected $menuLink;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
|
||||
// Put the title field first.
|
||||
$form['title'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Title'),
|
||||
// @todo Ensure that the view is not loaded with a localized title.
|
||||
// https://www.drupal.org/node/2309507
|
||||
'#default_value' => $this->menuLink->getTitle(),
|
||||
'#weight' => -10,
|
||||
);
|
||||
|
||||
$form['description'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Description'),
|
||||
'#description' => $this->t('Shown when hovering over the menu link.'),
|
||||
// @todo Ensure that the view is not loaded with a localized description.
|
||||
// https://www.drupal.org/node/2309507
|
||||
'#default_value' => $this->menuLink->getDescription(),
|
||||
'#weight' => -5,
|
||||
);
|
||||
|
||||
$form += parent::buildConfigurationForm($form, $form_state);
|
||||
|
||||
$form['info']['#weight'] = -8;
|
||||
$form['path']['#weight'] = -7;
|
||||
|
||||
$view = $this->menuLink->loadView();
|
||||
$id = $view->storage->id();
|
||||
$label = $view->storage->label();
|
||||
if ($this->moduleHandler->moduleExists('views_ui')) {
|
||||
$message = $this->t('This link is provided by the Views module. The path can be changed by editing the view <a href="@url">@label</a>', array('@url' => \Drupal::url('entity.view.edit_form', array('view' => $id)), '@label' => $label));
|
||||
}
|
||||
else {
|
||||
$message = $this->t('This link is provided by the Views module from view %label.', array('%label' => $label));
|
||||
}
|
||||
$form['info']['#title'] = $message;
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function extractFormValues(array &$form, FormStateInterface $form_state) {
|
||||
$definition = parent::extractFormValues($form, $form_state);
|
||||
$definition['title'] = $form_state->getValue('title');
|
||||
$definition['description'] = $form_state->getValue('description');
|
||||
|
||||
return $definition;
|
||||
}
|
||||
|
||||
}
|
170
core/modules/views/src/Plugin/Menu/ViewsMenuLink.php
Normal file
170
core/modules/views/src/Plugin/Menu/ViewsMenuLink.php
Normal file
|
@ -0,0 +1,170 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\Menu\ViewsMenuLink.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\Menu;
|
||||
|
||||
use Drupal\Core\Menu\MenuLinkBase;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\views\ViewExecutableFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Defines menu links provided by views.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\Derivative\ViewsMenuLink
|
||||
*/
|
||||
class ViewsMenuLink extends MenuLinkBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $overrideAllowed = array(
|
||||
'menu_name' => 1,
|
||||
'parent' => 1,
|
||||
'weight' => 1,
|
||||
'expanded' => 1,
|
||||
'enabled' => 1,
|
||||
'title' => 1,
|
||||
'description' => 1,
|
||||
'metadata' => 1,
|
||||
);
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* The view executable factory.
|
||||
*
|
||||
* @var \Drupal\views\ViewExecutableFactory
|
||||
*/
|
||||
protected $viewExecutableFactory;
|
||||
|
||||
/**
|
||||
* The view executable of the menu link.
|
||||
*
|
||||
* @var \Drupal\views\ViewExecutable
|
||||
*/
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* Constructs a new ViewsMenuLink.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager
|
||||
* @param \Drupal\views\ViewExecutableFactory $view_executable_factory
|
||||
* The view executable factory
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, ViewExecutableFactory $view_executable_factory) {
|
||||
$this->configuration = $configuration;
|
||||
$this->pluginId = $plugin_id;
|
||||
$this->pluginDefinition = $plugin_definition;
|
||||
|
||||
$this->entityManager = $entity_manager;
|
||||
$this->viewExecutableFactory = $view_executable_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('entity.manager'),
|
||||
$container->get('views.executable')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the proper view.
|
||||
*
|
||||
* @return \Drupal\views\ViewExecutable
|
||||
* The view executable.
|
||||
*/
|
||||
public function loadView() {
|
||||
if (empty($this->view)) {
|
||||
$metadata = $this->getMetaData();
|
||||
$view_id = $metadata['view_id'];
|
||||
$display_id = $metadata['display_id'];
|
||||
$view_entity = $this->entityManager->getStorage('view')->load($view_id);
|
||||
$view = $this->viewExecutableFactory->get($view_entity);
|
||||
$view->setDisplay($display_id);
|
||||
$view->initDisplay();
|
||||
$this->view = $view;
|
||||
}
|
||||
return $this->view;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTitle() {
|
||||
// @todo Get the translated value from the config without instantiating the
|
||||
// view. https://www.drupal.org/node/2310379
|
||||
return $this->loadView()->display_handler->getOption('menu')['title'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDescription() {
|
||||
return $this->loadView()->display_handler->getOption('menu')['description'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function updateLink(array $new_definition_values, $persist) {
|
||||
$overrides = array_intersect_key($new_definition_values, $this->overrideAllowed);
|
||||
// Update the definition.
|
||||
$this->pluginDefinition = $overrides + $this->pluginDefinition;
|
||||
if ($persist) {
|
||||
$view = $this->loadView();
|
||||
$display = &$view->storage->getDisplay($view->current_display);
|
||||
// Just save the title to the original view.
|
||||
$changed = FALSE;
|
||||
foreach ($new_definition_values as $key => $new_definition_value) {
|
||||
if (isset($display['display_options']['menu'][$key]) && $display['display_options']['menu'][$key] != $new_definition_values[$key]) {
|
||||
$display['display_options']['menu'][$key] = $new_definition_values[$key];
|
||||
$changed = TRUE;
|
||||
}
|
||||
}
|
||||
if ($changed) {
|
||||
// @todo Improve this to not trigger a full rebuild of everything, if we
|
||||
// just changed some properties. https://www.drupal.org/node/2310389
|
||||
$view->storage->save();
|
||||
}
|
||||
}
|
||||
return $this->pluginDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isDeletable() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteLink() {
|
||||
}
|
||||
|
||||
}
|
140
core/modules/views/src/Plugin/ViewsHandlerManager.php
Normal file
140
core/modules/views/src/Plugin/ViewsHandlerManager.php
Normal file
|
@ -0,0 +1,140 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\ViewsHandlerManager.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin;
|
||||
|
||||
use Drupal\Component\Plugin\FallbackPluginManagerInterface;
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Plugin\DefaultPluginManager;
|
||||
use Drupal\views\ViewsData;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Drupal\views\Plugin\views\HandlerBase;
|
||||
|
||||
/**
|
||||
* Plugin type manager for all views handlers.
|
||||
*/
|
||||
class ViewsHandlerManager extends DefaultPluginManager implements FallbackPluginManagerInterface {
|
||||
|
||||
/**
|
||||
* The views data cache.
|
||||
*
|
||||
* @var \Drupal\views\ViewsData
|
||||
*/
|
||||
protected $viewsData;
|
||||
|
||||
/**
|
||||
* The handler type.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @see \Drupal\views\ViewExecutable::getHandlerTypes().
|
||||
*/
|
||||
protected $handlerType;
|
||||
|
||||
/**
|
||||
* Constructs a ViewsHandlerManager object.
|
||||
*
|
||||
* @param string $handler_type
|
||||
* The plugin type, for example filter.
|
||||
* @param \Traversable $namespaces
|
||||
* An object that implements \Traversable which contains the root paths
|
||||
* keyed by the corresponding namespace to look for plugin implementations,
|
||||
* @param \Drupal\views\ViewsData $views_data
|
||||
* The views data cache.
|
||||
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
|
||||
* Cache backend instance to use.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler to invoke the alter hook with.
|
||||
*/
|
||||
public function __construct($handler_type, \Traversable $namespaces, ViewsData $views_data, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
|
||||
$plugin_definition_annotation_name = 'Drupal\views\Annotation\Views' . Container::camelize($handler_type);
|
||||
$plugin_interface = 'Drupal\views\Plugin\views\ViewsHandlerInterface';
|
||||
if ($handler_type == 'join') {
|
||||
$plugin_interface = 'Drupal\views\Plugin\views\join\JoinPluginInterface';
|
||||
}
|
||||
parent::__construct("Plugin/views/$handler_type", $namespaces, $module_handler, $plugin_interface, $plugin_definition_annotation_name);
|
||||
|
||||
$this->setCacheBackend($cache_backend, "views:$handler_type");
|
||||
$this->alterInfo('views_plugins_' . $handler_type);
|
||||
|
||||
$this->viewsData = $views_data;
|
||||
$this->handlerType = $handler_type;
|
||||
$this->defaults = array(
|
||||
'plugin_type' => $handler_type,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a handler from the data cache.
|
||||
*
|
||||
* @param array $item
|
||||
* An associative array representing the handler to be retrieved:
|
||||
* - table: The name of the table containing the handler.
|
||||
* - field: The name of the field the handler represents.
|
||||
* @param string|null $override
|
||||
* (optional) Override the actual handler object with this plugin ID. Used for
|
||||
* aggregation when the handler is redirected to the aggregation handler.
|
||||
*
|
||||
* @return \Drupal\views\Plugin\views\ViewsHandlerInterface
|
||||
* An instance of a handler object. May be a broken handler instance.
|
||||
*/
|
||||
public function getHandler($item, $override = NULL) {
|
||||
$table = $item['table'];
|
||||
$field = $item['field'];
|
||||
// Get the plugin manager for this type.
|
||||
$data = $this->viewsData->get($table);
|
||||
|
||||
if (isset($data[$field][$this->handlerType])) {
|
||||
$definition = $data[$field][$this->handlerType];
|
||||
foreach (array('group', 'title', 'title short', 'help', 'real field', 'real table', 'entity type', 'entity field') as $key) {
|
||||
if (!isset($definition[$key])) {
|
||||
// First check the field level.
|
||||
if (!empty($data[$field][$key])) {
|
||||
$definition[$key] = $data[$field][$key];
|
||||
}
|
||||
// Then if that doesn't work, check the table level.
|
||||
elseif (!empty($data['table'][$key])) {
|
||||
$definition_key = $key === 'entity type' ? 'entity_type' : $key;
|
||||
$definition[$definition_key] = $data['table'][$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @todo This is crazy. Find a way to remove the override functionality.
|
||||
$plugin_id = $override ? : $definition['id'];
|
||||
// Try to use the overridden handler.
|
||||
$handler = $this->createInstance($plugin_id, $definition);
|
||||
if ($override && method_exists($handler, 'broken') && $handler->broken()) {
|
||||
$handler = $this->createInstance($definition['id'], $definition);
|
||||
}
|
||||
return $handler;
|
||||
}
|
||||
|
||||
// Finally, use the 'broken' handler.
|
||||
return $this->createInstance('broken', array('original_configuration' => $item));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createInstance($plugin_id, array $configuration = array()) {
|
||||
$instance = parent::createInstance($plugin_id, $configuration);
|
||||
if ($instance instanceof HandlerBase) {
|
||||
$instance->setModuleHandler($this->moduleHandler);
|
||||
$instance->setViewsData($this->viewsData);
|
||||
}
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFallbackPluginId($plugin_id, array $configuration = array()) {
|
||||
return 'broken';
|
||||
}
|
||||
}
|
49
core/modules/views/src/Plugin/ViewsPluginManager.php
Normal file
49
core/modules/views/src/Plugin/ViewsPluginManager.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\ViewsPluginManager.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin;
|
||||
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Plugin\DefaultPluginManager;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
|
||||
/**
|
||||
* Plugin type manager for all views plugins.
|
||||
*
|
||||
* @ingroup views_plugins
|
||||
*/
|
||||
class ViewsPluginManager extends DefaultPluginManager {
|
||||
|
||||
/**
|
||||
* Constructs a ViewsPluginManager object.
|
||||
*
|
||||
* @param string $type
|
||||
* The plugin type, for example filter.
|
||||
* @param \Traversable $namespaces
|
||||
* An object that implements \Traversable which contains the root paths
|
||||
* keyed by the corresponding namespace to look for plugin implementations,
|
||||
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
|
||||
* Cache backend instance to use.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler to invoke the alter hook with.
|
||||
*/
|
||||
public function __construct($type, \Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
|
||||
$plugin_definition_annotation_name = 'Drupal\views\Annotation\Views' . Container::camelize($type);
|
||||
parent::__construct("Plugin/views/$type", $namespaces, $module_handler, 'Drupal\views\Plugin\views\ViewsPluginInterface', $plugin_definition_annotation_name);
|
||||
|
||||
$this->defaults += array(
|
||||
'parent' => 'parent',
|
||||
'plugin_type' => $type,
|
||||
'register_theme' => TRUE,
|
||||
);
|
||||
|
||||
$this->alterInfo('views_plugins_' . $type);
|
||||
$this->setCacheBackend($cache_backend, "views:$type");
|
||||
}
|
||||
|
||||
}
|
109
core/modules/views/src/Plugin/views/BrokenHandlerTrait.php
Normal file
109
core/modules/views/src/Plugin/views/BrokenHandlerTrait.php
Normal file
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\views\BrokenHandlerTrait.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\views;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* A Trait for Views broken handlers.
|
||||
*/
|
||||
trait BrokenHandlerTrait {
|
||||
|
||||
/**
|
||||
* Returns this handlers name in the UI.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\PluginBase::defineOptions().
|
||||
*/
|
||||
public function adminLabel($short = FALSE) {
|
||||
return t('Broken/missing handler');
|
||||
}
|
||||
|
||||
/**
|
||||
* The option definition for this handler.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\PluginBase::defineOptions().
|
||||
*/
|
||||
public function defineOptions() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the main table for this handler is in the query. This is used
|
||||
* a lot.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\HandlerBase::ensureMyTable().
|
||||
*/
|
||||
public function ensureMyTable() {
|
||||
// No table to ensure.
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the views query.
|
||||
*/
|
||||
public function query($group_by = FALSE) {
|
||||
/* No query to run */
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a form to edit options for this plugin.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\PluginBase::defineOptions().
|
||||
*/
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
$description_top = t('The handler for this item is broken or missing. The following details are available:');
|
||||
|
||||
foreach ($this->definition['original_configuration'] as $key => $value) {
|
||||
if (is_scalar($value)) {
|
||||
$items[] = SafeMarkup::format('@key: @value', array('@key' => $key, '@value' => $value));
|
||||
}
|
||||
}
|
||||
|
||||
$description_bottom = t('Enabling the appropriate module will may solve this issue. Otherwise, check to see if there is a module update available.');
|
||||
|
||||
$form['description'] = array(
|
||||
'#type' => 'container',
|
||||
'#attributes' => array(
|
||||
'class' => array('form-item', 'description'),
|
||||
),
|
||||
'description_top' => array(
|
||||
'#markup' => '<p>' . $description_top . '</p>',
|
||||
),
|
||||
'detail_list' => array(
|
||||
'#theme' => 'item_list',
|
||||
'#items' => $items,
|
||||
),
|
||||
'description_bottom' => array(
|
||||
'#markup' => '<p>' . $description_bottom . '</p>',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the handler is considered 'broken'.
|
||||
*
|
||||
* This means it's a placeholder used when a handler can't be found.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\HandlerBase::broken().
|
||||
*/
|
||||
public function broken() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets dependencies for a broken handler.
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\PluginBase::calculateDependencies().
|
||||
*/
|
||||
public function calculateDependencies() {
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
845
core/modules/views/src/Plugin/views/HandlerBase.php
Normal file
845
core/modules/views/src/Plugin/views/HandlerBase.php
Normal file
|
@ -0,0 +1,845 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\views\HandlerBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\views;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Component\Utility\UrlHelper;
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\views\ViewsData;
|
||||
|
||||
/**
|
||||
* Base class for Views handler plugins.
|
||||
*
|
||||
* @ingroup views_plugins
|
||||
*/
|
||||
abstract class HandlerBase extends PluginBase implements ViewsHandlerInterface {
|
||||
|
||||
/**
|
||||
* Where the $query object will reside:
|
||||
*
|
||||
* @var \Drupal\views\Plugin\views\query\QueryPluginBase
|
||||
*/
|
||||
public $query = NULL;
|
||||
|
||||
/**
|
||||
* The table this handler is attached to.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $table;
|
||||
|
||||
/**
|
||||
* The alias of the table of this handler which is used in the query.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $tableAlias;
|
||||
|
||||
/**
|
||||
* When a table has been moved this property is set.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $actualTable;
|
||||
|
||||
/**
|
||||
* The actual field in the database table, maybe different
|
||||
* on other kind of query plugins/special handlers.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $realField;
|
||||
|
||||
/**
|
||||
* With field you can override the realField if the real field is not set.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $field;
|
||||
|
||||
/**
|
||||
* When a field has been moved this property is set.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $actualField;
|
||||
|
||||
/**
|
||||
* The relationship used for this field.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $relationship = NULL;
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The views data service.
|
||||
*
|
||||
* @var \Drupal\views\ViewsData
|
||||
*/
|
||||
protected $viewsData;
|
||||
|
||||
/**
|
||||
* Constructs a Handler object.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->is_handler = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
|
||||
parent::init($view, $display, $options);
|
||||
|
||||
// Check to see if this handler type is defaulted. Note that
|
||||
// we have to do a lookup because the type is singular but the
|
||||
// option is stored as the plural.
|
||||
|
||||
// If the 'moved to' keyword moved our handler, let's fix that now.
|
||||
if (isset($this->actualTable)) {
|
||||
$options['table'] = $this->actualTable;
|
||||
}
|
||||
|
||||
if (isset($this->actualField)) {
|
||||
$options['field'] = $this->actualField;
|
||||
}
|
||||
|
||||
$this->unpackOptions($this->options, $options);
|
||||
|
||||
// This exist on most handlers, but not all. So they are still optional.
|
||||
if (isset($options['table'])) {
|
||||
$this->table = $options['table'];
|
||||
}
|
||||
|
||||
// Allow aliases on both fields and tables.
|
||||
if (isset($this->definition['real table'])) {
|
||||
$this->table = $this->definition['real table'];
|
||||
}
|
||||
|
||||
if (isset($this->definition['real field'])) {
|
||||
$this->realField = $this->definition['real field'];
|
||||
}
|
||||
|
||||
if (isset($this->definition['field'])) {
|
||||
$this->realField = $this->definition['field'];
|
||||
}
|
||||
|
||||
if (isset($options['field'])) {
|
||||
$this->field = $options['field'];
|
||||
if (!isset($this->realField)) {
|
||||
$this->realField = $options['field'];
|
||||
}
|
||||
}
|
||||
|
||||
$this->query = &$view->query;
|
||||
}
|
||||
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
|
||||
$options['id'] = array('default' => '');
|
||||
$options['table'] = array('default' => '');
|
||||
$options['field'] = array('default' => '');
|
||||
$options['relationship'] = array('default' => 'none');
|
||||
$options['group_type'] = array('default' => 'group');
|
||||
$options['admin_label'] = array('default' => '');
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function adminLabel($short = FALSE) {
|
||||
if (!empty($this->options['admin_label'])) {
|
||||
$title = SafeMarkup::checkPlain($this->options['admin_label']);
|
||||
return $title;
|
||||
}
|
||||
$title = ($short && isset($this->definition['title short'])) ? $this->definition['title short'] : $this->definition['title'];
|
||||
return $this->t('!group: !title', array('!group' => $this->definition['group'], '!title' => $title));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getField($field = NULL) {
|
||||
if (!isset($field)) {
|
||||
if (!empty($this->formula)) {
|
||||
$field = $this->getFormula();
|
||||
}
|
||||
else {
|
||||
$field = $this->tableAlias . '.' . $this->realField;
|
||||
}
|
||||
}
|
||||
|
||||
// If grouping, check to see if the aggregation method needs to modify the field.
|
||||
if ($this->view->display_handler->useGroupBy()) {
|
||||
$this->view->initQuery();
|
||||
if ($this->query) {
|
||||
$info = $this->query->getAggregationInfo();
|
||||
if (!empty($info[$this->options['group_type']]['method'])) {
|
||||
$method = $info[$this->options['group_type']]['method'];
|
||||
if (method_exists($this->query, $method)) {
|
||||
return $this->query->$method($this->options['group_type'], $field);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sanitizeValue($value, $type = NULL) {
|
||||
switch ($type) {
|
||||
case 'xss':
|
||||
$value = Xss::filter($value);
|
||||
break;
|
||||
case 'xss_admin':
|
||||
$value = Xss::filterAdmin($value);
|
||||
break;
|
||||
case 'url':
|
||||
$value = SafeMarkup::checkPlain(UrlHelper::stripDangerousProtocols($value));
|
||||
break;
|
||||
default:
|
||||
$value = SafeMarkup::checkPlain($value);
|
||||
break;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a string by a certain method.
|
||||
*
|
||||
* @param $string
|
||||
* The input you want to transform.
|
||||
* @param $option
|
||||
* How do you want to transform it, possible values:
|
||||
* - upper: Uppercase the string.
|
||||
* - lower: lowercase the string.
|
||||
* - ucfirst: Make the first char uppercase.
|
||||
* - ucwords: Make each word in the string uppercase.
|
||||
*
|
||||
* @return string
|
||||
* The transformed string.
|
||||
*/
|
||||
protected function caseTransform($string, $option) {
|
||||
switch ($option) {
|
||||
default:
|
||||
return $string;
|
||||
case 'upper':
|
||||
return Unicode::strtoupper($string);
|
||||
case 'lower':
|
||||
return Unicode::strtolower($string);
|
||||
case 'ucfirst':
|
||||
return Unicode::ucfirst($string);
|
||||
case 'ucwords':
|
||||
return Unicode::ucwords($string);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
// Some form elements belong in a fieldset for presentation, but can't
|
||||
// be moved into one because of the $form_state->getValues() hierarchy. Those
|
||||
// elements can add a #fieldset => 'fieldset_name' property, and they'll
|
||||
// be moved to their fieldset during pre_render.
|
||||
$form['#pre_render'][] = array(get_class($this), 'preRenderAddFieldsetMarkup');
|
||||
|
||||
parent::buildOptionsForm($form, $form_state);
|
||||
|
||||
$form['fieldsets'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => array('more', 'admin_label'),
|
||||
);
|
||||
|
||||
$form['admin_label'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' =>$this->t('Administrative title'),
|
||||
'#weight' => 150,
|
||||
);
|
||||
$form['admin_label']['admin_label'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Administrative title'),
|
||||
'#description' => $this->t('This title will be displayed on the views edit page instead of the default one. This might be useful if you have the same item twice.'),
|
||||
'#default_value' => $this->options['admin_label'],
|
||||
'#parents' => array('options', 'admin_label'),
|
||||
);
|
||||
|
||||
// This form is long and messy enough that the "Administrative title" option
|
||||
// belongs in "Administrative title" fieldset at the bottom of the form.
|
||||
$form['more'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('More'),
|
||||
'#weight' => 200,
|
||||
);
|
||||
// Allow to alter the default values brought into the form.
|
||||
// @todo Do we really want to keep this hook.
|
||||
$this->getModuleHandler()->alter('views_handler_options', $this->options, $this->view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the module handler.
|
||||
*
|
||||
* @return \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected function getModuleHandler() {
|
||||
if (!$this->moduleHandler) {
|
||||
$this->moduleHandler = \Drupal::moduleHandler();
|
||||
}
|
||||
|
||||
return $this->moduleHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the module handler.
|
||||
*
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
*/
|
||||
public function setModuleHandler(ModuleHandlerInterface $module_handler) {
|
||||
$this->moduleHandler = $module_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the handler some groupby.
|
||||
*/
|
||||
public function usesGroupBy() {
|
||||
return TRUE;
|
||||
}
|
||||
/**
|
||||
* Provide a form for aggregation settings.
|
||||
*/
|
||||
public function buildGroupByForm(&$form, FormStateInterface $form_state) {
|
||||
$display_id = $form_state->get('display_id');
|
||||
$type = $form_state->get('type');
|
||||
$id = $form_state->get('id');
|
||||
|
||||
$form['#section'] = $display_id . '-' . $type . '-' . $id;
|
||||
|
||||
$this->view->initQuery();
|
||||
$info = $this->view->query->getAggregationInfo();
|
||||
foreach ($info as $id => $aggregate) {
|
||||
$group_types[$id] = $aggregate['title'];
|
||||
}
|
||||
|
||||
$form['group_type'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Aggregation type'),
|
||||
'#default_value' => $this->options['group_type'],
|
||||
'#description' => $this->t('Select the aggregation function to use on this field.'),
|
||||
'#options' => $group_types,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any necessary changes to the form values prior to storage.
|
||||
* There is no need for this function to actually store the data.
|
||||
*/
|
||||
public function submitGroupByForm(&$form, FormStateInterface $form_state) {
|
||||
$form_state->get('handler')->options['group_type'] = $form_state->getValue(['options', 'group_type']);
|
||||
}
|
||||
|
||||
/**
|
||||
* If a handler has 'extra options' it will get a little settings widget and
|
||||
* another form called extra_options.
|
||||
*/
|
||||
public function hasExtraOptions() { return FALSE; }
|
||||
|
||||
/**
|
||||
* Provide defaults for the handler.
|
||||
*/
|
||||
public function defineExtraOptions(&$option) { }
|
||||
|
||||
/**
|
||||
* Provide a form for setting options.
|
||||
*/
|
||||
public function buildExtraOptionsForm(&$form, FormStateInterface $form_state) { }
|
||||
|
||||
/**
|
||||
* Validate the options form.
|
||||
*/
|
||||
public function validateExtraOptionsForm($form, FormStateInterface $form_state) { }
|
||||
|
||||
/**
|
||||
* Perform any necessary changes to the form values prior to storage.
|
||||
* There is no need for this function to actually store the data.
|
||||
*/
|
||||
public function submitExtraOptionsForm($form, FormStateInterface $form_state) { }
|
||||
|
||||
/**
|
||||
* Determine if a handler can be exposed.
|
||||
*/
|
||||
public function canExpose() { return FALSE; }
|
||||
|
||||
/**
|
||||
* Set new exposed option defaults when exposed setting is flipped
|
||||
* on.
|
||||
*/
|
||||
public function defaultExposeOptions() { }
|
||||
|
||||
/**
|
||||
* Get information about the exposed form for the form renderer.
|
||||
*/
|
||||
public function exposedInfo() { }
|
||||
|
||||
/**
|
||||
* Render our chunk of the exposed handler form when selecting
|
||||
*/
|
||||
public function buildExposedForm(&$form, FormStateInterface $form_state) { }
|
||||
|
||||
/**
|
||||
* Validate the exposed handler form
|
||||
*/
|
||||
public function validateExposed(&$form, FormStateInterface $form_state) { }
|
||||
|
||||
/**
|
||||
* Submit the exposed handler form
|
||||
*/
|
||||
public function submitExposed(&$form, FormStateInterface $form_state) { }
|
||||
|
||||
/**
|
||||
* Form for exposed handler options.
|
||||
*/
|
||||
public function buildExposeForm(&$form, FormStateInterface $form_state) { }
|
||||
|
||||
/**
|
||||
* Validate the options form.
|
||||
*/
|
||||
public function validateExposeForm($form, FormStateInterface $form_state) { }
|
||||
|
||||
/**
|
||||
* Perform any necessary changes to the form exposes prior to storage.
|
||||
* There is no need for this function to actually store the data.
|
||||
*/
|
||||
public function submitExposeForm($form, FormStateInterface $form_state) { }
|
||||
|
||||
/**
|
||||
* Shortcut to display the expose/hide button.
|
||||
*/
|
||||
public function showExposeButton(&$form, FormStateInterface $form_state) { }
|
||||
|
||||
/**
|
||||
* Shortcut to display the exposed options form.
|
||||
*/
|
||||
public function showExposeForm(&$form, FormStateInterface $form_state) {
|
||||
if (empty($this->options['exposed'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->buildExposeForm($form, $form_state);
|
||||
|
||||
// When we click the expose button, we add new gadgets to the form but they
|
||||
// have no data in POST so their defaults get wiped out. This prevents
|
||||
// these defaults from getting wiped out. This setting will only be TRUE
|
||||
// during a 2nd pass rerender.
|
||||
if ($form_state->get('force_expose_options')) {
|
||||
foreach (Element::children($form['expose']) as $id) {
|
||||
if (isset($form['expose'][$id]['#default_value']) && !isset($form['expose'][$id]['#value'])) {
|
||||
$form['expose'][$id]['#value'] = $form['expose'][$id]['#default_value'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function access(AccountInterface $account) {
|
||||
if (isset($this->definition['access callback']) && function_exists($this->definition['access callback'])) {
|
||||
if (isset($this->definition['access arguments']) && is_array($this->definition['access arguments'])) {
|
||||
return call_user_func_array($this->definition['access callback'], array($account) + $this->definition['access arguments']);
|
||||
}
|
||||
return $this->definition['access callback']($account);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function preQuery() {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function postExecute(&$values) { }
|
||||
|
||||
/**
|
||||
* Provides a unique placeholders for handlers.
|
||||
*
|
||||
* @return string
|
||||
* A placeholder which contains the table and the fieldname.
|
||||
*/
|
||||
protected function placeholder() {
|
||||
return $this->query->placeholder($this->table . '_' . $this->field);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setRelationship() {
|
||||
// Ensure this gets set to something.
|
||||
$this->relationship = NULL;
|
||||
|
||||
// Don't process non-existent relationships.
|
||||
if (empty($this->options['relationship']) || $this->options['relationship'] == 'none') {
|
||||
return;
|
||||
}
|
||||
|
||||
$relationship = $this->options['relationship'];
|
||||
|
||||
// Ignore missing/broken relationships.
|
||||
if (empty($this->view->relationship[$relationship])) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check to see if the relationship has already processed. If not, then we
|
||||
// cannot process it.
|
||||
if (empty($this->view->relationship[$relationship]->alias)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Finally!
|
||||
$this->relationship = $this->view->relationship[$relationship]->alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function ensureMyTable() {
|
||||
if (!isset($this->tableAlias)) {
|
||||
$this->tableAlias = $this->query->ensureTable($this->table, $this->relationship);
|
||||
}
|
||||
return $this->tableAlias;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function adminSummary() { }
|
||||
|
||||
/**
|
||||
* Determine if this item is 'exposed', meaning it provides form elements
|
||||
* to let users modify the view.
|
||||
*
|
||||
* @return TRUE/FALSE
|
||||
*/
|
||||
public function isExposed() {
|
||||
return !empty($this->options['exposed']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if the exposed filter works like a grouped filter.
|
||||
*/
|
||||
public function isAGroup() { return FALSE; }
|
||||
|
||||
/**
|
||||
* Define if the exposed input has to be submitted multiple times.
|
||||
* This is TRUE when exposed filters grouped are using checkboxes as
|
||||
* widgets.
|
||||
*/
|
||||
public function multipleExposedInput() { return FALSE; }
|
||||
|
||||
/**
|
||||
* Take input from exposed handlers and assign to this handler, if necessary.
|
||||
*/
|
||||
public function acceptExposedInput($input) { return TRUE; }
|
||||
|
||||
/**
|
||||
* If set to remember exposed input in the session, store it there.
|
||||
*/
|
||||
public function storeExposedInput($input, $status) { return TRUE; }
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getJoin() {
|
||||
// get the join from this table that links back to the base table.
|
||||
// Determine the primary table to seek
|
||||
if (empty($this->query->relationships[$this->relationship])) {
|
||||
$base_table = $this->view->storage->get('base_table');
|
||||
}
|
||||
else {
|
||||
$base_table = $this->query->relationships[$this->relationship]['base'];
|
||||
}
|
||||
|
||||
$join = $this->getTableJoin($this->table, $base_table);
|
||||
if ($join) {
|
||||
return clone $join;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate() { return array(); }
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function broken() {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates cross-database SQL date formatting.
|
||||
*
|
||||
* @param string $format
|
||||
* A format string for the result, like 'Y-m-d H:i:s'.
|
||||
*
|
||||
* @return string
|
||||
* An appropriate SQL string for the DB type and field type.
|
||||
*/
|
||||
public function getDateFormat($format) {
|
||||
return $this->query->getDateFormat($this->getDateField(), $format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates cross-database SQL dates.
|
||||
*
|
||||
* @return string
|
||||
* An appropriate SQL string for the db type and field type.
|
||||
*/
|
||||
public function getDateField() {
|
||||
return $this->query->getDateField("$this->tableAlias.$this->realField");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets views data service.
|
||||
*
|
||||
* @return \Drupal\views\ViewsData
|
||||
*/
|
||||
protected function getViewsData() {
|
||||
if (!$this->viewsData) {
|
||||
$this->viewsData = Views::viewsData();
|
||||
}
|
||||
|
||||
return $this->viewsData;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setViewsData(ViewsData $views_data) {
|
||||
$this->viewsData = $views_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getTableJoin($table, $base_table) {
|
||||
$data = Views::viewsData()->get($table);
|
||||
if (isset($data['table']['join'][$base_table])) {
|
||||
$join_info = $data['table']['join'][$base_table];
|
||||
if (!empty($join_info['join_id'])) {
|
||||
$id = $join_info['join_id'];
|
||||
}
|
||||
else {
|
||||
$id = 'standard';
|
||||
}
|
||||
|
||||
$configuration = $join_info;
|
||||
// Fill in some easy defaults.
|
||||
if (empty($configuration['table'])) {
|
||||
$configuration['table'] = $table;
|
||||
}
|
||||
// If this is empty, it's a direct link.
|
||||
if (empty($configuration['left_table'])) {
|
||||
$configuration['left_table'] = $base_table;
|
||||
}
|
||||
|
||||
if (isset($join_info['arguments'])) {
|
||||
foreach ($join_info['arguments'] as $key => $argument) {
|
||||
$configuration[$key] = $argument;
|
||||
}
|
||||
}
|
||||
|
||||
$join = Views::pluginManager('join')->createInstance($id, $configuration);
|
||||
|
||||
return $join;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getEntityType() {
|
||||
// If the user has configured a relationship on the handler take that into
|
||||
// account.
|
||||
if (!empty($this->options['relationship']) && $this->options['relationship'] != 'none') {
|
||||
$relationship = $this->displayHandler->getOption('relationships')[$this->options['relationship']];
|
||||
$table_data = $this->getViewsData()->get($relationship['table']);
|
||||
$views_data = $this->getViewsData()->get($table_data[$relationship['field']]['relationship']['base']);
|
||||
}
|
||||
else {
|
||||
$views_data = $this->getViewsData()->get($this->view->storage->get('base_table'));
|
||||
}
|
||||
|
||||
if (isset($views_data['table']['entity type'])) {
|
||||
return $views_data['table']['entity type'];
|
||||
}
|
||||
else {
|
||||
throw new \Exception(SafeMarkup::format('No entity type for field @field on view @view', array('@field' => $this->options['id'], '@view' => $this->view->storage->id())));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function breakString($str, $force_int = FALSE) {
|
||||
$operator = NULL;
|
||||
$value = array();
|
||||
|
||||
// Determine if the string has 'or' operators (plus signs) or 'and'
|
||||
// operators (commas) and split the string accordingly.
|
||||
if (preg_match('/^([\w0-9-_]+[+ ]+)+[\w0-9-_]+$/u', $str)) {
|
||||
// The '+' character in a query string may be parsed as ' '.
|
||||
$operator = 'or';
|
||||
$value = preg_split('/[+ ]/', $str);
|
||||
}
|
||||
elseif (preg_match('/^([\w0-9-_]+[, ]+)*[\w0-9-_]+$/u', $str)) {
|
||||
$operator = 'and';
|
||||
$value = explode(',', $str);
|
||||
}
|
||||
|
||||
// Filter any empty matches (Like from '++' in a string) and reset the
|
||||
// array keys. 'strlen' is used as the filter callback so we do not lose
|
||||
// 0 values (would otherwise evaluate == FALSE).
|
||||
$value = array_values(array_filter($value, 'strlen'));
|
||||
|
||||
if ($force_int) {
|
||||
$value = array_map('intval', $value);
|
||||
}
|
||||
|
||||
return (object) array('value' => $value, 'operator' => $operator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the Expose form.
|
||||
*/
|
||||
public function displayExposedForm($form, FormStateInterface $form_state) {
|
||||
$item = &$this->options;
|
||||
// flip
|
||||
$item['exposed'] = empty($item['exposed']);
|
||||
|
||||
// If necessary, set new defaults:
|
||||
if ($item['exposed']) {
|
||||
$this->defaultExposeOptions();
|
||||
}
|
||||
|
||||
$view = $form_state->get('view');
|
||||
$display_id = $form_state->get('display_id');
|
||||
$type = $form_state->get('type');
|
||||
$id = $form_state->get('id');
|
||||
$view->getExecutable()->setHandler($display_id, $type, $id, $item);
|
||||
|
||||
$view->addFormToStack($form_state->get('form_key'), $display_id, $type, $id, TRUE, TRUE);
|
||||
|
||||
$view->cacheSet();
|
||||
$form_state->set('rerender', TRUE);
|
||||
$form_state->setRebuild();
|
||||
$form_state->set('force_expose_options', TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* A submit handler that is used for storing temporary items when using
|
||||
* multi-step changes, such as ajax requests.
|
||||
*/
|
||||
public function submitTemporaryForm($form, FormStateInterface $form_state) {
|
||||
// Run it through the handler's submit function.
|
||||
$this->submitOptionsForm($form['options'], $form_state);
|
||||
$item = $this->options;
|
||||
$types = ViewExecutable::getHandlerTypes();
|
||||
|
||||
// For footer/header $handler_type is area but $type is footer/header.
|
||||
// For all other handle types it's the same.
|
||||
$handler_type = $type = $form_state->get('type');
|
||||
if (!empty($types[$type]['type'])) {
|
||||
$handler_type = $types[$type]['type'];
|
||||
}
|
||||
|
||||
$override = NULL;
|
||||
$view = $form_state->get('view');
|
||||
$executable = $view->getExecutable();
|
||||
if ($executable->display_handler->useGroupBy() && !empty($item['group_type'])) {
|
||||
if (empty($executable->query)) {
|
||||
$executable->initQuery();
|
||||
}
|
||||
$aggregate = $executable->query->getAggregationInfo();
|
||||
if (!empty($aggregate[$item['group_type']]['handler'][$type])) {
|
||||
$override = $aggregate[$item['group_type']]['handler'][$type];
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new handler and unpack the options from the form onto it. We
|
||||
// can use that for storage.
|
||||
$handler = Views::handlerManager($handler_type)->getHandler($item, $override);
|
||||
$handler->init($executable, $executable->display_handler, $item);
|
||||
|
||||
// Add the incoming options to existing options because items using
|
||||
// the extra form may not have everything in the form here.
|
||||
$options = $form_state->getValue('options') + $this->options;
|
||||
|
||||
// This unpacks only options that are in the definition, ensuring random
|
||||
// extra stuff on the form is not sent through.
|
||||
$handler->unpackOptions($handler->options, $options, NULL, FALSE);
|
||||
|
||||
// Store the item back on the view.
|
||||
$executable = $view->getExecutable();
|
||||
$executable->temporary_options[$type][$form_state->get('id')] = $handler->options;
|
||||
|
||||
// @todo Decide if \Drupal\views_ui\Form\Ajax\ViewsFormBase::getForm() is
|
||||
// perhaps the better place to fix the issue.
|
||||
// \Drupal\views_ui\Form\Ajax\ViewsFormBase::getForm() drops the current
|
||||
// form from the stack, even if it's an #ajax. So add the item back to the top
|
||||
// of the stack.
|
||||
$view->addFormToStack($form_state->get('form_key'), $form_state->get('display_id'), $type, $item['id'], TRUE);
|
||||
|
||||
$form_state->get('rerender', TRUE);
|
||||
$form_state->setRebuild();
|
||||
// Write to cache
|
||||
$view->cacheSet();
|
||||
}
|
||||
}
|
620
core/modules/views/src/Plugin/views/PluginBase.php
Normal file
620
core/modules/views/src/Plugin/views/PluginBase.php
Normal file
|
@ -0,0 +1,620 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\views\PluginBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\views;
|
||||
|
||||
use Drupal\Component\Plugin\DependentPluginInterface;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Plugin\PluginBase as ComponentPluginBase;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Base class for any views plugin types.
|
||||
*
|
||||
* Via the @Plugin definition the plugin may specify a theme function or
|
||||
* template to be used for the plugin. It also can auto-register the theme
|
||||
* implementation for that file or function.
|
||||
* - theme: the theme implementation to use in the plugin. This may be the name
|
||||
* of the function (without theme_ prefix) or the template file (without
|
||||
* template engine extension).
|
||||
* If a template file should be used, the file has to be placed in the
|
||||
* module's templates folder.
|
||||
* Example: theme = "mymodule_row" of module "mymodule" will implement
|
||||
* mymodule-row.html.twig in the [..]/modules/mymodule/templates folder.
|
||||
* - register_theme: (optional) When set to TRUE (default) the theme is
|
||||
* registered automatically. When set to FALSE the plugin reuses an existing
|
||||
* theme implementation, defined by another module or views plugin.
|
||||
* - theme_file: (optional) the location of an include file that may hold the
|
||||
* theme or preprocess function. The location has to be relative to module's
|
||||
* root directory.
|
||||
* - module: machine name of the module. It must be present for any plugin that
|
||||
* wants to register a theme.
|
||||
*
|
||||
* @ingroup views_plugins
|
||||
*/
|
||||
abstract class PluginBase extends ComponentPluginBase implements ContainerFactoryPluginInterface, ViewsPluginInterface, DependentPluginInterface {
|
||||
|
||||
/**
|
||||
* Include negotiated languages when listing languages.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\PluginBase::listLanguages()
|
||||
*/
|
||||
const INCLUDE_NEGOTIATED = 16;
|
||||
|
||||
/**
|
||||
* Include entity row languages when listing languages.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\PluginBase::listLanguages()
|
||||
*/
|
||||
const INCLUDE_ENTITY = 32;
|
||||
|
||||
/**
|
||||
* Query string to indicate the site default language.
|
||||
*
|
||||
* @see \Drupal\Core\Language\LanguageInterface::LANGCODE_DEFAULT
|
||||
*/
|
||||
const VIEWS_QUERY_LANGUAGE_SITE_DEFAULT = '***LANGUAGE_site_default***';
|
||||
|
||||
/**
|
||||
* Options for this plugin will be held here.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $options = array();
|
||||
|
||||
/**
|
||||
* The top object of a view.
|
||||
*
|
||||
* @var \Drupal\views\ViewExecutable
|
||||
*/
|
||||
public $view = NULL;
|
||||
|
||||
/**
|
||||
* The display object this plugin is for.
|
||||
*
|
||||
* For display plugins this is empty.
|
||||
*
|
||||
* @todo find a better description
|
||||
*
|
||||
* @var \Drupal\views\Plugin\views\display\DisplayPluginBase
|
||||
*/
|
||||
public $displayHandler;
|
||||
|
||||
/**
|
||||
* Plugins's definition
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $definition;
|
||||
|
||||
/**
|
||||
* Denotes whether the plugin has an additional options form.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $usesOptions = FALSE;
|
||||
|
||||
/**
|
||||
* Stores the render API renderer.
|
||||
*
|
||||
* @var \Drupal\Core\Render\RendererInterface
|
||||
*/
|
||||
protected $renderer;
|
||||
|
||||
/**
|
||||
* Constructs a PluginBase object.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
|
||||
$this->definition = $plugin_definition + $configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static($configuration, $plugin_id, $plugin_definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
|
||||
$this->view = $view;
|
||||
$this->setOptionDefaults($this->options, $this->defineOptions());
|
||||
$this->displayHandler = $display;
|
||||
|
||||
$this->unpackOptions($this->options, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Information about options for all kinds of purposes will be held here.
|
||||
* @code
|
||||
* 'option_name' => array(
|
||||
* - 'default' => default value,
|
||||
* - 'contains' => (optional) array of items this contains, with its own
|
||||
* defaults, etc. If contains is set, the default will be ignored and
|
||||
* assumed to be array().
|
||||
* ),
|
||||
* @endcode
|
||||
*
|
||||
* @return array
|
||||
* Returns the options of this handler/plugin.
|
||||
*/
|
||||
protected function defineOptions() { return array(); }
|
||||
|
||||
/**
|
||||
* Fills up the options of the plugin with defaults.
|
||||
*
|
||||
* @param array $storage
|
||||
* An array which stores the actual option values of the plugin.
|
||||
* @param array $options
|
||||
* An array which describes the options of a plugin. Each element is an
|
||||
* associative array containing:
|
||||
* - default: The default value of one option. Should be translated to the
|
||||
* interface text language selected for page if translatable.
|
||||
* - (optional) contains: An array which describes the available options
|
||||
* under the key. If contains is set, the default will be ignored and
|
||||
* assumed to be an empty array.
|
||||
* - (optional) 'bool': TRUE if the value is boolean, else FALSE.
|
||||
*/
|
||||
protected function setOptionDefaults(array &$storage, array $options) {
|
||||
foreach ($options as $option => $definition) {
|
||||
if (isset($definition['contains'])) {
|
||||
$storage[$option] = array();
|
||||
$this->setOptionDefaults($storage[$option], $definition['contains']);
|
||||
}
|
||||
else {
|
||||
$storage[$option] = $definition['default'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function filterByDefinedOptions(array &$storage) {
|
||||
$this->doFilterByDefinedOptions($storage, $this->defineOptions());
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the work to filter out stored options depending on the defined options.
|
||||
*
|
||||
* @param array $storage
|
||||
* The stored options.
|
||||
*
|
||||
* @param array $options
|
||||
* The defined options.
|
||||
*/
|
||||
protected function doFilterByDefinedOptions(array &$storage, array $options) {
|
||||
foreach ($storage as $key => $sub_storage) {
|
||||
if (!isset($options[$key])) {
|
||||
unset($storage[$key]);
|
||||
}
|
||||
|
||||
if (isset($options[$key]['contains'])) {
|
||||
$this->doFilterByDefinedOptions($storage[$key], $options[$key]['contains']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function unpackOptions(&$storage, $options, $definition = NULL, $all = TRUE, $check = TRUE) {
|
||||
if ($check && !is_array($options)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset($definition)) {
|
||||
$definition = $this->defineOptions();
|
||||
}
|
||||
|
||||
foreach ($options as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
// Ignore arrays with no definition.
|
||||
if (!$all && empty($definition[$key])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($storage[$key]) || !is_array($storage[$key])) {
|
||||
$storage[$key] = array();
|
||||
}
|
||||
|
||||
// If we're just unpacking our known options, and we're dropping an
|
||||
// unknown array (as might happen for a dependent plugin fields) go
|
||||
// ahead and drop that in.
|
||||
if (!$all && isset($definition[$key]) && !isset($definition[$key]['contains'])) {
|
||||
$storage[$key] = $value;
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->unpackOptions($storage[$key], $value, isset($definition[$key]['contains']) ? $definition[$key]['contains'] : array(), $all, FALSE);
|
||||
}
|
||||
else if ($all || !empty($definition[$key])) {
|
||||
$storage[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function destroy() {
|
||||
unset($this->view, $this->display, $this->query);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
// Some form elements belong in a fieldset for presentation, but can't
|
||||
// be moved into one because of the $form_state->getValues() hierarchy. Those
|
||||
// elements can add a #fieldset => 'fieldset_name' property, and they'll
|
||||
// be moved to their fieldset during pre_render.
|
||||
$form['#pre_render'][] = array(get_class($this), 'preRenderAddFieldsetMarkup');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateOptionsForm(&$form, FormStateInterface $form_state) { }
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitOptionsForm(&$form, FormStateInterface $form_state) { }
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() { }
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function themeFunctions() {
|
||||
return $this->view->buildThemeFunctions($this->definition['theme']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate() { return array(); }
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function summaryTitle() {
|
||||
return $this->t('Settings');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function pluginTitle() {
|
||||
// Short_title is optional so its defaults to an empty string.
|
||||
if (!empty($this->definition['short_title'])) {
|
||||
return SafeMarkup::checkPlain($this->definition['short_title']);
|
||||
}
|
||||
return SafeMarkup::checkPlain($this->definition['title']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function usesOptions() {
|
||||
return $this->usesOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function globalTokenReplace($string = '', array $options = array()) {
|
||||
return \Drupal::token()->replace($string, array('view' => $this->view), $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces Views' tokens in a given string. It is the responsibility of the
|
||||
* calling function to ensure $text and $token replacements are sanitized.
|
||||
*
|
||||
* This used to be a simple strtr() scattered throughout the code. Some Views
|
||||
* tokens, such as arguments (e.g.: %1 or !1), still use the old format so we
|
||||
* handle those as well as the new Twig-based tokens (e.g.: {{ field_name }})
|
||||
*
|
||||
* @param $text
|
||||
* String with possible tokens.
|
||||
* @param $tokens
|
||||
* Array of token => replacement_value items.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
protected function viewsTokenReplace($text, $tokens) {
|
||||
if (empty($tokens)) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
// Separate Twig tokens from other tokens (e.g.: contextual filter tokens in
|
||||
// the form of %1).
|
||||
$twig_tokens = array();
|
||||
$other_tokens = array();
|
||||
foreach ($tokens as $token => $replacement) {
|
||||
if (strpos($token, '{{') !== FALSE) {
|
||||
// Twig wants a token replacement array stripped of curly-brackets.
|
||||
$token = trim(str_replace(array('{', '}'), '', $token));
|
||||
$twig_tokens[$token] = $replacement;
|
||||
}
|
||||
else {
|
||||
$other_tokens[$token] = $replacement;
|
||||
}
|
||||
}
|
||||
|
||||
// Non-Twig tokens are a straight string replacement, Twig tokens get run
|
||||
// through an inline template for rendering and replacement.
|
||||
$text = strtr($text, $other_tokens);
|
||||
if ($twig_tokens && !empty($text)) {
|
||||
$build = array(
|
||||
'#type' => 'inline_template',
|
||||
'#template' => $text,
|
||||
'#context' => $twig_tokens,
|
||||
);
|
||||
|
||||
return $this->getRenderer()->render($build);
|
||||
}
|
||||
else {
|
||||
return $text;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAvailableGlobalTokens($prepared = FALSE, array $types = array()) {
|
||||
$info = \Drupal::token()->getInfo();
|
||||
// Site and view tokens should always be available.
|
||||
$types += array('site', 'view');
|
||||
$available = array_intersect_key($info['tokens'], array_flip($types));
|
||||
|
||||
// Construct the token string for each token.
|
||||
if ($prepared) {
|
||||
$prepared = array();
|
||||
foreach ($available as $type => $tokens) {
|
||||
foreach (array_keys($tokens) as $token) {
|
||||
$prepared[$type][] = "[$type:$token]";
|
||||
}
|
||||
}
|
||||
|
||||
return $prepared;
|
||||
}
|
||||
|
||||
return $available;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function globalTokenForm(&$form, FormStateInterface $form_state) {
|
||||
$token_items = array();
|
||||
|
||||
foreach ($this->getAvailableGlobalTokens() as $type => $tokens) {
|
||||
$item = array(
|
||||
'#markup' => $type,
|
||||
'children' => array(),
|
||||
);
|
||||
foreach ($tokens as $name => $info) {
|
||||
$item['children'][$name] = "[$type:$name]" . ' - ' . $info['name'] . ': ' . $info['description'];
|
||||
}
|
||||
|
||||
$token_items[$type] = $item;
|
||||
}
|
||||
|
||||
$form['global_tokens'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Available global token replacements'),
|
||||
);
|
||||
$form['global_tokens']['list'] = array(
|
||||
'#theme' => 'item_list',
|
||||
'#items' => $token_items,
|
||||
'#attributes' => array(
|
||||
'class' => array('global-tokens'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function preRenderAddFieldsetMarkup(array $form) {
|
||||
foreach (Element::children($form) as $key) {
|
||||
$element = $form[$key];
|
||||
// In our form builder functions, we added an arbitrary #fieldset property
|
||||
// to any element that belongs in a fieldset. If this form element has
|
||||
// that property, move it into its fieldset.
|
||||
if (isset($element['#fieldset']) && isset($form[$element['#fieldset']])) {
|
||||
$form[$element['#fieldset']][$key] = $element;
|
||||
// Remove the original element this duplicates.
|
||||
unset($form[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function preRenderFlattenData($form) {
|
||||
foreach (Element::children($form) as $key) {
|
||||
$element = $form[$key];
|
||||
if (!empty($element['#flatten'])) {
|
||||
foreach (Element::children($element) as $child_key) {
|
||||
$form[$child_key] = $form[$key][$child_key];
|
||||
}
|
||||
// All done, remove the now-empty parent.
|
||||
unset($form[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function calculateDependencies() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getProvider() {
|
||||
$definition = $this->getPluginDefinition();
|
||||
return $definition['provider'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes an array of languages, optionally including special languages.
|
||||
*
|
||||
* @param int $flags
|
||||
* (optional) Flags for which languages to return (additive). Options:
|
||||
* - \Drupal\Core\Language::STATE_ALL (default): All languages
|
||||
* (configurable and default).
|
||||
* - \Drupal\Core\Language::STATE_CONFIGURABLE: Configurable languages.
|
||||
* - \Drupal\Core\Language::STATE_LOCKED: Locked languages.
|
||||
* - \Drupal\Core\Language::STATE_SITE_DEFAULT: Add site default language;
|
||||
* note that this is not included in STATE_ALL.
|
||||
* - \Drupal\views\Plugin\views\PluginBase::INCLUDE_NEGOTIATED: Add
|
||||
* negotiated language types.
|
||||
* - \Drupal\views\Plugin\views\PluginBase::INCLUDE_ENTITY: Add
|
||||
* entity row language types. Note that these are only supported for
|
||||
* display options, not substituted in queries.
|
||||
* @param array|null $current_values
|
||||
* The currently-selected options in the list, if available.
|
||||
*
|
||||
* @return array
|
||||
* An array of language names, keyed by the language code. Negotiated and
|
||||
* special languages have special codes that are substituted in queries by
|
||||
* PluginBase::queryLanguageSubstitutions().
|
||||
* Only configurable languages and languages that are in $current_values are
|
||||
* included in the list.
|
||||
*/
|
||||
protected function listLanguages($flags = LanguageInterface::STATE_ALL, array $current_values = NULL) {
|
||||
$manager = \Drupal::languageManager();
|
||||
$languages = $manager->getLanguages($flags);
|
||||
$list = array();
|
||||
|
||||
// The entity languages should come first, if requested.
|
||||
if ($flags & PluginBase::INCLUDE_ENTITY) {
|
||||
$list['***LANGUAGE_entity_translation***'] = $this->t('Content language of view row');
|
||||
$list['***LANGUAGE_entity_default***'] = $this->t('Original language of content in view row');
|
||||
}
|
||||
|
||||
// STATE_SITE_DEFAULT comes in with ID set
|
||||
// to LanguageInterface::LANGCODE_SITE_DEFAULT.
|
||||
// Since this is not a real language, surround it by '***LANGUAGE_...***',
|
||||
// like the negotiated languages below.
|
||||
if ($flags & LanguageInterface::STATE_SITE_DEFAULT) {
|
||||
$list[PluginBase::VIEWS_QUERY_LANGUAGE_SITE_DEFAULT] = $this->t($languages[LanguageInterface::LANGCODE_SITE_DEFAULT]->getName());
|
||||
// Remove site default language from $languages so it's not added
|
||||
// twice with the real languages below.
|
||||
unset($languages[LanguageInterface::LANGCODE_SITE_DEFAULT]);
|
||||
}
|
||||
|
||||
// Add in negotiated languages, if requested.
|
||||
if ($flags & PluginBase::INCLUDE_NEGOTIATED) {
|
||||
$types_info = $manager->getDefinedLanguageTypesInfo();
|
||||
$types = $manager->getLanguageTypes();
|
||||
// We only go through the configured types.
|
||||
foreach ($types as $id) {
|
||||
if (isset($types_info[$id]['name'])) {
|
||||
$name = $types_info[$id]['name'];
|
||||
// Surround IDs by '***LANGUAGE_...***', to avoid query collisions.
|
||||
$id = '***LANGUAGE_' . $id . '***';
|
||||
$list[$id] = $this->t('!type language selected for page', array('!type' => $name));
|
||||
}
|
||||
}
|
||||
if (!empty($current_values)) {
|
||||
foreach ($types_info as $id => $type) {
|
||||
$id = '***LANGUAGE_' . $id . '***';
|
||||
// If this (non-configurable) type is among the current values,
|
||||
// add that option too, so it is not lost. If not among the current
|
||||
// values, skip displaying it to avoid user confusion.
|
||||
if (isset($type['name']) && !isset($list[$id]) && in_array($id, $current_values)) {
|
||||
$list[$id] = $this->t('!type language selected for page', array('!type' => $type['name']));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add real languages.
|
||||
foreach ($languages as $id => $language) {
|
||||
$list[$id] = $this->t($language->getName());
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns substitutions for Views queries for languages.
|
||||
*
|
||||
* This is needed so that the language options returned by
|
||||
* PluginBase::listLanguages() are able to be used in queries. It is called
|
||||
* by the Views module implementation of hook_views_query_substitutions()
|
||||
* to get the language-related substitutions.
|
||||
*
|
||||
* @return array
|
||||
* An array in the format of hook_views_query_substitutions() that gives
|
||||
* the query substitutions needed for the special language types.
|
||||
*/
|
||||
public static function queryLanguageSubstitutions() {
|
||||
$changes = array();
|
||||
$manager = \Drupal::languageManager();
|
||||
|
||||
// Handle default language.
|
||||
$default = $manager->getDefaultLanguage()->getId();
|
||||
$changes[PluginBase::VIEWS_QUERY_LANGUAGE_SITE_DEFAULT] = $default;
|
||||
|
||||
// Handle negotiated languages.
|
||||
$types = $manager->getDefinedLanguageTypesInfo();
|
||||
foreach ($types as $id => $type) {
|
||||
if (isset($type['name'])) {
|
||||
$changes['***LANGUAGE_' . $id . '***'] = $manager->getCurrentLanguage($id)->getId();
|
||||
}
|
||||
}
|
||||
|
||||
return $changes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the render API renderer.
|
||||
*
|
||||
* @return \Drupal\Core\Render\RendererInterface
|
||||
*/
|
||||
protected function getRenderer() {
|
||||
if (!isset($this->renderer)) {
|
||||
$this->renderer = \Drupal::service('renderer');
|
||||
}
|
||||
|
||||
return $this->renderer;
|
||||
}
|
||||
|
||||
}
|
14
core/modules/views/src/Plugin/views/PluginInterface.php
Normal file
14
core/modules/views/src/Plugin/views/PluginInterface.php
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\views\PluginInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\views;
|
||||
|
||||
use Drupal\Component\Plugin\PluginInspectionInterface;
|
||||
|
||||
interface PluginInterface extends PluginInspectionInterface {
|
||||
|
||||
}
|
146
core/modules/views/src/Plugin/views/ViewsHandlerInterface.php
Normal file
146
core/modules/views/src/Plugin/views/ViewsHandlerInterface.php
Normal file
|
@ -0,0 +1,146 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\views\ViewsHandlerInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\views;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface for all views handlers.
|
||||
*/
|
||||
interface ViewsHandlerInterface extends ViewsPluginInterface {
|
||||
|
||||
/**
|
||||
* Run before the view is built.
|
||||
*
|
||||
* This gives all the handlers some time to set up before any handler has
|
||||
* been fully run.
|
||||
*/
|
||||
public function preQuery();
|
||||
|
||||
/**
|
||||
* Determines the entity type used by this handler.
|
||||
*
|
||||
* If this handler uses a relationship, the base class of the relationship is
|
||||
* taken into account.
|
||||
*
|
||||
* @return string
|
||||
* The machine name of the entity type.
|
||||
*/
|
||||
public function getEntityType();
|
||||
|
||||
/**
|
||||
* Determines if the handler is considered 'broken', meaning it's a
|
||||
* a placeholder used when a handler can't be found.
|
||||
*/
|
||||
public function broken();
|
||||
|
||||
/**
|
||||
* Ensure the main table for this handler is in the query. This is used
|
||||
* a lot.
|
||||
*/
|
||||
public function ensureMyTable();
|
||||
|
||||
/**
|
||||
* Check whether given user has access to this handler.
|
||||
*
|
||||
* @param AccountInterface $account
|
||||
* The user account to check.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the user has access to the handler, FALSE otherwise.
|
||||
*/
|
||||
public function access(AccountInterface $account);
|
||||
|
||||
/**
|
||||
* Get the join object that should be used for this handler.
|
||||
*
|
||||
* This method isn't used a great deal, but it's very handy for easily
|
||||
* getting the join if it is necessary to make some changes to it, such
|
||||
* as adding an 'extra'.
|
||||
*/
|
||||
public function getJoin();
|
||||
|
||||
/**
|
||||
* Sanitize the value for output.
|
||||
*
|
||||
* @param $value
|
||||
* The value being rendered.
|
||||
* @param $type
|
||||
* The type of sanitization needed. If not provided, SafeMarkup::checkPlain() is used.
|
||||
*
|
||||
* @return string
|
||||
* Returns the safe value.
|
||||
*/
|
||||
public function sanitizeValue($value, $type = NULL);
|
||||
|
||||
/**
|
||||
* Fetches a handler to join one table to a primary table from the data cache.
|
||||
*
|
||||
* @param string $table
|
||||
* The table to join from.
|
||||
* @param string $base_table
|
||||
* The table to join to.
|
||||
*
|
||||
* @return \Drupal\views\Plugin\views\join\JoinPluginBase
|
||||
*/
|
||||
public static function getTableJoin($table, $base_table);
|
||||
|
||||
/**
|
||||
* Shortcut to get a handler's raw field value.
|
||||
*
|
||||
* This should be overridden for handlers with formulae or other
|
||||
* non-standard fields. Because this takes an argument, fields
|
||||
* overriding this can just call return parent::getField($formula)
|
||||
*/
|
||||
public function getField($field = NULL);
|
||||
|
||||
/**
|
||||
* Run after the view is executed, before the result is cached.
|
||||
*
|
||||
* This gives all the handlers some time to modify values. This is primarily
|
||||
* used so that handlers that pull up secondary data can put it in the
|
||||
* $values so that the raw data can be used externally.
|
||||
*/
|
||||
public function postExecute(&$values);
|
||||
|
||||
/**
|
||||
* Shortcut to display the exposed options form.
|
||||
*/
|
||||
public function showExposeForm(&$form, FormStateInterface $form_state);
|
||||
|
||||
/**
|
||||
* Called just prior to query(), this lets a handler set up any relationship
|
||||
* it needs.
|
||||
*/
|
||||
public function setRelationship();
|
||||
|
||||
/**
|
||||
* Return a string representing this handler's name in the UI.
|
||||
*/
|
||||
public function adminLabel($short = FALSE);
|
||||
|
||||
/**
|
||||
* Breaks x,y,z and x+y+z into an array.
|
||||
*
|
||||
* @param string $str
|
||||
* The string to split.
|
||||
* @param bool $force_int
|
||||
* Enforce a numeric check.
|
||||
*
|
||||
* @return \stdClass
|
||||
* A stdClass object containing value and operator properties.
|
||||
*/
|
||||
public static function breakString($str, $force_int = FALSE);
|
||||
|
||||
/**
|
||||
* Provide text for the administrative summary.
|
||||
*/
|
||||
public function adminSummary();
|
||||
|
||||
}
|
186
core/modules/views/src/Plugin/views/ViewsPluginInterface.php
Normal file
186
core/modules/views/src/Plugin/views/ViewsPluginInterface.php
Normal file
|
@ -0,0 +1,186 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\views\ViewsPluginInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\views;
|
||||
|
||||
use Drupal\Component\Plugin\DerivativeInspectionInterface;
|
||||
use Drupal\Component\Plugin\PluginInspectionInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface for all views plugins.
|
||||
*/
|
||||
interface ViewsPluginInterface extends PluginInspectionInterface, DerivativeInspectionInterface {
|
||||
|
||||
/**
|
||||
* Returns the plugin provider.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getProvider();
|
||||
|
||||
/**
|
||||
* Return the human readable name of the display.
|
||||
*
|
||||
* This appears on the ui beside each plugin and beside the settings link.
|
||||
*/
|
||||
public function pluginTitle();
|
||||
|
||||
/**
|
||||
* Returns the usesOptions property.
|
||||
*/
|
||||
public function usesOptions();
|
||||
|
||||
/**
|
||||
* Filter out stored options depending on the defined options.
|
||||
*
|
||||
* @param array $storage
|
||||
* The stored options.
|
||||
*/
|
||||
public function filterByDefinedOptions(array &$storage);
|
||||
|
||||
/**
|
||||
* Validate the options form.
|
||||
*/
|
||||
public function validateOptionsForm(&$form, FormStateInterface $form_state);
|
||||
|
||||
/**
|
||||
* Returns the summary of the settings in the display.
|
||||
*/
|
||||
public function summaryTitle();
|
||||
|
||||
/**
|
||||
* Moves form elements into fieldsets for presentation purposes.
|
||||
*
|
||||
* Many views forms use #tree = TRUE to keep their values in a hierarchy for
|
||||
* easier storage. Moving the form elements into fieldsets during form
|
||||
* building would break up that hierarchy. Therefore, we wait until the
|
||||
* pre_render stage, where any changes we make affect presentation only and
|
||||
* aren't reflected in $form_state->getValues().
|
||||
*
|
||||
* @param array $form
|
||||
* The form build array to alter.
|
||||
*
|
||||
* @return array
|
||||
* The form build array.
|
||||
*/
|
||||
public static function preRenderAddFieldsetMarkup(array $form);
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition);
|
||||
|
||||
/**
|
||||
* Initialize the plugin.
|
||||
*
|
||||
* @param \Drupal\views\ViewExecutable $view
|
||||
* The view object.
|
||||
* @param \Drupal\views\Plugin\views\display\DisplayPluginBase $display
|
||||
* The display handler.
|
||||
* @param array $options
|
||||
* The options configured for this plugin.
|
||||
*/
|
||||
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL);
|
||||
|
||||
/**
|
||||
* Handle any special handling on the validate form.
|
||||
*/
|
||||
public function submitOptionsForm(&$form, FormStateInterface $form_state);
|
||||
|
||||
/**
|
||||
* Adds elements for available core tokens to a form.
|
||||
*
|
||||
* @param array $form
|
||||
* The form array to alter, passed by reference.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
*/
|
||||
public function globalTokenForm(&$form, FormStateInterface $form_state);
|
||||
|
||||
/**
|
||||
* Returns an array of available token replacements.
|
||||
*
|
||||
* @param bool $prepared
|
||||
* Whether to return the raw token info for each token or an array of
|
||||
* prepared tokens for each type. E.g. "[view:name]".
|
||||
* @param array $types
|
||||
* An array of additional token types to return, defaults to 'site' and
|
||||
* 'view'.
|
||||
*
|
||||
* @return array
|
||||
* An array of available token replacement info or tokens, grouped by type.
|
||||
*/
|
||||
public function getAvailableGlobalTokens($prepared = FALSE, array $types = array());
|
||||
|
||||
/**
|
||||
* Flattens the structure of form elements.
|
||||
*
|
||||
* If a form element has #flatten = TRUE, then all of it's children get moved
|
||||
* to the same level as the element itself. So $form['to_be_flattened'][$key]
|
||||
* becomes $form[$key], and $form['to_be_flattened'] gets unset.
|
||||
*
|
||||
* @param array $form
|
||||
* The form build array to alter.
|
||||
*
|
||||
* @return array
|
||||
* The form build array.
|
||||
*/
|
||||
public static function preRenderFlattenData($form);
|
||||
|
||||
/**
|
||||
* Returns a string with any core tokens replaced.
|
||||
*
|
||||
* @param string $string
|
||||
* The string to preform the token replacement on.
|
||||
* @param array $options
|
||||
* An array of options, as passed to \Drupal\Core\Utility\Token::replace().
|
||||
*
|
||||
* @return string
|
||||
* The tokenized string.
|
||||
*/
|
||||
public function globalTokenReplace($string = '', array $options = array());
|
||||
|
||||
/**
|
||||
* Clears a plugin.
|
||||
*/
|
||||
public function destroy();
|
||||
|
||||
/**
|
||||
* Validate that the plugin is correct and can be saved.
|
||||
*
|
||||
* @return
|
||||
* An array of error strings to tell the user what is wrong with this
|
||||
* plugin.
|
||||
*/
|
||||
public function validate();
|
||||
|
||||
/**
|
||||
* Add anything to the query that we might need to.
|
||||
*/
|
||||
public function query();
|
||||
|
||||
/**
|
||||
* Unpack options over our existing defaults, drilling down into arrays
|
||||
* so that defaults don't get totally blown away.
|
||||
*/
|
||||
public function unpackOptions(&$storage, $options, $definition = NULL, $all = TRUE, $check = TRUE);
|
||||
|
||||
/**
|
||||
* Provide a form to edit options for this plugin.
|
||||
*/
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state);
|
||||
|
||||
/**
|
||||
* Provide a full list of possible theme templates used by this style.
|
||||
*/
|
||||
public function themeFunctions();
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\views\access\AccessPluginBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\views\access;
|
||||
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\views\Plugin\views\PluginBase;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
* @defgroup views_access_plugins Views access plugins
|
||||
* @{
|
||||
* Plugins to handle access checking for views.
|
||||
*
|
||||
* Access plugins are responsible for controlling access to the view.
|
||||
*
|
||||
* Access plugins extend \Drupal\views\Plugin\views\access\AccessPluginBase,
|
||||
* implementing the access() and alterRouteDefinition() methods. They must be
|
||||
* annotated with \Drupal\views\Annotation\ViewsAccess annotation, and they
|
||||
* must be in namespace directory Plugin\views\access.
|
||||
*
|
||||
* @ingroup views_plugins
|
||||
* @see plugin_api
|
||||
*/
|
||||
|
||||
/**
|
||||
* The base plugin to handle access control.
|
||||
*/
|
||||
abstract class AccessPluginBase extends PluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function summaryTitle() {
|
||||
return $this->t('Unknown');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the current user has access or not.
|
||||
*
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The user who wants to access this view.
|
||||
*
|
||||
* @return TRUE
|
||||
* Returns whether the user has access to the view.
|
||||
*/
|
||||
abstract public function access(AccountInterface $account);
|
||||
|
||||
/**
|
||||
* Allows access plugins to alter the route definition of a view.
|
||||
*
|
||||
* Likely the access plugin will add new requirements, so its custom access
|
||||
* checker can be applied.
|
||||
*
|
||||
* @param \Symfony\Component\Routing\Route $route
|
||||
* The route to change.
|
||||
*/
|
||||
abstract public function alterRouteDefinition(Route $route);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
48
core/modules/views/src/Plugin/views/access/None.php
Normal file
48
core/modules/views/src/Plugin/views/access/None.php
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\views\access\None.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\views\access;
|
||||
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
* Access plugin that provides no access control at all.
|
||||
*
|
||||
* @ingroup views_access_plugins
|
||||
*
|
||||
* @ViewsAccess(
|
||||
* id = "none",
|
||||
* title = @Translation("None"),
|
||||
* help = @Translation("Will be available to all users.")
|
||||
* )
|
||||
*/
|
||||
class None extends AccessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function summaryTitle() {
|
||||
return $this->t('Unrestricted');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function access(AccountInterface $account) {
|
||||
// No access control.
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function alterRouteDefinition(Route $route) {
|
||||
$route->setRequirement('_access', 'TRUE');
|
||||
}
|
||||
|
||||
}
|
134
core/modules/views/src/Plugin/views/area/AreaPluginBase.php
Normal file
134
core/modules/views/src/Plugin/views/area/AreaPluginBase.php
Normal file
|
@ -0,0 +1,134 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\views\area\AreaPluginBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\views\area;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\Plugin\views\HandlerBase;
|
||||
|
||||
/**
|
||||
* @defgroup views_area_handlers Views area handler plugins
|
||||
* @{
|
||||
* Plugins governing areas of views, such as header, footer, and empty text.
|
||||
*
|
||||
* Area handler plugins extend \Drupal\views\Plugin\views\area\AreaPluginBase.
|
||||
* They must be annotated with \Drupal\views\Annotation\ViewsArea annotation,
|
||||
* and they must be in namespace directory Plugin\views\area.
|
||||
*
|
||||
* @ingroup views_plugins
|
||||
* @see plugin_api
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base class for area handler plugins.
|
||||
*/
|
||||
abstract class AreaPluginBase extends HandlerBase {
|
||||
|
||||
/**
|
||||
* The type of this area handler, i.e. 'header', 'footer', or 'empty'.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $areaType;
|
||||
|
||||
/**
|
||||
* Overrides Drupal\views\Plugin\views\HandlerBase::init().
|
||||
*
|
||||
* Make sure that no result area handlers are set to be shown when the result
|
||||
* is empty.
|
||||
*/
|
||||
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
|
||||
parent::init($view, $display, $options);
|
||||
|
||||
if ($this->areaType == 'empty') {
|
||||
$this->options['empty'] = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function usesGroupBy() {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
|
||||
$this->definition['field'] = !empty($this->definition['field']) ? $this->definition['field'] : '';
|
||||
$label = !empty($this->definition['label']) ? $this->definition['label'] : $this->definition['field'];
|
||||
$options['admin_label']['default'] = $label;
|
||||
$options['empty'] = array('default' => FALSE);
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function adminSummary() {
|
||||
return $this->adminLabel();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
parent::buildOptionsForm($form, $form_state);
|
||||
|
||||
if ($form_state->get('type') != 'empty') {
|
||||
$form['empty'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Display even if view has no result'),
|
||||
'#default_value' => isset($this->options['empty']) ? $this->options['empty'] : 0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs any operations needed before full rendering.
|
||||
*
|
||||
* @param array $results
|
||||
* The results of the view.
|
||||
*/
|
||||
public function preRender(array $results) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the area.
|
||||
*
|
||||
* @param bool $empty
|
||||
* (optional) Indicator if view result is empty or not. Defaults to FALSE.
|
||||
*
|
||||
* @return array
|
||||
* In any case we need a valid Drupal render array to return.
|
||||
*/
|
||||
public abstract function render($empty = FALSE);
|
||||
|
||||
/**
|
||||
* Does that area have nothing to show.
|
||||
*
|
||||
* This method should be overridden by more complex handlers where the output
|
||||
* is not static and maybe itself be empty if it's rendered.
|
||||
*
|
||||
* @return bool
|
||||
* Return TRUE if the area is empty, else FALSE.
|
||||
*/
|
||||
public function isEmpty() {
|
||||
return empty($this->options['empty']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
30
core/modules/views/src/Plugin/views/area/Broken.php
Normal file
30
core/modules/views/src/Plugin/views/area/Broken.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\views\area\Broken.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\views\area;
|
||||
|
||||
use Drupal\views\Plugin\views\BrokenHandlerTrait;
|
||||
|
||||
/**
|
||||
* A special handler to take the place of missing or broken handlers.
|
||||
*
|
||||
* @ingroup views_area_handlers
|
||||
*
|
||||
* @ViewsArea("broken")
|
||||
*/
|
||||
class Broken extends AreaPluginBase {
|
||||
use BrokenHandlerTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render($empty = FALSE) {
|
||||
// Simply render nothing by returning an empty render array.
|
||||
return array();
|
||||
}
|
||||
|
||||
}
|
201
core/modules/views/src/Plugin/views/area/Entity.php
Normal file
201
core/modules/views/src/Plugin/views/area/Entity.php
Normal file
|
@ -0,0 +1,201 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\views\area\Entity.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\views\area;
|
||||
|
||||
use Drupal\Component\Uuid\Uuid;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides an area handler which renders an entity in a certain view mode.
|
||||
*
|
||||
* @ingroup views_area_handlers
|
||||
*
|
||||
* @ViewsArea("entity")
|
||||
*/
|
||||
class Entity extends TokenizeAreaPluginBase {
|
||||
|
||||
/**
|
||||
* Stores the entity type of the result entities.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $entityType;
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* Constructs a new Entity instance.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
|
||||
$this->entityManager = $entity_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('entity.manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\area\AreaPluginBase::init().
|
||||
*/
|
||||
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
|
||||
parent::init($view, $display, $options);
|
||||
$this->entityType = $this->definition['entity_type'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
|
||||
// Per default we enable tokenize, as this is the most common use case for
|
||||
// this handler.
|
||||
$options['tokenize']['default'] = TRUE;
|
||||
|
||||
// Contains the config target identifier for the entity.
|
||||
$options['target'] = ['default' => ''];
|
||||
$options['view_mode'] = ['default' => 'default'];
|
||||
$options['bypass_access'] = ['default' => FALSE];
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
parent::buildOptionsForm($form, $form_state);
|
||||
|
||||
$form['view_mode'] = array(
|
||||
'#type' => 'select',
|
||||
'#options' => $this->entityManager->getViewModeOptions($this->entityType),
|
||||
'#title' => $this->t('View mode'),
|
||||
'#default_value' => $this->options['view_mode'],
|
||||
);
|
||||
|
||||
$label = $this->entityManager->getDefinition($this->entityType)->getLabel();
|
||||
$target = $this->options['target'];
|
||||
|
||||
// If the target does not contain tokens, try to load the entity and
|
||||
// display the entity ID to the admin form user.
|
||||
// @todo Use a method to check for tokens in
|
||||
// https://www.drupal.org/node/2396607.
|
||||
if (strpos($this->options['target'], '{{') === FALSE && strpos($this->options['target'], '!') === FALSE && strpos($this->options['target'], '%') === FALSE && strpos($this->options['target'], '[') === FALSE) {
|
||||
// @todo If the entity does not exist, this will will show the config
|
||||
// target identifier. Decide if this is the correct behavior in
|
||||
// https://www.drupal.org/node/2415391.
|
||||
if ($target_entity = $this->entityManager->loadEntityByConfigTarget($this->entityType, $this->options['target'])) {
|
||||
$target = $target_entity->id();
|
||||
}
|
||||
}
|
||||
$form['target'] = [
|
||||
'#title' => $this->t('@entity_type_label ID', ['@entity_type_label' => $label]),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $target,
|
||||
];
|
||||
|
||||
$form['bypass_access'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Bypass access checks'),
|
||||
'#description' => $this->t('If enabled, access permissions for rendering the entity are not checked.'),
|
||||
'#default_value' => !empty($this->options['bypass_access']),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
parent::submitOptionsForm($form, $form_state);
|
||||
|
||||
// Load the referenced entity and store its config target identifier if
|
||||
// the target does not contains tokens.
|
||||
// @todo Use a method to check for tokens in
|
||||
// https://www.drupal.org/node/2396607.
|
||||
$options = $form_state->getValue('options');
|
||||
if (strpos($options['target'], '{{') === FALSE && strpos($options['target'], '!') === FALSE && strpos($options['target'], '%') === FALSE && strpos($options['target'], '[') === FALSE) {
|
||||
if ($entity = $this->entityManager->getStorage($this->entityType)->load($options['target'])) {
|
||||
$options['target'] = $entity->getConfigTarget();
|
||||
}
|
||||
$form_state->setValue('options', $options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render($empty = FALSE) {
|
||||
if (!$empty || !empty($this->options['empty'])) {
|
||||
// @todo Use a method to check for tokens in
|
||||
// https://www.drupal.org/node/2396607.
|
||||
if (strpos($this->options['target'], '{{') !== FALSE || strpos($this->options['target'], '!') !== FALSE || strpos($this->options['target'], '%') !== FALSE || strpos($this->options['target'], '[') !== FALSE) {
|
||||
$target_id = $this->tokenizeValue($this->options['target']);
|
||||
if ($entity = $this->entityManager->getStorage($this->entityType)->load($target_id)) {
|
||||
$target_entity = $entity;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ($entity = $this->entityManager->loadEntityByConfigTarget($this->entityType, $this->options['target'])) {
|
||||
$target_entity = $entity;
|
||||
}
|
||||
}
|
||||
if (isset($target_entity) && (!empty($this->options['bypass_access']) || $target_entity->access('view'))) {
|
||||
$view_builder = $this->entityManager->getViewBuilder($this->entityType);
|
||||
return $view_builder->view($target_entity, $this->options['view_mode']);
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function calculateDependencies() {
|
||||
$dependencies = parent::calculateDependencies();
|
||||
|
||||
// Ensure that we don't add dependencies for placeholders.
|
||||
// @todo Use a method to check for tokens in
|
||||
// https://www.drupal.org/node/2396607.
|
||||
if (strpos($this->options['target'], '{{') === FALSE && strpos($this->options['target'], '!') === FALSE && strpos($this->options['target'], '%') === FALSE && strpos($this->options['target'], '[') === FALSE) {
|
||||
if ($entity = $this->entityManager->loadEntityByConfigTarget($this->entityType, $this->options['target'])) {
|
||||
$dependencies[$this->entityManager->getDefinition($this->entityType)->getConfigDependencyKey()][] = $entity->getConfigDependencyName();
|
||||
}
|
||||
}
|
||||
|
||||
return $dependencies;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue