/**
  * {@inheritdoc}
  */
 public function render(ResultRow $values)
 {
     $value = $this->getValue($values);
     if (empty($value)) {
         return '';
     }
     $entity = $this->getEntity($values);
     $address = $entity->{$this->definition['field_name']}->first();
     switch ($this->definition['property']) {
         case 'administrative_area':
             $parent_id = NULL;
             $needs_parent = FALSE;
             break;
         case 'locality':
             $parent_id = $address->administrative_area;
             $needs_parent = TRUE;
             break;
         case 'dependent_locality':
             $parent_id = $address->locality;
             $needs_parent = TRUE;
             break;
     }
     if (!$needs_parent || !empty($parent_id)) {
         $subdivisions = $this->subdivisionRepository->getList($address->country_code, $parent_id);
         if (isset($subdivisions[$value])) {
             $value = $subdivisions[$value];
         }
     }
     return $this->sanitizeValue($value);
 }
 /**
  * Gets the address values used for rendering.
  *
  * @param \Drupal\address\AddressInterface $address
  *   The address.
  * @param \Drupal\address\Entity\AddressFormatInterface $address_format
  *   The address format.
  *
  * @return array
  *   The values, keyed by address field.
  */
 protected function getValues(AddressInterface $address, AddressFormatInterface $address_format)
 {
     $values = [];
     foreach (AddressField::getAll() as $field) {
         $getter = 'get' . ucfirst($field);
         $values[$field] = $address->{$getter}();
     }
     // Replace the subdivision values with the names of any predefined ones.
     foreach ($address_format->getUsedSubdivisionFields() as $field) {
         if (empty($values[$field])) {
             // This level is empty, so there can be no sublevels.
             break;
         }
         $subdivision = $this->subdivisionRepository->get($values[$field], $address->getLocale());
         if (!$subdivision) {
             // This level has no predefined subdivisions, stop.
             break;
         }
         $values[$field] = $subdivision->getCode();
         if (!$subdivision->hasChildren()) {
             // The current subdivision has no children, stop.
             break;
         }
     }
     return $values;
 }
 /**
  * Builds the subdivision form elements.
  *
  * @param array $form
  *   The form.
  * @param array $values
  *   The form values.
  * @param \Drupal\address\Entity\AddressFormatInterface $address_format
  *  The address format for the selected country.
  *
  * @return array
  *   The form with the added subdivision elements.
  */
 protected function buildSubdivisionElements(array $form, array $values, AddressFormatInterface $address_format)
 {
     $depth = $this->subdivisionRepository->getDepth($values['country_code']);
     if ($depth === 0) {
         // No predefined data found.
         return $form;
     }
     $labels = LabelHelper::getFieldLabels($address_format);
     $subdivision_fields = $address_format->getUsedSubdivisionFields();
     $current_depth = 1;
     foreach ($subdivision_fields as $index => $field) {
         $property = FieldHelper::getPropertyName($field);
         $parent_property = $index ? FieldHelper::getPropertyName($subdivision_fields[$index - 1]) : NULL;
         if ($parent_property && empty($values[$parent_property])) {
             // No parent value selected.
             break;
         }
         $parent_id = $parent_property ? $values[$parent_property] : NULL;
         $subdivisions = $this->subdivisionRepository->getList($values['country_code'], $parent_id);
         if (empty($subdivisions)) {
             break;
         }
         $form[$property] = ['#type' => 'select', '#title' => $labels[$field], '#options' => $subdivisions, '#default_value' => $values[$property], '#empty_option' => $this->t('- All -')];
         if ($current_depth < $depth) {
             $form[$property]['#ajax'] = ['callback' => [get_class($this), 'ajaxRefresh'], 'wrapper' => $form['#wrapper_id']];
         }
         $current_depth++;
     }
     return $form;
 }
 /**
  * Gets the address values used for rendering.
  *
  * @param \Drupal\address\AddressInterface $address
  *   The address.
  * @param \Drupal\address\Entity\AddressFormatInterface $address_format
  *   The address format.
  *
  * @return array
  *   The values, keyed by address field.
  */
 protected function getValues(AddressInterface $address, AddressFormatInterface $address_format)
 {
     $values = [];
     foreach (AddressField::getAll() as $field) {
         $getter = 'get' . ucfirst($field);
         $values[$field] = $address->{$getter}();
     }
     foreach ($address_format->getUsedSubdivisionFields() as $field) {
         $value = $values[$field];
         // The template needs access to both the subdivision code and name.
         $values[$field] = ['code' => '', 'name' => $value];
         if (empty($value)) {
             // This level is empty, so there can be no sublevels.
             break;
         }
         $subdivision = $this->subdivisionRepository->get($value, $address->getLocale());
         if (!$subdivision) {
             // This level has no predefined subdivisions, stop.
             break;
         }
         // Replace the subdivision values with the predefined ones.
         $values[$field] = ['code' => $subdivision->getCode(), 'name' => $subdivision->getName()];
         if (!$subdivision->hasChildren()) {
             // The current subdivision has no children, stop.
             break;
         }
     }
     return $values;
 }
 /**
  * Validates the provided subdivision values.
  *
  * @param array                  $values        The field values, keyed by field constants.
  * @param AddressFormatInterface $addressFormat The address format.
  * @param Constraint             $constraint    The constraint.
  *
  * @return array An array of found valid subdivisions.
  */
 protected function validateSubdivisions($values, AddressFormatInterface $addressFormat, $constraint)
 {
     $countryCode = $addressFormat->getCountryCode();
     $subdivisionFields = $addressFormat->getUsedSubdivisionFields();
     $foundIds = [];
     foreach ($subdivisionFields as $index => $field) {
         if (empty($values[$field]) || !in_array($field, $constraint->fields)) {
             // The field is empty or validation is disabled.
             break;
         }
         $parentField = $index ? $subdivisionFields[$index - 1] : null;
         $parentId = $parentField ? $values[$parentField] : null;
         $children = $this->subdivisionRepository->getList($countryCode, $parentId);
         if (!$children) {
             // No predefined subdivisions found.
             break;
         }
         $found = false;
         $value = $values[$field];
         if (isset($children[$value])) {
             $found = true;
             $foundIds[] = $value;
         }
         if (!$found) {
             $this->addViolation($field, $constraint->invalidMessage, $value, $addressFormat);
             break;
         }
     }
     // Load the found subdivision ids.
     $subdivisions = [];
     foreach ($foundIds as $id) {
         $subdivisions[] = $this->subdivisionRepository->get($id);
     }
     return $subdivisions;
 }
 /**
  * Gets a list of form fields for the provided address format.
  *
  * @param AddressFormatInterface $addressFormat
  * @param array                  $subdivisions  An array of needed subdivisions.
  *
  * @return array An array in the $field => $formOptions format.
  */
 protected function getFormFields(AddressFormatInterface $addressFormat, $subdivisions)
 {
     // @todo Add support for having multiple fields in the same line.
     $fields = [];
     $labels = $this->getFieldLabels($addressFormat);
     $requiredFields = $addressFormat->getRequiredFields();
     $groupedFields = $addressFormat->getGroupedFields();
     foreach ($groupedFields as $lineFields) {
         foreach ($lineFields as $field) {
             $fields[$field] = ['label' => $labels[$field], 'required' => in_array($field, $requiredFields)];
         }
     }
     // Add choices for predefined subdivisions.
     foreach ($subdivisions as $field => $parentId) {
         // @todo Pass the form locale to get the translated values.
         $children = $this->subdivisionRepository->getList($addressFormat->getCountryCode(), $parentId);
         if ($children) {
             $fields[$field]['choices'] = $children;
         }
     }
     return $fields;
 }
 /**
  * Processes the subdivision elements, adding predefined values where found.
  *
  * @param array $element
  *   The existing form element array.
  * @param array $values
  *   An array of address values, keyed by property name.
  * @param \Drupal\address\Entity\AddressFormatInterface $address_format
  *   The address format.
  *
  * @return array
  *   The processed form element array.
  */
 protected function processSubdivisionElements(array $element, array $values, AddressFormatInterface $address_format)
 {
     $depth = $this->subdivisionRepository->getDepth($values['country_code']);
     if ($depth === 0) {
         // No predefined data found.
         return $element;
     }
     $subdivision_properties = [];
     foreach ($address_format->getUsedSubdivisionFields() as $field) {
         $subdivision_properties[] = FieldHelper::getPropertyName($field);
     }
     // Load and insert the subdivisions for each parent id.
     $currentDepth = 1;
     foreach ($subdivision_properties as $index => $property) {
         if (!isset($element[$property]) || !Element::isVisibleElement($element[$property])) {
             break;
         }
         $parent_property = $index ? $subdivision_properties[$index - 1] : NULL;
         if ($parent_property && empty($values[$parent_property])) {
             break;
         }
         $parent_id = $parent_property ? $values[$parent_property] : NULL;
         $subdivisions = $this->subdivisionRepository->getList($values['country_code'], $parent_id);
         if (empty($subdivisions)) {
             break;
         }
         $element[$property]['#type'] = 'select';
         $element[$property]['#options'] = $subdivisions;
         $element[$property]['#empty_value'] = '';
         unset($element[$property]['#size']);
         if ($currentDepth < $depth) {
             $element[$property]['#ajax'] = ['callback' => [get_class($this), 'ajaxRefresh'], 'wrapper' => $element['#wrapper_id']];
         }
         $currentDepth++;
     }
     return $element;
 }