View source
<?php
namespace Drupal\commerce_promotion\Plugin\Commerce\PromotionOffer;
use Drupal\commerce\ConditionGroup;
use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\commerce_price\Calculator;
use Drupal\commerce_promotion\Entity\PromotionInterface;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class CombinationOffer extends OrderPromotionOfferBase implements CombinationOfferInterface {
protected $inlineFormManager;
protected $offerManager;
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
$instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
$instance->inlineFormManager = $container
->get('plugin.manager.commerce_inline_form');
$instance->offerManager = $container
->get('plugin.manager.commerce_promotion_offer');
return $instance;
}
public function defaultConfiguration() {
return [
'offers' => [],
] + parent::defaultConfiguration();
}
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form += parent::buildConfigurationForm($form, $form_state);
$form['#type'] = 'container';
$wrapper_id = Html::getUniqueId('combination-offer-ajax-wrapper');
$form['#prefix'] = '<div id="' . $wrapper_id . '">';
$form['#suffix'] = '</div>';
$definitions = array_diff_key($this->offerManager
->getDefinitions(), [
$this->pluginId => '',
]);
$plugins = array_map(static function ($definition) {
return $definition['label'];
}, $definitions);
asort($plugins);
$user_input = (array) NestedArray::getValue($form_state
->getUserInput(), $form['#parents']);
if (!$form_state
->get('offers_form_initialized')) {
$offers = $this->configuration['offers'] ?: [
NULL,
];
if (isset($user_input['offers'])) {
$offers = $user_input['offers'];
}
$form_state
->set('offers', $offers);
$form_state
->set('offers_form_initialized', TRUE);
}
$class = get_class($this);
foreach ($form_state
->get('offers') as $index => $offer) {
if (!empty($user_input['offers'][$index])) {
$offer = $user_input['offers'][$index];
}
$offer_form =& $form['offers'][$index];
$offer_form['configuration'] = [
'#type' => 'fieldset',
'#title' => $this
->t('Offer #@index', [
'@index' => $index + 1,
]),
'#tree' => FALSE,
];
$offer_form['configuration']['target_plugin_id'] = [
'#type' => 'select',
'#title' => $this
->t('Type'),
'#options' => $plugins,
'#default_value' => $offer['target_plugin_id'] ?? '',
'#empty_value' => '',
'#required' => $index === 0,
'#ajax' => [
'callback' => [
$class,
'ajaxCallback',
],
'wrapper' => $wrapper_id,
],
'#parents' => array_merge($form['#parents'], [
'offers',
$index,
'target_plugin_id',
]),
];
if (!empty($offer['target_plugin_id'])) {
$inline_form = $this->inlineFormManager
->createInstance('plugin_configuration', [
'plugin_type' => 'commerce_promotion_offer',
'plugin_id' => $offer['target_plugin_id'],
'plugin_configuration' => $offer['target_plugin_configuration'] ?? [],
]);
$offer_form['configuration']['target_plugin_configuration'] = [
'#inline_form' => $inline_form,
'#parents' => array_merge($form['#parents'], [
'offers',
$index,
'target_plugin_configuration',
]),
];
$offer_form['configuration']['target_plugin_configuration'] = $inline_form
->buildInlineForm($offer_form['configuration']['target_plugin_configuration'], $form_state);
}
if ($index > 0) {
$offer_form['configuration']['remove'] = [
'#type' => 'submit',
'#name' => 'remove_offer' . $index,
'#value' => $this
->t('Remove'),
'#limit_validation_errors' => [],
'#submit' => [
[
$class,
'removeOfferSubmit',
],
],
'#offer_index' => $index,
'#parents' => array_merge($form['#parents'], [
'offers',
$index,
'remove',
]),
'#ajax' => [
'callback' => [
$class,
'ajaxCallback',
],
'wrapper' => $wrapper_id,
],
];
}
}
$form['offers'][] = [
'add_offer' => [
'#type' => 'submit',
'#value' => $this
->t('Add another offer'),
'#submit' => [
[
$class,
'addOfferSubmit',
],
],
'#limit_validation_errors' => [
array_merge($form['#parents'], [
'offers',
]),
],
'#ajax' => [
'callback' => [
$class,
'ajaxCallback',
],
'wrapper' => $wrapper_id,
],
],
];
return $form;
}
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
$values = $form_state
->getValue($form['#parents']);
$values['offers'] = array_filter($values['offers'], function ($offer) {
return !empty($offer['target_plugin_id']) && !empty($offer['target_plugin_configuration']) && !isset($offer['add_offer']);
});
$form_state
->setValue($form['#parents'], $values);
if (empty($values['offers'])) {
$form_state
->setError($form['offers'], $this
->t('Please configure at least one offer.'));
}
}
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::submitConfigurationForm($form, $form_state);
if (!$form_state
->getErrors()) {
$this->configuration['offers'] = [];
$values = $form_state
->getValue($form['#parents']);
foreach (array_filter($values['offers']) as $offer) {
$this->configuration['offers'][] = $offer;
}
}
}
public static function ajaxCallback(array $form, FormStateInterface $form_state) {
$triggering_element = $form_state
->getTriggeringElement();
$parents = $triggering_element['#array_parents'];
$form_index = array_search('form', $parents, TRUE);
$parents = array_splice($parents, 0, $form_index + 1);
return NestedArray::getValue($form, $parents);
}
public static function addOfferSubmit(array $form, FormStateInterface $form_state) {
$offers = $form_state
->get('offers');
$offers[] = [];
$form_state
->set('offers', $offers);
$form_state
->setRebuild();
}
public static function removeOfferSubmit(array $form, FormStateInterface $form_state) {
$offers = $form_state
->get('offers');
$index = $form_state
->getTriggeringElement()['#offer_index'];
unset($offers[$index]);
$form_state
->set('offers', $offers);
$form_state
->setRebuild();
}
public function apply(EntityInterface $entity, PromotionInterface $promotion) {
assert($entity instanceof OrderInterface);
foreach ($this
->getOffers() as $offer) {
if ($offer instanceof OrderItemPromotionOfferInterface) {
$offer_conditions = new ConditionGroup($offer
->getConditions(), $offer
->getConditionOperator());
foreach ($entity
->getItems() as $order_item) {
if (!$order_item
->getUnitPrice() || Calculator::compare($order_item
->getQuantity(), '0') === 0) {
continue;
}
if ($offer_conditions
->evaluate($order_item)) {
$offer
->apply($order_item, $promotion);
}
}
}
else {
$offer
->apply($entity, $promotion);
}
}
}
public function getOffers() {
$offers = [];
foreach ($this->configuration['offers'] as $offer) {
$offers[] = $this->offerManager
->createInstance($offer['target_plugin_id'], $offer['target_plugin_configuration']);
}
return $offers;
}
}