Similar to its Drupal 7 version #1269608: Integrate Addressfield with Search API
The Address module stores country and state information in the database as abbreviations such as NY for New York and US for United States. Unfortunately, this is how the Search API indexes the information meaning that the an aggregated fulltext search filter will not return results for 'United States' and 'New York' but only for US and NY. The Search API faceted search blocks for the Addressfield's country field does show the full name of the country but only the abbreviated letters for the state.
The Search API does have an API hook to alter the values of the items being indexed, function hook_search_api_index_items_alter(array &$items, SearchApiIndex $index), however, I can not find a way to change the values of the country and state abbreviations to the full name using any Address module's functions.
| Comment | File | Size | Author |
|---|---|---|---|
| #81 | search_api_facet_values.png | 23.36 KB | robpowell |
| #81 | search_api_configure_processor.png | 55.8 KB | robpowell |
| #81 | search_api_add_processor.png | 58.91 KB | robpowell |
| #81 | search_api_add_field.png | 211.17 KB | robpowell |
| #77 | address-integrate_address_searchapi-2812659-77.patch | 8.97 KB | recrit |
Issue fork address-2812659
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
bojanz commentedAddressPlainFormatter is a good example of getting both the codes and the full names.
Comment #3
chriscalip commented@bojanz
Thanks for the info. Currently building patch.
Comment #4
chriscalip commentedPatched Attached.
Comment #5
chriscalip commentedScreenshots of successful test attached.
Screenshots before Address Field : Full Administrative Area got activated.
2812659-before-address-processor-indexed.png
2812659-before-index-no-address-preprocessor.png
Screenshots of processor Address Field : Full Administrative use.
2812659-address-processor-settings.png
2812659-after-address-processor-indexed.png
Comment #6
borisson_Should be only one line.
Not sure about this id, let's prefix this with address field as well.
Let's mention in the label or description that this is only useful for US states.
We don't do this, we usually extend the contructor and implemt a
createmethod to set those in.I don't think we need to do it like that, can be refactored to be shorter.
This will also need at least a unit test, maybe integration as well (even though that'd need to have address as a test-dependency - so not sure about that.
Comment #7
borisson_Oh wait, this is in the address queue - not in search api.
The fourth issue I posted is probably not as relevant as for the search api queue.
This makes the integration test also a lot less viable, so that's probably not needed. Also not sure how strict @bojanz is about unit tests.
Comment #8
chriscalip commentedOk here's the patch:
Also here are response point by point from comment # 6.
1. Fixed. Additional ran phpcs using drupal codesniffer standards.
2. This is directly related to comment # 7. To be clear I dont think it is necessary to prefix with address field because it already namespace for address.
3. This processor for address is meant for all of the countries. Here's a screenshot, 2812659-address-processor-US-MX.png, that this processor is working for Mexico and United States. For illustration purposes here's code at main algorithm compressed in a simple script. The addressing api means to have a subdvision code and subdivision full name. Admittedly Canada in this example is using subdivision code for its subdivision name. But I believe thats for another issue entirely.
4. This is directly related to comment # 7. I believe this approach is ok as it makes use of existing resources provided by address module.
5. Nice, updated per suggestion.
6. About integration test and unit test.. yeah i think thats overkill :) please help.
Comment #9
chriscalip commentedComment #10
borisson_If no tests are needed, this looks rtbc to me.
Comment #11
chriscalip commentedSetting to conditional RTBC per previous comment. Up to address maintainers on go ahead.
Comment #12
bojanz commented1) We never use array() in Drupal anymore, only short array syntax: [].
2) The address format and subdivision repositories can be injected, you don't need to use \Drupal::service()?
3) I've never seen the convention of using "heap" as a prefix for static caches? Probably unneeded?
In the same block of code you use subdivisions, administrative areas, states. Only the first one is precise (state is just one label that an administrative area could have).
Architectural issues:
1) I don't see this code accounting for a country not having any subdivisions defined? In which case the static cache will always be empty and you will call subdivisionRepository->getAll() for each item? The library optimizes this away, but for clarity's sake it would make sense to acknowledge in the code that it's a possibility.
2) Some countries (Russia, China, Japan, etc) also have a local code and a local name (cyrlic, chinese version, etc). You would want to add those as well. The local code and the local name could be identical, in which case you'd only add the local code.
3) We would ideally register this handler for the locality and dependent_locality fields as well, load the right values using the parents. Brazil has predefined localities, China has both predefined levels. On those two levels the name could be the same as the code (cause there's no actual abbreviation to use), in which case you could skip adding it.
Comment #13
yoran scholiers commentedThis patch does not work correctly for me but I might be misunderstanding the desired functionality.
Instead of displaying the full country name (instead of the code) it displays the administrative subdivision.
So in this case the result is:
Country = wv - West Vlaanderen
subdevision = wv
EDIT
Never mind, I did misunderstand the purpose..
I was able to make it work for the country name as well.
Anyway, out of the box search_api integration would be a very nice to have.
Comment #14
chriscalip commentedWell changes from 8.x-1.0-beta3 to 8.x-1.0-beta4 broke api again.. and I don't want to deal doing constant corresponding changes to the API for this plugin patch. Maybe this plugin is safe from the api changes brought about by destructive patch https://www.drupal.org/node/2656052 I don't know, and I don't want to spend time and effort to something that will probably again change.
I'll revisit patch build once search_api gets to 1.x stable.
Comment #15
chriscalip commentedLooks like d8 search_api getting in a stable place. Going back to work on this patch.
Comment #16
drunken monkeyI won't comment on general code style issues, etc., just on the Search API side of things:
Largest problem: you mustn't use
setValues()to set unprocessed values on a field, as the documentation notes. UseaddValue()instead. (Cf. #2764385: Aggregated text plugin setting field value without datatype.)Also, if you don't override/implement
process()(or any of the otherprocess*()methods) anyways, there's no need to callprocessField()from here.Finally, I agree with Joris, the plugin ID should definitely be prefixed with the module name – as everywhere in Drupal. Only the module defining the plugin type (the Search API, in this case) can be exempt, as that sets the standard, which more or less guarantees there won't be any clashes (provided we're careful with new plugins now that 1.0 is out). For other modules, this can't be guaranteed, so the prefix is needed.
Again, it's the same for all other plugin types in Drupal.
Comment #17
chriscalip commentedThis patch is based on suggestions found in comment #12 by bojanz, and comment #16 by drunken monkey, and my own project needs.
A) comment#12 item 3) We would ideally register this handler for the locality and dependent_locality fields as well, load the right values using the parents. Brazil has predefined localities, China has both predefined levels. On those two levels the name could be the same as the code (cause there's no actual abbreviation to use), in which case you could skip adding it.
Great idea, I also need this on my projects. Hence plugin processor scope increased from just dealing administrative_area to targeted
$this->supportedComponents = ['country_code', 'administrative_area', 'locality', 'dependent_locality'];B) The plugin is now id = "address_abbreviations_to_full_form", class AddressAbbreviationsToFullForm per increased scope and comment#16.
C) configuration per field_name and component. So far we have configuration 'concat' in play.
Potentially doing :
country_code : US - United States
country_code : United States
administrative_areas: IL - Illinois
administrative_areas: Illinois
D) Point by point addressing comment #12 by bojanz
1) We never use array() in Drupal anymore, only short array syntax: [].
-- done. code changed to short array syntax
2. The address format and subdivision repositories can be injected, you don't need to use \Drupal::service()?
-- I was only using existing examples in address module codebase. What's the alternative way to inject these repos?
3) I've never seen the convention of using "heap" as a prefix for static caches? Probably unneeded?
-- done. code changed.. static caches removed, triangulation is derived strictly from api.
Architectural issues:
1) I don't see this code accounting for a country not having any subdivisions defined? In which case the static cache will always be empty and you will call subdivisionRepository->getAll() for each item? The library optimizes this away, but for clarity's sake it would make sense to acknowledge in the code that it's a possibility.
-- N/A because of code change.
2) Some countries (Russia, China, Japan, etc) also have a local code and a local name (cyrlic, chinese version, etc). You would want to add those as well. The local code and the local name could be identical, in which case you'd only add the local code.
-- cool, code changed.
E) comment#16
Also, if you don't override/implement process() (or any of the other process*() methods) anyways, there's no need to call processField() from here.
-- done. code updated.
Largest problem: you mustn't use setValues() to set unprocessed values on a field, as the documentation notes. Use addValue() instead.
-- I am unable to comply with suggestion as the processor plugin requires update of address component code value to full text value. I am unable to make use of $field->addValue()
Reference: search_api/src/Item/Field.php
This appends the full text value to a random delta on value.. its pretty unreliable and unusable for this situation. Please update patch if there is a way.
Comment #18
chriscalip commentedScreenshot of configuration of processor plugin at search_api dashboard.
Comment #19
chriscalip commentedComment #20
chriscalip commentedPatch #17 is not enough. Sadly patch #17 does not hit 100% when used in live production situations. This patch fails to handle situations where same field and component is used n times. It clearly needs attributes from "field_name,component" to "field_name,component,machine_name". Patch needs work.
Comment #21
chriscalip commentedComment #22
chriscalip commentedComment #23
chriscalip commentedThis patch, integrate-address-searchapi-2812659-23.patch, fixes concerns by comment #20.
a.) Processor is now centered around the search_api index fields instead of entity fields and its components.
b.) run through of codebase on phpcs per drupal.org/project/coder 8.x styleguide.
c.) Screenshot abbrev2full-processor-admin-config.png shows processor configuration per search_api index field.
d.) Screenshot abbrev2full-noderecord.png shows node records with multiple address field values.
e.) Screenshot abbrev2full-indexrecord.png shows delta alignment. Delta alignment is why I think
$field->addValue()does not apply for this situation.f.) interdiff-2812659-17-23.txt :)
Comment #24
chriscalip commentedPatch needs review.
Comment #25
gnugetHi!
Thanks for all the work on this patch.
I tried this today and I got an error when the data is re-indexing if I set the type as "full text" in the fields page.
Comment #26
drunken monkeyYes, that's exactly what will happen if
setValues()is used instead ofaddValue().Comment #27
gnugetSo, this needs work, yes?
Thanks!
Comment #28
recrit commentedThis can implemented cleaner by extending the property definitions of the address field items with computed fields for the full names of the sub-properties.
With the full names as field item properties:
* Search API automatically finds them.
* They can be added to the Search API index fields as needed.
* Concatenation can be accomplished with Search API's "Aggregated fields" with the code property and the equivalent new full name property.
The attached patch adds:
Comment #29
chriscalip commentedHeads up, I'll stop participating on this issue for the time being because most of my current and immediate projects are rest-api based which is mostly laravel.
Comment #30
vaccinemedia commented@recrit I can't add the address fields using the patch above to facets unfortunately... I get this:
Error: Call to undefined method Drupal\Core\TypedData\DataDefinition::getPropertyDefinitions() in Drupal\facets\Plugin\facets\processor\BooleanItemProcessor->supportsFacet() (line 92 of /var/www/vhosts/example.dev/web/modules/contrib/facets/src/Plugin/facets/processor/BooleanItemProcessor.php) #0
Comment #31
borisson_#30 is a bug in facets, see #2917323: Critical error thrown when editing a facet based on an aggregated field - please confirm if the patch there fixes your problem.
Comment #32
vaccinemedia commented@borisson_ thanks for the link. This did indeed fix the issue. Just to clarify - I have a content type with an address field and search api installed using database (for now may up to using solar before the project is finished). Instead of using the patch by chriscalip which appears to add a processor option to the index I went for the latest patch by recrit which adds the full country name to the list of fields I can add to the index.
I have created a view based on the index and added 4 of the required fields into a table display.
I then added some facets for taxonomy terms which worked great. Then I got the error mentioned above for country name but the patch you referenced has enabled me to fully configure the facet and place all the blocks required for testing. So for that - thanks very much!
Quick question though as I prefer to make sure I'm doing things correctly: In your opinion, which patch should I be using here? The one by chriscalip which adds a processor plugin specifically for address fields or recrit which allows you to add the country field with nothing extra turned on?
Comment #33
nickbits commentedHi,
I applied the patch in #28 thinking it would fix my issue. Sadly doesn't seem to be working for me. I may have missed the point totally here. Here is what I have - a content type with an address field. Got Search API installed using database for the index.
Can add the address field to the agregated content.
For the field I can add additional_name, locality_name, address_line1 and so on. However it does report one field skipped, field_item:address (see attached screenshot).
Ignoring this I add the fields, perform a re-index, and do a search for something I know is in one of the fields. Location name, postcodes, etc. It does find most of them. The only one that doesn't seem to work is "Company" which is what I assume is Organization.
Comment #34
andriy khomych commentedHi Bojan Živanović, Michael Vanetta.
Why wasn't https://www.drupal.org/files/issues/address-search-api-full-name-properties-2812659-28.patch added to the module? Except for comment https://www.drupal.org/project/address/issues/2812659#comment-12563243, it works clear and I think is the best suggestion. However, it requires some views filter for the Search API like
Drupal\address\Plugin\views\filter\AdministrativeArea. Can you check this issue again and maybe update main issue goals? E.g. if somebody wants to finish this issue.Comment #35
andriy khomych commentedComment #36
radiumhe commentedaddress 8.x-1.4 "require": "commerceguys/addressing": "^1.0.0" , Addressing\LocaleHelper -> Addressing\Locale
addressing-1.0.0-beta5 is LocaleHelper.php
revise
Comment #37
recrit commented@radiumhe Thanks for locale change!
Patch re-rolled for the latest 8.x-1.x as of #a29a522.
Comment #38
recrit commentedupdated status
Comment #39
kyuubi commentedHi guys,
Patch seems to be working for me.
When can we make this RTBC?
Comment #40
rbosscher commentedI have used #37 successfully for a while now, I believe when multiple users has tested the patch with success we can mark this RTBC.
Comment #41
bojanz commented#28 and later are "won't fix" as far as I'm concerned. We are not going to modify the field type itself to support a contrib module, especially since the original approach seemed to be valid (adding search-api specific plugins).
Rewriting the patch mid-issue after it has already been reviewed is a good way to ensure an issue never lands.
Comment #42
chriscalip commentedTo my future self or anyone wanting to move this issue forward.
Notes to move forward #23 patch. Approach via search-api specific plugins
a.) Instead of method preprocessIndexItems use addFieldValues; this will make patch compliant to comment #16
For an example see
search_api/src/Plugin/search_api/processor/AddUrl.phpAlso see https://www.drupal.org/docs/8/modules/search-api/developer-documentation...
Check into #36 tidbit.
b.) Please create unit tests.
I know its tedious but it saves the contrib maintainer(s) future time and effort by having unit test. Yes --> address module has reached that complexity threshold needing unit-tests. Unit test(s) helps software maintainers be able to safely add-in new features/new fixes/new changes. For example on upcoming address 8.2.x a unit-test gives visibility IF these plugins breaks with a new major version.
Breaking changes happens on major versions. address 8.1.x -> address 8.2.x
For patch to have a unit-test regimen I suggest a split of responsibilities per class.
Country to full text as
Drupal\address\Plugin\search_api\processor\AddressTextCountry,Drupal\address\Plugin\search_api\processor\AddressCodeTextCountryprocessor\AddressTextCountry strictly does country to full text and processor\AddressCodeTextCountry doing country code with full text of country.
Administrative Area as
Drupal\address\Plugin\search_api\processor\AddressTextAdminArea,Drupal\address\Plugin\search_api\processor\AddressTextCodeAdminArea, etc..ie. https://en.wikipedia.org/wiki/Single_responsibility_principle
For an example of unit-testing see
search_api/tests/src/Unit/Plugin/Processor/AddURLTest.phpComment #43
maskedjellybeanIs there any way to use the entire address as a single field to build a facet? For example, I'd like a facet block of checkboxes with the entire address as the checkbox label.
Edit: I've realized what I'm asking for would not be practical for usability anyways. Nevermind!
Comment #44
andrew answer commentedHello,
I modified patch #23 to use addValue(). Now I can use full text search field and it works. I also tried to use Search API Autocomplete with Address field, but it doesn't work. I created another issue for this: #3126474: Integrate Address with Search API Autocomplete.
Comment #45
andrew answer commentedAlso, I see notice "Notice: Undefined offset: 1 in Drupal\address\Plugin\search_api\processor\AddressAbbreviationsToFullForm->buildConfigurationForm() (line 69 of modules/contrib/address/src/Plugin/search_api/processor/AddressAbbreviationsToFullForm.php)." in some cases. I fixed it.
Comment #46
andrew answer commentedComment #47
andrew answer commentedChecked on working site and fixed several other errors.
Comment #48
andrew answer commentedFixed the typo.
Comment #49
andrew answer commentedComment #50
langelhc commentedHello,
After Applying patch #48:
1. In Facets: I get duplicated items (Country code and Country name)
PE (1)
Peru (1)
United States (1)
US (1)
2. Views using Content indexed: When 'Content datasource: address » The two-letter country code (indexed field)' field is added Country code is displayed.
Comment #51
clemens.tolboomComment #52
vflirt commentedMinor fix for when the address is empty.
Comment #53
andrew answer commentedThis patch replaces the field value instead of adding it, so @langelhc it can probably fix your problem (but the facet case hasn't been tested by me yet).
Comment #54
andrew answer commentedComment #55
oleksiyThe patch gives me the following error:
It works only if "Fulltext" field type selected.
And another error I got when tried to apply the previous patch (#52):
Drupal\search_api_solr\SearchApiSolrException while indexing item entity:node/6:en: Solr endpoint http://solr:8983/ bad request (400). ERROR: [doc=674e8e-search_api_solr_index-entity:node/6:en] multiple values encountered for non multiValued field ss_country_code: [UA, Ukraine] in Drupal\search_api_solr\SolrConnector\SolrConnectorPluginBase->handleHttpException() (line 997 of /modules/contrib/search_api_solr/src/SolrConnector/SolrConnectorPluginBase.php).Comment #56
oleksiyAdded fix for scalar values.
Comment #57
didierdemaeyer commentedAdded support for fields on referenced entities.
For example, when you want to use the processor on fields from a user profile (https://www.drupal.org/project/profile).
Then the property path is something like this
user_profiles:entity:field_address:country_codeComment #59
ghenov.andrei commentedFixed - warnings about undefined offset.
Comment #60
ghenov.andrei commented// [$field_name, $component, $reference_field_name, $reference_component] = explode(':', $field->getPropertyPath());
[$field_name, $component, $reference_field_name, $reference_component] = array_pad(explode(':', $field->getPropertyPath()), 4, '');
// $target = $reference_component ?? $component;
$target = $reference_component ?: $component;
Comment #61
recrit commentedAll of the "fixes" for the Search API approach patch - facet support, any index field type, any level of nesting of entity references - were already handled by just adding the computed properties to the address field type in the patch #37.
The Search API Processor Plugin that is post processing an existing indexed field is going to have these issues since you are trying to reproduce what Drupal Core already provides to you with the Field API system. The admin UX also will have the issue where the admin / developer must know that the index type selected on the Search API "Fields" page must be acceptable by the new Search API Processor plugin selected on the Search API "Processors" page.
Adding the computed properties to the field type solves all of these issues for the Search API indexing while exposing the properties for any non Search API usage.
Example: Get the administrative area name.
Comment #62
damienmckennaMaintainers - any feedback on @recrit's comment #61?
Comment #63
damienmckennaQuick reminder - please set the status to "needs review" after you upload a patch so we can see what the testbot thinks of it.
Comment #64
rszrama commentedCopying some thoughts over from Slack, let's start by attempting to make the Search API field processor plugin work. If that system was designed to do what this issue desires, I'd second bojanz's earlier desire to make use of it vs. working around it with a pattern unique to this module. (In other words, I'd rather we do what other modules do, if that's the case with the processor, vs. present our own workaround for Address.)
I believe the latest patch to work from is #59, but I haven't tested it myself.
Comment #65
pyxio commentedi am getting the following error in drupal 9.3.7
PHP Fatal error: Cannot declare class Drupal\address\Plugin\search_api\processor\AddressAbbreviationsToFullForm, because the name is already in use in /var/www/html/*/web/modules/contrib/search_api/src/Plugin/search_api/processor/AddressAbbreviationsToFullForm.php on line 29
is there a fix? cheers kevin
Comment #66
drunken monkey@ pyxio: Seems like you maybe applied the patch to both the Search API and the Address modules, leading to two copies of the same class in your installation? The patch should only be applied to Address, not to Search API.
Please delete the one in
web/modules/contrib/search_api/src/Plugin/search_api/processorand make sure there is also one inweb/modules/contrib/address/src/Plugin/search_api/processor.Comment #67
pyxio commented@drunken monkey thanks for the reply. I do not believe I tried to patch search api but I can't confirm that now as I have updated the code base.
Now I have applied the patch successfully and there are no errors. I now have the processor Address Field : Convert Abbreviations into Full Text Form. available and have enabled it. Unfortunately, views field and facet still show abbreviation. I have tried both fulltext and string in the search api fields config. I can't find any other settings.
What else is needed to configure other than enable the processor and reindex? many thanks.
Comment #68
golddragon007 commentedSomething does not seem correct to me, I can't select the country code for indexing and therefore I can't apply this preprocess to my address field. To get the country code in the facet list, I need to use the bare field, without any additional "target" or subpath.
Comment #69
golddragon007 commentedBecause the county_code is actually the main property of this field, it can't be referred to as a component like others. So it was needed to adjust the logic.
Comment #70
damienmckennaFor sites that might be using it, this provides a fix for patch #37 due to changes in the addressing library.
Comment #71
socialnicheguru commentedso is #69 or #70 the correct patch?
Comment #72
damienmckenna#69 is the preferred path forward, #70 was a fix of #37 necessary for a site that was built using the previous approach where we didn't have time to switch (we'll work on the switch shortly).
Comment #73
manuel.adanAdded support for country field type.
Comment #74
manuel.adanCountry field stores the country code in the default 'value' property instead of 'country_code'.
Comment #75
dxvargas commentedPatch #74 works well (as did patch #69) with an address field.
I've also tested with a Country field type and the preprocessor worked as expected.
I vote for this to be RTBC.
Comment #76
borisson_This looks great, I'm not sure how viable it is to add integration tests for this and a unit test doesn't add much value, because it's only the integration with search api that matters.
RTBC based on that.
Comment #77
recrit commentedAfter applying patch address-integrate_address_searchapi-2812659-74.patch, I started to notice the logs being littered with the following warning:
Cause:
This is caused by the new code in patch 74 to account for the country field:
An address field can have optional properties so
$field_value[$target]may actually be NULL for an address field (not a country field).Fix:
The attached patch changes the line to the following to account for NULL values.
The patch also updates the "preprocessIndexField" method to account for NULL to avoid string operations on a NULL value which causes deprecation notices in PHP 8.1
Comment #78
maxilein commentedDoes 2.0 work with search api?
Comment #79
bojanz commentedChanging version to 2.x-dev, this will have to go into the 2.1.0 release, 8.x-1.x is now closed.
Comment #80
proweb.ua commentedaddress 2.0.1
#77 works
Comment #81
robpowellSteps to test
I tested on
"drupal/search_api": "1.40.0",
"drupal/address": "2.0.4",
"drupal/facets": "3.0.2",
This works! See screenshots.
Comment #82
steinmb commentedBased on #76, remove the need for tests tag. I would help to get this in if the patch would be converted to a MR.
Comment #83
kevinquillen commentedCountry code is missing for some reason.
Comment #84
kevinquillen commentedActually 'country_code' is represented as 'address' which is quite misleading. It also would index the code and not the country name (I suspect most would want that option) which I could only get with a Custom Value index item and token.
Comment #87
tbkot commentedMR is created based on patch #77