commerce_cart.module in Commerce Core 8.2
Same filename and directory in other branches
Implements the shopping cart system and add to cart features.
File
modules/cart/commerce_cart.moduleView source
<?php
/**
* @file
* Implements the shopping cart system and add to cart features.
*/
use Drupal\commerce_cart\CartSessionInterface;
use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\commerce_order\Entity\OrderItemInterface;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\Display\EntityFormDisplayInterface;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Session\AnonymousUserSession;
/**
* Implements hook_cron().
*/
function commerce_cart_cron() {
\Drupal::service('commerce_cart.cron')
->run();
}
/**
* Implements hook_menu_links_discovered_alter().
*/
function commerce_cart_menu_links_discovered_alter(&$links) {
$description = t('Manage fields, Add to Cart forms, other form and display settings for your order items.');
$links['entity.commerce_order_item_type.collection']['description'] = $description;
}
/**
* Implements hook_theme().
*/
function commerce_cart_theme($existing, $type, $theme, $path) {
return [
'commerce_cart_block' => [
'variables' => [
'icon' => NULL,
'count' => NULL,
'count_text' => '',
'content' => NULL,
'url' => NULL,
'links' => [],
],
],
'commerce_cart_empty_page' => [
'render element' => 'element',
],
];
}
/**
* Implements hook_preprocess_views_view().
*
* Moves the commerce_cart_form footer output above the submit buttons.
*/
function commerce_cart_preprocess_views_view(&$variables) {
$view = $variables['view'];
if (strpos($view->storage
->get('tag'), 'commerce_cart_form') !== FALSE) {
$variables['rows']['footer'] = $variables['footer'];
$variables['footer'] = '';
}
}
/**
* Implements hook_entity_base_field_info().
*/
function commerce_cart_entity_base_field_info(EntityTypeInterface $entity_type) {
if ($entity_type
->id() === 'commerce_order') {
$fields['cart'] = BaseFieldDefinition::create('boolean')
->setLabel(t('Cart'))
->setSettings([
'on_label' => t('Yes'),
'off_label' => t('No'),
])
->setDisplayOptions('form', [
'type' => 'boolean_checkbox',
'settings' => [
'display_label' => TRUE,
],
'weight' => 20,
])
->setDisplayConfigurable('form', TRUE)
->setDefaultValue(FALSE);
return $fields;
}
}
/**
* Implements hook_entity_type_build().
*/
function commerce_cart_entity_type_build(array &$entity_types) {
$entity_types['commerce_order_item']
->setFormClass('add_to_cart', '\\Drupal\\commerce_cart\\Form\\AddToCartForm');
}
/**
* Implements hook_user_login().
*/
function commerce_cart_user_login($account) {
// Assign the anonymous user's carts to the logged-in account.
// This will only affect the carts that are in the user's session.
$anonymous = new AnonymousUserSession();
$carts = \Drupal::service('commerce_cart.cart_provider')
->getCarts($anonymous);
\Drupal::service('commerce_order.order_assignment')
->assignMultiple($carts, $account);
}
/**
* Implements hook_ENTITY_TYPE_delete().
*
* Removes deleted carts from the anonymous user's session.
*/
function commerce_cart_commerce_order_delete(OrderInterface $order) {
if (!empty($order->cart->value)) {
\Drupal::service('commerce_cart.cart_session')
->deleteCartId($order
->id());
}
}
/**
* Implements hook_ENTITY_TYPE_access().
*/
function commerce_cart_commerce_order_access(OrderInterface $order, $operation, AccountInterface $account) {
return _commerce_cart_order_access($order, $operation, $account);
}
/**
* Implements hook_ENTITY_TYPE_access().
*/
function commerce_cart_commerce_order_item_access(OrderItemInterface $order_item, $operation, AccountInterface $account) {
$order = $order_item
->getOrder();
return $order ? _commerce_cart_order_access($order, $operation, $account) : AccessResult::neutral();
}
/**
* Checks that the account has access to the cart.
*
* @param \Drupal\commerce_order\Entity\OrderInterface $order
* The cart order.
* @param string $operation
* The operation.
* @param \Drupal\Core\Session\AccountInterface $account
* The account.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result.
*/
function _commerce_cart_order_access(OrderInterface $order, $operation, AccountInterface $account) {
if ($operation !== 'view' && $operation !== 'update') {
return AccessResult::neutral();
}
$customer_id = (int) $order
->getCustomerId();
$order_id = $order
->id();
if ($account
->isAuthenticated()) {
$customer_check = (int) $account
->id() === $customer_id;
}
else {
$cart_session = \Drupal::service('commerce_cart.cart_session');
assert($cart_session instanceof CartSessionInterface);
$active_cart = $cart_session
->hasCartId($order_id, CartSessionInterface::ACTIVE);
$completed_cart = $cart_session
->hasCartId($order_id, CartSessionInterface::COMPLETED);
$customer_check = $active_cart || $completed_cart;
}
$access_result = AccessResult::allowedIf($customer_check);
if ($operation === 'update') {
$access_result = $access_result
->andIf(AccessResult::allowedIf($order
->getState()
->getId() === 'draft'));
}
return $access_result
->addCacheableDependency($order)
->cachePerUser();
}
/**
* Implements hook_form_FORM_ID_alter() for 'entity_form_display_edit_form'.
*
* Hides irrelevant purchased_entity widgets on the add_to_cart order item
* form display.
*/
function commerce_cart_form_entity_form_display_edit_form_alter(array &$form, FormStateInterface $form_state) {
/** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $entity */
$entity = $form_state
->getFormObject()
->getEntity();
if ($form['#entity_type'] == 'commerce_order_item' && $entity
->getMode() == 'add_to_cart') {
$options =& $form['fields']['purchased_entity']['plugin']['type']['#options'];
unset($options['commerce_entity_select']);
unset($options['entity_reference_autocomplete_tags']);
unset($options['entity_reference_autocomplete']);
unset($options['inline_entity_form_complex']);
unset($options['options_buttons']);
unset($options['options_select']);
}
}
/**
* Implements hook_form_BASE_FORM_ID_alter() for 'commerce_order_form'.
*/
function commerce_cart_form_commerce_order_form_alter(array &$form, FormStateInterface $form_state) {
if (isset($form['cart'])) {
/** @var \Drupal\commerce_order\Entity\OrderInterface $order */
$order = $form_state
->getFormObject()
->getEntity();
if ($order
->getState()
->getId() == 'draft') {
// Move the cart element to the bottom of the meta sidebar container.
$form['cart']['#group'] = 'meta';
$form['cart']['#weight'] = 100;
}
else {
// Only draft orders can be carts.
$form['cart']['#type'] = 'hidden';
$form['#default_value'] = FALSE;
}
}
}
/**
* Implements hook_form_BASE_FORM_ID_alter() for 'commerce_order_type_form'.
*/
function commerce_cart_form_commerce_order_type_form_alter(array &$form, FormStateInterface $form_state) {
/** @var \Drupal\commerce_order\Entity\OrderTypeInterface $order_type */
$order_type = $form_state
->getFormObject()
->getEntity();
$cart_form_view = $order_type
->getThirdPartySetting('commerce_cart', 'cart_form_view', 'commerce_cart_form');
$cart_block_view = $order_type
->getThirdPartySetting('commerce_cart', 'cart_block_view', 'commerce_cart_block');
$cart_expiration = $order_type
->getThirdPartySetting('commerce_cart', 'cart_expiration');
$view_storage = \Drupal::entityTypeManager()
->getStorage('view');
$available_form_views = [];
$available_block_views = [];
foreach ($view_storage
->loadMultiple() as $view) {
if (strpos($view
->get('tag'), 'commerce_cart_form') !== FALSE) {
$available_form_views[$view
->id()] = $view
->label();
}
if (strpos($view
->get('tag'), 'commerce_cart_block') !== FALSE) {
$available_block_views[$view
->id()] = $view
->label();
}
}
$form['commerce_cart'] = [
'#type' => 'details',
'#title' => t('Shopping cart settings'),
'#weight' => 5,
'#open' => TRUE,
'#attached' => [
'library' => [
'commerce_cart/admin',
],
],
];
$form['commerce_cart']['cart_form_view'] = [
'#type' => 'select',
'#title' => t('Shopping cart form view'),
'#options' => $available_form_views,
'#default_value' => $cart_form_view,
];
$form['commerce_cart']['cart_block_view'] = [
'#type' => 'select',
'#title' => t('Shopping cart block view'),
'#options' => $available_block_views,
'#default_value' => $cart_block_view,
];
$form['commerce_cart']['cart_expiration_enable'] = [
'#type' => 'checkbox',
'#title' => t('Delete abandoned carts'),
'#default_value' => !empty($cart_expiration['number']),
];
$form['commerce_cart']['cart_expiration'] = [
'#type' => 'container',
'#attributes' => [
'class' => [
'interval',
],
],
'#states' => [
'visible' => [
':input[name="commerce_cart[cart_expiration_enable]"]' => [
'checked' => TRUE,
],
],
],
'#open' => TRUE,
];
$form['commerce_cart']['cart_expiration']['number'] = [
'#type' => 'number',
'#title' => t('Interval'),
'#default_value' => !empty($cart_expiration['number']) ? $cart_expiration['number'] : 30,
'#required' => TRUE,
'#min' => 1,
];
$form['commerce_cart']['cart_expiration']['unit'] = [
'#type' => 'select',
'#title' => t('Unit'),
'#title_display' => 'invisible',
'#default_value' => !empty($cart_expiration['unit']) ? $cart_expiration['unit'] : 'day',
'#options' => [
'minute' => t('Minute'),
'hour' => t('Hour'),
'day' => t('Day'),
'month' => t('Month'),
],
'#required' => TRUE,
];
$form['actions']['submit']['#submit'][] = 'commerce_cart_order_type_form_submit';
}
/**
* Form submission handler for 'commerce_order_type_form'.
*/
function commerce_cart_order_type_form_submit($form, FormStateInterface $form_state) {
/** @var \Drupal\commerce_order\Entity\OrderTypeInterface $order_type */
$order_type = $form_state
->getFormObject()
->getEntity();
$settings =& $form_state
->getValue('commerce_cart');
$order_type
->setThirdPartySetting('commerce_cart', 'cart_form_view', $settings['cart_form_view']);
$order_type
->setThirdPartySetting('commerce_cart', 'cart_block_view', $settings['cart_block_view']);
$cart_expiration = [];
if (!empty($settings['cart_expiration_enable'])) {
$cart_expiration = [
'unit' => $settings['cart_expiration']['unit'],
'number' => $settings['cart_expiration']['number'],
];
}
$order_type
->setThirdPartySetting('commerce_cart', 'cart_expiration', $cart_expiration);
$order_type
->save();
}
/**
* Implements hook_form_BASE_FORM_ID_alter() for 'commerce_order_item_type_form'.
*/
function commerce_cart_form_commerce_order_item_type_form_alter(array &$form, FormStateInterface $form_state) {
$form['actions']['submit']['#submit'][] = 'commerce_cart_order_item_type_form_submit';
}
/**
* Form submission handler for 'commerce_order_item_type_form'.
*/
function commerce_cart_order_item_type_form_submit($form, FormStateInterface $form_state) {
$form_object = $form_state
->getFormObject();
assert($form_object instanceof EntityForm);
if ($form_object
->getOperation() == 'add') {
// Help merchants navigate the admin UI by ensuring the order item type
// has a matching 'add_to_cart' form display.
$storage = \Drupal::entityTypeManager()
->getStorage('entity_form_display');
/** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display */
$form_display = $storage
->create([
'targetEntityType' => 'commerce_order_item',
'bundle' => $form_object
->getEntity()
->id(),
'mode' => 'add_to_cart',
'status' => TRUE,
]);
$form_display
->removeComponent('unit_price');
$form_display
->save();
}
}
/**
* Implements hook_entity_form_display_alter().
*/
function commerce_cart_entity_form_display_alter(EntityFormDisplayInterface $form_display, array $context) {
if ($context['entity_type'] != 'commerce_order_item') {
return;
}
// The "add_to_cart" form mode doesn't have a form display yet.
// Default to hiding the unit_price field.
if ($context['form_mode'] == 'add_to_cart' && $context['form_mode'] != $form_display
->getMode()) {
$form_display
->removeComponent('unit_price');
}
}
/**
* Implements hook_views_data_alter().
*/
function commerce_cart_views_data_alter(array &$data) {
$data['commerce_order_item']['edit_quantity']['field'] = [
'title' => t('Quantity text field'),
'help' => t('Adds a text field for editing the quantity.'),
'id' => 'commerce_order_item_edit_quantity',
];
$data['commerce_order_item']['remove_button']['field'] = [
'title' => t('Remove button'),
'help' => t('Adds a button for removing the order item.'),
'id' => 'commerce_order_item_remove_button',
];
$data['commerce_order']['empty_cart_button'] = [
'title' => t('Empty cart button'),
'help' => t('Adds a button for emptying the cart.'),
'area' => [
'id' => 'commerce_order_empty_cart_button',
],
];
}
/**
* Prepares variables for the cart block element template.
*/
function template_preprocess_commerce_cart_block(&$variables) {
$variables['attributes']['class'][] = 'cart--cart-block';
}