(original title: "Country validation fails when Google Chrome autofill populates the Country field")

When the Country field gets populated by Chrome's autofill option an error gets thrown.

Notice: Undefined index: #default_value in addressfield_standard_country_validate()

It seems browser specific since Safari isn't causing any issues.

Drupal 7.56
Addressfield 7.x-1.2
Google Chrome 61.0.3163.100

P.S. I'm on a Mac

CommentFileSizeAuthor
#6 addressfield-n2914448-6.patch685 bytesDamienMcKenna
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

timcamps created an issue. See original summary.

donquixote’s picture

Title: Country validation fails when Google Chrome autofill populates the Country field » Notice: Undefined index: #default_value in addressfield_standard_country_validate() (e.g. with Google Chrome autofill)
Issue summary: View changes

I second this.

I am changing the title, so that people can search for the error message (notice) itself.

I had this a few times, and I think in those cases it was reproducible.
I do not remember the exact criteria, unfortunately. But I remember my debugging results!

Where does the error/notice happen?

The problem is that addressfield_standard_country_validate() assumes that $element['#default_value'] is always defined. However, this is not guaranteed.

Where is the #default_value filled?

In _addressfield_process_format_form():

      if (isset($address[$key])) {
        $child['#default_value'] = $address[$key];
      }

This means: If $address[$key] === NULL, the #default_value will not be set.

In the case that I was debugging, many of the address components were indeed NULL.

Where does $address come from?

The function _addressfield_process_format_form() is called from addressfield_process_format_form(), with $address === $format['#address'].

  _addressfield_process_format_form($format, $format['#address']);

Where is $format['#address'] filled?

In addressfield_generate():

  $format['#address'] = $address;

Where does this $address come from?

It may come from form input or from the (possibly empty) shipping profile.
I hope I come into a situation where I can provide more info.

Solution?

Add an isset($element['#default_value']) check at the top of addressfield_standard_country_validate()!
It is usually not wise to rely on array values being set.

donquixote’s picture

Original title "Country validation fails" was not fully correct.
The validation did not fail, it simply produced a notice.

donquixote’s picture

fgjohnson@lojoh.ca’s picture

We are getting this Notice when we save a content type "Person" that includes a dropdown field for "Building".
The Building content type includes the "Address Field".

Oddly though - It only throws this message when I add additional components not related to Building...
Digging.

DamienMcKenna’s picture

Version: 7.x-1.2 » 7.x-1.x-dev
Status: Active » Needs review
FileSize
685 bytes

I haven't reproduced this myself, but one site I maintain shows up with the error occasionally.

Here's a simple isset() on the variable.

DamienMcKenna’s picture

For what it's worth, the last time this happened on our site it was for an anonymous visitor.

parasolx’s picture

Status: Needs review » Reviewed & tested by the community

Patch #6 yet simple and working perfectly on my production system.

donquixote’s picture

Status: Reviewed & tested by the community » Needs work

I had a quick look at the patch. No time to actually test it unfortunately.

I am sure it solves the issue described here.
But does it preserve the intended behavior? Does it do the right thing in the edge case?

If isset($element['#default_value']), it behaves as before.

If !isset($element['#default_value']), now the code within the if() is skipped.
Is this intended?
It is long ago that I looked at this, but I would assume if #default_value is not set, then it should behave as if #value != #default_value.

original:

  if ($element['#default_value'] != $element['#value']) {

patch from #6:

  if (isset($element['#default_value']) && $element['#default_value'] != $element['#value']) {

proposed change:

  if (!isset($element['#default_value']) || $element['#default_value'] != $element['#value']) {

Atm I am not sure which one would be the "correct" behavior.
In either case we need an explanation why we do one or the other (or something else).

Otherwise we risk to fix one problem but introduce another.

tonytheferg’s picture

I am seeing this notice in the logs also now.