commerce_amws-8.x-1.x-dev/modules/order/src/HelperService.php
modules/order/src/HelperService.php
<?php
namespace Drupal\commerce_amws_order;
use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Psr\Log\LoggerInterface;
/**
* Provides helper functions related to Amazon MWS orders.
*/
class HelperService {
/**
* The profile storage.
*
* @var \Drupal\profile\ProfileStorageInterface
*/
protected $profileStorage;
/**
* The Amazon MWS order configuration.
*
* @var \Drupal\Core\Config\Config
*/
protected $config;
/**
* The logger.
*
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
/**
* Constructs a new HelperService object.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The configuration object factory.
* @param \Psr\Logger\LoggerInterface $logger
* The logger.
*/
public function __construct(
EntityTypeManagerInterface $entity_type_manager,
ConfigFactoryInterface $config_factory,
LoggerInterface $logger
) {
$this->profileStorage = $entity_type_manager->getStorage('profile');
$this->config = $config_factory->get('commerce_amws_order.settings');
$this->logger = $logger;
}
/**
* Creates a profile for the given Amazon MWS address data.
*
* @param \Drupal\commerce_order\Entity\OrderInterface $order
* The created order that will hold the profile.
* @param object $amws_address
* The adress data of an Amazon MWS order. It should be the data contained
* in the order's `ShippingAddress` property.
* @param string $profile_type
* The type of the profile that will be created. Defaults to the `customer`
* profile type that is the default profile used by Drupal Commerce.
* @param bool $save
* Whether to save the created profile. If FALSE, the created profile will
* be returned unsaved.
*
* @return \Drupal\profile\Entity\ProfileInterface
* The created profile entity.
*/
public function amwsAddressToCustomerProfile(
OrderInterface $order,
\stdClass $amws_address,
$profile_type = 'customer',
$save = TRUE
) {
$profile = $this->profileStorage->create([
'type' => $profile_type,
// Following Drupal Commerce conventions, the profile belongs to the order
// and not to the user's address book therefore the 0 owner ID.
'uid' => 0,
'address' => $this->amwsAddressToAddressValue($amws_address),
]);
if ($save) {
$profile->save();
}
return $profile;
}
/**
* Returns the AMWS address data converting to array format.
*
* The array is formatted as required by the `address` field type.
*
* @param object $amws_address
* The adress data of an Amazon MWS order. It should be the data contained
* in the order's `ShippingAddress` property.
*
* @return array
* An array containing the values for a Drupal `address` field.
*/
public function amwsAddressToAddressValue(\stdClass $amws_address) {
// Address.
$address = $this->parseAmwsAddress($amws_address);
// Name.
if (!empty($amws_address->Name)) {
$address += $this->parseAmwsName($amws_address->Name);
}
return $address;
}
/**
* Parses Amazon MWS address data and converts it to Drupal address data.
*
* @param object $amws_address
* The adress data of an Amazon MWS order. It should be the data contained
* in the order's `ShippingAddress` property.
*
* @return array
* An array containing the values for a Drupal `address` field.
*/
protected function parseAmwsAddress(\stdClass $amws_address) {
$address = [];
if (!empty($amws_address->CountryCode)) {
$address['country_code'] = $amws_address->CountryCode;
}
if (!empty($amws_address->StateOrRegion)) {
if (empty($amws_address->CountryCode)) {
$address['administrative_area'] = $amws_address->StateOrRegion;
}
else {
$address['administrative_area'] = $this->parseAmwsStateOrRegion(
$amws_address->CountryCode,
$amws_address->StateOrRegion
);
}
}
if (!empty($amws_address->City)) {
$address['locality'] = $amws_address->City;
}
if (!empty($amws_address->PostalCode)) {
$address['postal_code'] = $amws_address->PostalCode;
}
if (!empty($amws_address->AddressLine1)) {
$address['address_line1'] = $amws_address->AddressLine1;
}
// Amazon MWS address provides 3 address lines while Drupal address supports
// only 2. We will be entering the concatenation of the 2nd and 3rd Amazon
// MWS address line as the 2nd Drupal address line.
if (!empty($amws_address->AddressLine2)) {
$address['address_line2'] = $amws_address->AddressLine2;
}
if (!empty($amws_address->AddressLine3)) {
if (empty($address['address_line2'])) {
$address['address_line2'] = $amws_address->AddressLine3;
}
else {
$address['address_line2'] .= ', ' . $amws_address->AddressLine3;
}
}
return $address;
}
/**
* Converts an Amazon MWS name into a 3-component Drupal address name.
*
* We ignore the additional name and simply split the name into a given name
* and a family name.
*
* @param string $name
* The name to parse.
*
* @return array
* An array containing the components of the name as expected by a Drupal
* `address` field.
*/
protected function parseAmwsName($name) {
$name_parts = explode(' ', $name);
$names = [];
$names['family_name'] = array_pop($name_parts);
if (count($name_parts)) {
$names['given_name'] = implode(' ', $name_parts);
}
return $names;
}
/**
* Converts the state or region field to the an administrative area code.
*
* In some old addresses Amazon MWS gives us the full USA state name instead
* of the 2-digit code e.g. NEW MEXICO instead of NM. In such cases, try to
* identify the code using the JSON resource files from the
* `commerceguys/addressing` library.
*
* @param string $country_code
* The address's country code.
* @param string $state
* The state code or name.
*
* @return string
* The parsed state or region.
*/
protected function parseAmwsStateOrRegion($country_code, $state) {
$convert_states = $this->config->get('general.address_convert_states');
if (!$convert_states) {
return $state;
}
// For now, only USA states are supported.
if ($country_code !== 'US') {
return $state;
}
$state_lowercase = strtolower($state);
// Load the list of administrative areas (subdivisions) for the country from
// the `commerceguys/addressing` library. We expect the library to be under
// the `vendor` folder in the standard location; but we may make this
// configurable in the future.
$subdivisions_dir = realpath(DRUPAL_ROOT . '/../vendor/commerceguys/addressing/resources/subdivision');
$filename = $subdivisions_dir . '/' . $country_code . '.json';
if (!file_exists($filename)) {
$this->logger->warning(
'The file containing the subdivisions for the country with code "@country_code" was not found at the expected location ("@filename").',
[
'@country_code' => $country_code,
'@filename' => $filename,
]
);
return $state;
}
$subdivisions = json_decode(file_get_contents($filename));
$subdivisions = get_object_vars($subdivisions->subdivisions);
// First, check if we already have the state/region code.
$subdivision_keys = array_map('strtolower', array_keys($subdivisions));
if (in_array($state_lowercase, $subdivision_keys)) {
return $state;
}
// Otherwise, check for a name match.
foreach ($subdivisions as $code => $subdivision) {
$has_name = property_exists($subdivision, 'name');
if ($has_name && strtolower($subdivision->name) === $state_lowercase) {
return $code;
}
}
return $state;
}
}
