View source
<?php
namespace Drupal\commerce_order\Plugin\Commerce\InlineForm;
use Drupal\commerce\CurrentCountryInterface;
use Drupal\commerce\EntityHelper;
use Drupal\commerce\Plugin\Commerce\InlineForm\EntityInlineFormBase;
use Drupal\commerce_order\AddressBookInterface;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\profile\Entity\ProfileInterface;
use Drupal\user\Entity\User;
use Symfony\Component\DependencyInjection\ContainerInterface;
class CustomerProfile extends EntityInlineFormBase {
protected $addressBook;
protected $currentCountry;
protected $currentUser;
protected $entityTypeManager;
protected $entity;
public function __construct(array $configuration, $plugin_id, $plugin_definition, AddressBookInterface $address_book, CurrentCountryInterface $current_country, AccountInterface $current_user, EntityTypeManagerInterface $entity_type_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->addressBook = $address_book;
$this->currentCountry = $current_country;
$this->currentUser = $current_user;
$this->entityTypeManager = $entity_type_manager;
}
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->get('commerce_order.address_book'), $container
->get('commerce.current_country'), $container
->get('current_user'), $container
->get('entity_type.manager'));
}
public function defaultConfiguration() {
return [
'profile_scope' => '',
'available_countries' => [],
'address_book_uid' => 0,
'copy_on_save' => TRUE,
'admin' => FALSE,
];
}
protected function requiredConfiguration() {
return [
'profile_scope',
];
}
protected function validateConfiguration() {
parent::validateConfiguration();
if (!is_array($this->configuration['available_countries'])) {
throw new \RuntimeException('The available_countries configuration value must be an array.');
}
if (empty($this->configuration['address_book_uid'])) {
$this->configuration['copy_on_save'] = FALSE;
}
}
public function buildInlineForm(array $inline_form, FormStateInterface $form_state) {
$inline_form = parent::buildInlineForm($inline_form, $form_state);
$inline_form['#profile_scope'] = $this->configuration['profile_scope'];
assert($this->entity instanceof ProfileInterface);
$profile_type_id = $this->entity
->bundle();
$allows_multiple = $this->addressBook
->allowsMultiple($profile_type_id);
$customer = $this
->loadUser($this->configuration['address_book_uid']);
$available_countries = $this->configuration['available_countries'];
$address_book_profile = NULL;
if ($customer
->isAuthenticated() && $allows_multiple) {
$address_book_profiles = $this->addressBook
->loadAll($customer, $profile_type_id, $available_countries);
if ($address_book_profiles) {
$user_input = (array) NestedArray::getValue($form_state
->getUserInput(), $inline_form['#parents']);
if (!empty($user_input['select_address'])) {
$address_book_profile = $this
->getProfileForOption($user_input['select_address']);
}
elseif ($this->entity
->isNew()) {
$address_book_profile = $this
->selectDefaultProfile($address_book_profiles);
}
}
$profile_options = $this
->buildOptions($address_book_profiles);
if ($address_book_profile) {
$selected_option = $this
->selectOptionForProfile($address_book_profile);
}
else {
$selected_option = $this->entity
->isNew() ? '_new' : '_original';
if ($selected_option == '_original' && !isset($profile_options['_original'])) {
$selected_option = $this->entity
->getData('address_book_profile_id');
}
}
$inline_form['#after_build'][] = [
get_called_class(),
'clearValues',
];
$inline_form['select_address'] = [
'#type' => 'select',
'#title' => $this
->t('Select an address'),
'#options' => $profile_options,
'#default_value' => $selected_option,
'#access' => !empty($address_book_profiles),
'#ajax' => [
'callback' => [
get_called_class(),
'ajaxRefresh',
],
'wrapper' => $inline_form['#id'],
],
'#attributes' => [
'class' => [
'available-profiles',
],
],
'#weight' => -999,
];
}
elseif ($customer
->isAuthenticated() && $this->entity
->isNew()) {
$address_book_profile = $this->addressBook
->load($customer, $profile_type_id, $available_countries);
}
if ($address_book_profile) {
$this->entity
->populateFromProfile($address_book_profile);
$this->entity
->unsetData('copy_to_address_book');
$this->entity
->unsetData('address_book_profile_id');
if (!$address_book_profile
->isNew()) {
$this->entity
->setData('address_book_profile_id', $address_book_profile
->id());
}
}
if ($this
->shouldRender($inline_form, $form_state)) {
$view_builder = $this->entityTypeManager
->getViewBuilder('profile');
$inline_form['rendered'] = $view_builder
->view($this->entity);
$inline_form['edit_button'] = [
'#type' => 'button',
'#name' => $inline_form['#profile_scope'] . '_edit',
'#value' => $this
->t('Edit'),
'#ajax' => [
'callback' => [
get_called_class(),
'ajaxRefresh',
],
'wrapper' => $inline_form['#id'],
],
'#limit_validation_errors' => [
$inline_form['#parents'],
],
'#attributes' => [
'class' => [
'address-book-edit-button',
],
],
];
}
else {
$address_book_profile_id = $this->entity
->getData('address_book_profile_id');
$profile_storage = $this->entityTypeManager
->getStorage('profile');
if ($address_book_profile_id && !$profile_storage
->load($address_book_profile_id)) {
$this->entity
->unsetData('address_book_profile_id');
}
$form_display = $this
->loadFormDisplay();
$form_display
->buildForm($this->entity, $inline_form, $form_state);
$inline_form = $this
->prepareProfileForm($inline_form, $form_state);
$edit = $address_book_profile ? !$address_book_profile
->isNew() : !$this->entity
->isNew();
$update_on_copy = (bool) $this->entity
->getData('address_book_profile_id');
if ($allows_multiple) {
$default_value = TRUE;
if ($this->configuration['admin'] && !$edit) {
$default_value = FALSE;
}
if ($edit && !$update_on_copy) {
$default_value = FALSE;
}
$visible = !$default_value || !$update_on_copy;
}
else {
$default_value = !$this->configuration['admin'];
$visible = $this->configuration['admin'];
}
$inline_form['copy_to_address_book'] = [
'#type' => 'checkbox',
'#title' => $this
->getCopyLabel($profile_type_id, $update_on_copy),
'#default_value' => (bool) $this->entity
->getData('copy_to_address_book', $default_value),
'#weight' => 999,
'#access' => $customer
->isAuthenticated() && $visible,
];
}
return $inline_form;
}
public static function ajaxRefresh(array &$form, FormStateInterface $form_state) {
$triggering_element = $form_state
->getTriggeringElement();
$inline_form = NestedArray::getValue($form, array_slice($triggering_element['#array_parents'], 0, -1));
return $inline_form;
}
public static function clearValues(array $element, FormStateInterface $form_state) {
$triggering_element_name = static::getTriggeringElementName($element, $form_state);
if ($triggering_element_name != 'select_address') {
return $element;
}
$user_input =& $form_state
->getUserInput();
$inline_form_input = NestedArray::getValue($user_input, $element['#parents']);
$inline_form_input = array_intersect_assoc($inline_form_input, [
'select_address' => $inline_form_input['select_address'],
]);
NestedArray::setValue($user_input, $element['#parents'], $inline_form_input);
return $element;
}
public function validateInlineForm(array &$inline_form, FormStateInterface $form_state) {
parent::validateInlineForm($inline_form, $form_state);
if (!isset($inline_form['rendered'])) {
$form_display = $this
->loadFormDisplay();
$form_display
->extractFormValues($this->entity, $inline_form, $form_state);
$form_display
->validateFormValues($this->entity, $inline_form, $form_state);
}
}
public function submitInlineForm(array &$inline_form, FormStateInterface $form_state) {
parent::submitInlineForm($inline_form, $form_state);
if (!isset($inline_form['rendered'])) {
$form_display = $this
->loadFormDisplay();
$form_display
->extractFormValues($this->entity, $inline_form, $form_state);
$values = $form_state
->getValue($inline_form['#parents']);
if (!empty($values['copy_to_address_book'])) {
$this->entity
->setData('copy_to_address_book', TRUE);
}
else {
$this->entity
->unsetData('copy_to_address_book');
}
}
$this->entity
->save();
if ($this->configuration['copy_on_save'] && $this->addressBook
->needsCopy($this->entity)) {
$customer = $this
->loadUser($this->configuration['address_book_uid']);
$this->addressBook
->copy($this->entity, $customer);
}
}
protected function loadUser($uid) {
$customer = User::getAnonymousUser();
if (!empty($uid)) {
$user_storage = $this->entityTypeManager
->getStorage('user');
$user = $user_storage
->load($uid);
if ($user) {
$customer = $user;
}
}
return $customer;
}
protected function loadFormDisplay() {
$form_mode = $this->configuration['profile_scope'];
$form_display = EntityFormDisplay::collectRenderDisplay($this->entity, $form_mode);
$form_display
->removeComponent('revision_log_message');
return $form_display;
}
protected function shouldRender(array $inline_form, FormStateInterface $form_state) {
$render_parents = array_merge($inline_form['#parents'], [
'render',
]);
$triggering_element_name = static::getTriggeringElementName($inline_form, $form_state);
if ($triggering_element_name == 'select_address') {
$form_state
->set($render_parents, NULL);
}
elseif ($triggering_element_name == 'edit_button') {
$form_state
->set($render_parents, FALSE);
}
$render = $form_state
->get($render_parents);
if (!isset($render)) {
$render = !$this
->isProfileIncomplete($this->entity);
$form_state
->set($render_parents, $render);
}
return $render;
}
protected function prepareProfileForm(array $profile_form, FormStateInterface $form_state) {
if (!empty($profile_form['address']['widget'][0])) {
$address_widget =& $profile_form['address']['widget'][0];
$address_widget['#type'] = 'container';
$available_countries = $this->configuration['available_countries'];
if ($available_countries) {
$address_widget['address']['#available_countries'] = $available_countries;
}
$default_country = $this->currentCountry
->getCountry();
if ($default_country && empty($address_widget['address']['#default_value']['country_code'])) {
$default_country = $default_country
->getCountryCode();
if (!$available_countries || in_array($default_country, $available_countries)) {
$address_widget['address']['#default_value']['country_code'] = $default_country;
}
}
}
return $profile_form;
}
protected function buildOptions(array $address_book_profiles) {
$profile_options = EntityHelper::extractLabels($address_book_profiles);
if (!$this->entity
->isNew()) {
$profile_options['_original'] = $this->entity
->label();
$address_book_profile_id = $this->entity
->getData('address_book_profile_id', 0);
if (isset($address_book_profiles[$address_book_profile_id])) {
$source_address_book_profile = $address_book_profiles[$address_book_profile_id];
if ($source_address_book_profile
->equalToProfile($this->entity)) {
unset($profile_options['_original']);
}
else {
if ($profile_options['_original'] == $source_address_book_profile
->label()) {
$profile_options['_original'] = $this
->t('@profile (current version)', [
'@profile' => $this->entity
->label(),
]);
}
$this->entity
->setData('copy_to_address_book', FALSE);
}
}
}
$profile_options['_new'] = $this
->t('+ Enter a new address');
return $profile_options;
}
protected function selectOptionForProfile(ProfileInterface $address_book_profile) {
if ($address_book_profile
->isNew()) {
$option_id = '_new';
}
else {
$option_id = $address_book_profile
->id();
}
return $option_id;
}
protected function getProfileForOption($option_id) {
$profile_storage = $this->entityTypeManager
->getStorage('profile');
if ($option_id == '_new') {
$address_book_profile = $profile_storage
->create([
'type' => $this->entity
->bundle(),
'uid' => 0,
]);
}
elseif ($option_id == '_original') {
$address_book_profile = NULL;
}
else {
assert(is_numeric($option_id));
$address_book_profile = $profile_storage
->load($option_id);
}
return $address_book_profile;
}
protected function selectDefaultProfile(array $address_book_profiles) {
$default_profile = reset($address_book_profiles);
foreach ($address_book_profiles as $profile) {
if ($profile
->isDefault()) {
$default_profile = $profile;
break;
}
}
return $default_profile;
}
protected function isProfileIncomplete(ProfileInterface $profile) {
$violations = $profile
->validate();
return count($violations) > 0;
}
protected function getCopyLabel($profile_type_id, $update_on_copy) {
$is_owner = FALSE;
if (!$this->configuration['admin']) {
$is_owner = $this->currentUser
->id() == $this->configuration['address_book_uid'];
}
if ($this->addressBook
->allowsMultiple($profile_type_id) && $is_owner) {
if ($update_on_copy) {
$copy_label = $this
->t('Also update the address in my address book.');
}
else {
$copy_label = $this
->t('Save to my address book.');
}
}
else {
if ($update_on_copy) {
$copy_label = $this
->t("Also update the address in the customer's address book.");
}
else {
$copy_label = $this
->t("Save to the customer's address book.");
}
}
return $copy_label;
}
protected static function getTriggeringElementName(array $inline_form, FormStateInterface $form_state) {
$triggering_element_name = '';
$triggering_element = $form_state
->getTriggeringElement();
if ($triggering_element) {
$parents = array_slice($triggering_element['#parents'], 0, count($inline_form['#parents']));
if ($inline_form['#parents'] === $parents) {
$triggering_element_name = end($triggering_element['#parents']);
}
}
return $triggering_element_name;
}
}