Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
project
address
Commits
115bea5e
Commit
115bea5e
authored
May 18, 2017
by
Derek Wright
Committed by
Bojan Živanović
May 18, 2017
Browse files
Issue
#2787255
by dww, bojanz: Provide a views filter for administrative areas
parent
0db5d0de
Changes
11
Expand all
Hide whitespace changes
Inline
Side-by-side
address.views.inc
View file @
115bea5e
...
...
@@ -43,6 +43,8 @@ function address_field_views_data(FieldStorageConfigInterface $field) {
}
// Add the custom country_code filter.
$data
[
$table_name
][
$field_name
.
'_country_code'
][
'filter'
][
'id'
]
=
'country_code'
;
// Add the custom administrative_area filter.
$data
[
$table_name
][
$field_name
.
'_administrative_area'
][
'filter'
][
'id'
]
=
'administrative_area'
;
}
}
elseif
(
$field_type
==
'address_country'
)
{
...
...
config/schema/address.schema.yml
View file @
115bea5e
...
...
@@ -150,3 +150,29 @@ field.widget.settings.address_zone_default:
views.filter.country_code
:
type
:
views.filter.in_operator
label
:
'
Country'
views.filter.administrative_area
:
type
:
views.filter.in_operator
label
:
'
Administrative
area'
mapping
:
country
:
type
:
mapping
mapping
:
country_source
:
type
:
string
label
:
'
Country
source'
country_argument_id
:
type
:
string
label
:
'
Country
contextual
filter
ID'
country_filter_id
:
type
:
string
label
:
'
Exposed
country
filter
ID'
country_static_code
:
type
:
string
label
:
'
Predefined
country
for
administrative
areas'
expose
:
type
:
mapping
mapping
:
label_type
:
type
:
string
label
:
'
Label
type'
src/Plugin/views/filter/AdministrativeArea.php
0 → 100644
View file @
115bea5e
This diff is collapsed.
Click to expand it.
src/Plugin/views/filter/CountryAwareInOperatorBase.php
0 → 100644
View file @
115bea5e
<?php
namespace
Drupal\address\Plugin\views\filter
;
use
CommerceGuys\Addressing\Country\CountryRepositoryInterface
;
use
Drupal\Core\Entity\EntityFieldManagerInterface
;
use
Drupal\Core\Entity\EntityTypeInterface
;
use
Drupal\Core\Entity\EntityTypeManagerInterface
;
use
Drupal\views\Plugin\views\filter\InOperator
;
use
Symfony\Component\DependencyInjection\ContainerInterface
;
/**
* Abstract base class for country-aware InOperator views filters.
*/
abstract
class
CountryAwareInOperatorBase
extends
InOperator
{
/**
* The country repository.
*
* @var \CommerceGuys\Addressing\Country\CountryRepositoryInterface
*/
protected
$countryRepository
;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected
$entityTypeManager
;
/**
* The entity field manager.
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected
$entityFieldManager
;
/**
* Constructs a new CountryAwareInOperatorBase 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 \CommerceGuys\Addressing\Country\CountryRepositoryInterface $country_repository
* The country repository.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
* The entity field manager.
*/
public
function
__construct
(
array
$configuration
,
$plugin_id
,
$plugin_definition
,
CountryRepositoryInterface
$country_repository
,
EntityTypeManagerInterface
$entity_type_manager
,
EntityFieldManagerInterface
$entity_field_manager
)
{
parent
::
__construct
(
$configuration
,
$plugin_id
,
$plugin_definition
);
$this
->
countryRepository
=
$country_repository
;
$this
->
entityTypeManager
=
$entity_type_manager
;
$this
->
entityFieldManager
=
$entity_field_manager
;
}
/**
* {@inheritdoc}
*/
public
static
function
create
(
ContainerInterface
$container
,
array
$configuration
,
$plugin_id
,
$plugin_definition
)
{
return
new
static
(
$configuration
,
$plugin_id
,
$plugin_definition
,
$container
->
get
(
'address.country_repository'
),
$container
->
get
(
'entity_type.manager'
),
$container
->
get
(
'entity_field.manager'
)
);
}
/**
* Gets the name of the entity field on which this filter operates.
*
* @return string
* The field name.
*/
protected
function
getFieldName
()
{
if
(
isset
(
$this
->
configuration
[
'field_name'
]))
{
// Configurable field.
$field_name
=
$this
->
configuration
[
'field_name'
];
}
else
{
// Base field.
$field_name
=
$this
->
configuration
[
'entity field'
];
}
return
$field_name
;
}
/**
* Gets the list of available countries for the current entity field.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type, defaults to the current type for this filter.
* @param string $field_name
* The field name, defaults to the current field name for this filter.
*
* @return array
* An array of available country codes, including the full list when unrestricted.
*/
protected
function
getAvailableCountries
(
EntityTypeInterface
$entity_type
=
NULL
,
$field_name
=
NULL
)
{
if
(
!
isset
(
$entity_type
))
{
$entity_type_id
=
$this
->
getEntityType
();
$entity_type
=
$this
->
entityTypeManager
->
getDefinition
(
$entity_type_id
);
}
if
(
!
isset
(
$field_name
))
{
$field_name
=
$this
->
getFieldName
();
}
$bundles
=
$this
->
getBundles
(
$entity_type
,
$field_name
);
$storage
=
$this
->
entityTypeManager
->
getStorage
(
$entity_type
->
id
());
$countries_by_bundle
=
[];
foreach
(
$bundles
as
$bundle
)
{
$values
=
[];
if
(
$bundle_key
=
$entity_type
->
getKey
(
'bundle'
))
{
$values
[
$bundle_key
]
=
$bundle
;
}
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
$entity
=
$storage
->
create
(
$values
);
if
(
$entity
->
hasField
(
$field_name
))
{
$countries_by_bundle
[
$bundle
]
=
$entity
->
get
(
$field_name
)
->
appendItem
()
->
getAvailableCountries
();
}
}
// Create the unified list, valid across bundles.
// Start by filtering out lists that are empty cause no restrictions apply.
$countries
=
[];
$countries_by_bundle
=
array_filter
(
$countries_by_bundle
);
if
(
count
(
$countries_by_bundle
)
===
1
)
{
$countries
=
reset
(
$countries_by_bundle
);
}
elseif
(
count
(
$countries_by_bundle
)
>
1
)
{
// Leave only the country codes that are common to all lists.
$countries
=
array_pop
(
$countries_by_bundle
);
foreach
(
$countries_by_bundle
as
$list
)
{
$countries
=
array_intersect_key
(
$countries
,
$list
);
}
}
$available_countries
=
$this
->
countryRepository
->
getList
();
if
(
!
empty
(
$countries
))
{
$available_countries
=
array_intersect_key
(
$available_countries
,
$countries
);
}
return
$available_countries
;
}
/**
* Gets the bundles for the current entity field.
*
* If the view has a non-exposed bundle filter, the bundles are taken from
* there. Otherwise, the field's bundles are used.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The current entity type.
* @param string $field_name
* The current field name.
*
* @return string[]
* The bundles.
*/
protected
function
getBundles
(
EntityTypeInterface
$entity_type
,
$field_name
)
{
$bundles
=
[];
$bundle_key
=
$entity_type
->
getKey
(
'bundle'
);
if
(
$bundle_key
&&
isset
(
$this
->
view
->
filter
[
$bundle_key
]))
{
$filter
=
$this
->
view
->
filter
[
$bundle_key
];
if
(
!
$filter
->
isExposed
()
&&
!
empty
(
$filter
->
value
))
{
// 'all' is added by Views and isn't a bundle.
$bundles
=
array_diff
(
$filter
->
value
,
[
'all'
]);
}
}
// Fallback to the list of bundles the field is attached to.
if
(
empty
(
$bundles
))
{
$map
=
$this
->
entityFieldManager
->
getFieldMap
();
$bundles
=
$map
[
$entity_type
->
id
()][
$field_name
][
'bundles'
];
}
return
$bundles
;
}
}
src/Plugin/views/filter/CountryCode.php
View file @
115bea5e
...
...
@@ -2,13 +2,6 @@
namespace
Drupal\address\Plugin\views\filter
;
use
CommerceGuys\Addressing\Country\CountryRepositoryInterface
;
use
Drupal\Core\Entity\EntityFieldManagerInterface
;
use
Drupal\Core\Entity\EntityTypeInterface
;
use
Drupal\Core\Entity\EntityTypeManagerInterface
;
use
Drupal\views\Plugin\views\filter\InOperator
;
use
Symfony\Component\DependencyInjection\ContainerInterface
;
/**
* Filter by country.
*
...
...
@@ -16,181 +9,17 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
*
* @ViewsFilter("country_code")
*/
class
CountryCode
extends
InOperator
{
/**
* The country repository.
*
* @var \CommerceGuys\Addressing\Country\CountryRepositoryInterface
*/
protected
$countryRepository
;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected
$entityTypeManager
;
/**
* The entity field manager.
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected
$entityFieldManager
;
/**
* Constructs a new CountryCode 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 \CommerceGuys\Addressing\Country\CountryRepositoryInterface $country_repository
* The country repository.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
* The entity field manager.
*/
public
function
__construct
(
array
$configuration
,
$plugin_id
,
$plugin_definition
,
CountryRepositoryInterface
$country_repository
,
EntityTypeManagerInterface
$entity_type_manager
,
EntityFieldManagerInterface
$entity_field_manager
)
{
parent
::
__construct
(
$configuration
,
$plugin_id
,
$plugin_definition
);
$this
->
countryRepository
=
$country_repository
;
$this
->
entityTypeManager
=
$entity_type_manager
;
$this
->
entityFieldManager
=
$entity_field_manager
;
}
/**
* {@inheritdoc}
*/
public
static
function
create
(
ContainerInterface
$container
,
array
$configuration
,
$plugin_id
,
$plugin_definition
)
{
return
new
static
(
$configuration
,
$plugin_id
,
$plugin_definition
,
$container
->
get
(
'address.country_repository'
),
$container
->
get
(
'entity_type.manager'
),
$container
->
get
(
'entity_field.manager'
)
);
}
class
CountryCode
extends
CountryAwareInOperatorBase
{
/**
* {@inheritdoc}
*/
public
function
getValueOptions
()
{
if
(
!
isset
(
$this
->
valueOptions
))
{
$entity_type_id
=
$this
->
getEntityType
();
$entity_type
=
$this
->
entityTypeManager
->
getDefinition
(
$entity_type_id
);
$field_name
=
$this
->
getFieldName
();
$available_countries
=
$this
->
getAvailableCountries
(
$entity_type
,
$field_name
);
$countries
=
$this
->
countryRepository
->
getList
();
if
(
!
empty
(
$available_countries
))
{
$countries
=
array_intersect_key
(
$countries
,
$available_countries
);
}
$this
->
valueOptions
=
$countries
;
$this
->
valueOptions
=
$this
->
getAvailableCountries
();
}
return
$this
->
valueOptions
;
}
/**
* Gets the name of the entity field on which this filter operates.
*
* @return string
* The field name.
*/
protected
function
getFieldName
()
{
if
(
isset
(
$this
->
configuration
[
'field_name'
]))
{
// Configurable field.
$field_name
=
$this
->
configuration
[
'field_name'
];
}
else
{
// Base field.
$field_name
=
$this
->
configuration
[
'entity field'
];
}
return
$field_name
;
}
/**
* Gets the list of available countries for the current entity field.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The current entity type.
* @param string $field_name
* The current field name.
*
* @return array
* An array of country codes. Empty if the country list isn't restricted.
*/
protected
function
getAvailableCountries
(
EntityTypeInterface
$entity_type
,
$field_name
)
{
$bundles
=
$this
->
getBundles
(
$entity_type
,
$field_name
);
$storage
=
$this
->
entityTypeManager
->
getStorage
(
$entity_type
->
id
());
$countries_by_bundle
=
[];
foreach
(
$bundles
as
$bundle
)
{
$values
=
[];
if
(
$bundle_key
=
$entity_type
->
getKey
(
'bundle'
))
{
$values
[
$bundle_key
]
=
$bundle
;
}
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
$entity
=
$storage
->
create
(
$values
);
if
(
$entity
->
hasField
(
$field_name
))
{
$countries_by_bundle
[
$bundle
]
=
$entity
->
get
(
$field_name
)
->
appendItem
()
->
getAvailableCountries
();
}
}
// Create the unified list, valid across bundles.
// Start by filtering out lists that are empty cause no restrictions apply.
$countries
=
[];
$countries_by_bundle
=
array_filter
(
$countries_by_bundle
);
if
(
count
(
$countries_by_bundle
)
===
1
)
{
$countries
=
reset
(
$countries_by_bundle
);
}
elseif
(
count
(
$countries_by_bundle
)
>
1
)
{
// Leave only the country codes that are common to all lists.
$countries
=
array_pop
(
$countries_by_bundle
);
foreach
(
$countries_by_bundle
as
$list
)
{
$countries
=
array_intersect_key
(
$countries
,
$list
);
}
}
return
$countries
;
}
/**
* Gets the bundles for the current entity field.
*
* If the view has a non-exposed bundle filter, the bundles are taken from
* there. Otherwise, the field's bundles are used.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The current entity type.
* @param string $field_name
* The current field name.
*
* @return string[]
* The bundles.
*/
protected
function
getBundles
(
EntityTypeInterface
$entity_type
,
$field_name
)
{
$bundles
=
[];
$bundle_key
=
$entity_type
->
getKey
(
'bundle'
);
if
(
$bundle_key
&&
isset
(
$this
->
view
->
filter
[
$bundle_key
]))
{
$filter
=
$this
->
view
->
filter
[
$bundle_key
];
if
(
!
$filter
->
isExposed
()
&&
!
empty
(
$filter
->
value
))
{
// 'all' is added by Views and isn't a bundle.
$bundles
=
array_diff
(
$filter
->
value
,
[
'all'
]);
}
}
// Fallback to the list of bundles the field is attached to.
if
(
empty
(
$bundles
))
{
$map
=
$this
->
entityFieldManager
->
getFieldMap
();
$bundles
=
$map
[
$entity_type
->
id
()][
$field_name
][
'bundles'
];
}
return
$bundles
;
}
}
tests/modules/address_test/address_test.info.yml
View file @
115bea5e
name
:
Address test
type
:
module
description
:
'
Provides
functionality
for
testing
the
events
in
address
module.'
description
:
'
Provides
functionality
for
testing
the
address
module.'
package
:
Testing
core
:
8.x
dependencies
:
-
address
-
views
tests/modules/address_test/config/install/field.field.node.address_test.field_address_test.yml
0 → 100644
View file @
115bea5e
langcode
:
en
status
:
true
dependencies
:
config
:
-
field.storage.node.field_address_test
-
node.type.address_test
module
:
-
address
id
:
node.address_test.field_address_test
field_name
:
field_address_test
entity_type
:
node
bundle
:
address_test
label
:
Address
description
:
'
'
required
:
false
translatable
:
false
default_value
:
{
}
default_value_callback
:
'
'
settings
:
available_countries
:
{
}
fields
:
administrativeArea
:
administrativeArea
locality
:
locality
dependentLocality
:
dependentLocality
postalCode
:
postalCode
sortingCode
:
sortingCode
addressLine1
:
addressLine1
addressLine2
:
addressLine2
organization
:
organization
givenName
:
givenName
additionalName
:
additionalName
familyName
:
familyName
langcode_override
:
'
'
field_type
:
address
tests/modules/address_test/config/install/field.storage.node.field_address_test.yml
0 → 100644
View file @
115bea5e
langcode
:
en
status
:
true
dependencies
:
module
:
-
address
-
node
id
:
node.field_address_test
field_name
:
field_address_test
entity_type
:
node
type
:
address
settings
:
{
}
module
:
address
locked
:
false
cardinality
:
1
translatable
:
true
indexes
:
{
}
persist_with_no_fields
:
false
custom_storage
:
false
tests/modules/address_test/config/install/node.type.address_test.yml
0 → 100644
View file @
115bea5e
langcode
:
en
status
:
true
name
:
'
Address
Test'
type
:
address_test
description
:
'
'
help
:
'
'
new_revision
:
false
preview_mode
:
1
display_submitted
:
true
tests/modules/address_test/config/optional/views.view.address_test_filter_administrative_area.yml
0 → 100644
View file @
115bea5e
langcode
:
en
status
:
true
dependencies
:
module
:
-
address
-
node
-
user
id
:
address_test_filter_administrative_area
label
:
'
address
test
filter
administrative
area'
module
:
views
description
:
'
'
tag
:
'
'
base_table
:
node_field_data
base_field
:
nid
core
:
8.x
display
:
default
:
display_plugin
:
default
id
:
default
display_title
:
Master
position
:
0
display_options
:
access
:
type
:
perm
options
:
perm
:
'
access
content'
cache
:
type
:
tag
options
:
{
}
query
:
type
:
views_query
options
:
disable_sql_rewrite
:
false
distinct
:
false
replica
:
false
query_comment
:
'
'
query_tags
:
{
}
exposed_form
:
type
:
basic
options
:
submit_button
:
Apply
reset_button
:
false
reset_button_label
:
Reset
exposed_sorts_label
:
'
Sort
by'
expose_sort_order
:
true
sort_asc_label
:
Asc
sort_desc_label
:
Desc
pager
:
type
:
none
options
:
offset
:
0
style
:
type
:
default
row
:
type
:
fields
options
:
default_field_elements
:
true
inline
:
{
}
separator
:
'
'
hide_empty
:
false
fields
:
title
:
id
:
title
table
:
node_field_data
field
:
title
entity_type
:
node
entity_field
:
title
label
:
'
'
alter
:
alter_text
:
false
make_link
:
false
absolute
:
false
trim
:
false
word_boundary
:
false
ellipsis
:
false
strip_tags
:
false
html
:
false
hide_empty
:
false
empty_zero
:
false
settings
:
link_to_entity
:
true
plugin_id
:
field
relationship
:
none
group_type
:
group
admin_label
:
'
'
exclude
:
false
element_type
:
'
'
element_class
:
'
'
element_label_type
:
'
'
element_label_class
:
'
'
element_label_colon
:
true
element_wrapper_type
:
'
'
element_wrapper_class
:
'
'
element_default_classes
:
true
empty
:
'
'
hide_alter_empty
:
true
click_sort_column
:
value
type
:
string