diff --git a/src/Entity/Payment.php b/src/Entity/Payment.php index bddb36e..9aaadd5 100644 --- a/src/Entity/Payment.php +++ b/src/Entity/Payment.php @@ -7,7 +7,6 @@ namespace Drupal\payment\Entity; -use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface; use Drupal\Core\Entity\ContentEntityBase; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityTypeInterface; @@ -61,54 +60,6 @@ use Drupal\user\UserInterface; class Payment extends ContentEntityBase implements PaymentInterface { /** - * The payment method. - * - * @var \Drupal\payment\Plugin\Payment\Method\PaymentMethodInterface - */ - protected $method; - - /** - * The payment type. - * - * @var \Drupal\payment\Plugin\Payment\Type\PaymentTypeInterface - */ - protected $type; - - /** - * Line items. - * - * @var \Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemInterface[] - * Keys are line item machine names. - */ - protected $lineItems = []; - - /** - * Payment statuses. - * - * @var array - * Values are \Drupal\payment\Plugin\Payment\Status\PaymentStatusInterface - * objects. - */ - protected $statuses = []; - - /** - * {@inheritdoc} - */ - public function __construct(array $values, $entity_type, $bundle = FALSE, $translations = []) { - parent::__construct($values, $entity_type, $bundle, $translations); - $payment_type_manager = PaymentServiceWrapper::typeManager(); - if ($payment_type_manager instanceof CachedDiscoveryInterface) { - $payment_type_manager->clearCachedDefinitions(); - } - // When a payment is newly created, its bundle is set, but there is no - // plugin yet. - if (!isset($values['type'])) { - $this->type = PaymentServiceWrapper::typeManager()->createInstance($this->bundle()); - } - $this->type->setPayment($this); - } - - /** * {@inheritdoc} */ public function getChangedTime() { @@ -126,7 +77,10 @@ class Payment extends ContentEntityBase implements PaymentInterface { * {@inheritdoc} */ public function getPaymentType() { - return $this->type; + /** @var \Drupal\payment\Plugin\Field\FieldType\PluginBagItemBase $payment_type_item */ + $payment_type_item = $this->get('payment_type')[0]; + + return $payment_type_item->getContainedPluginInstance(); } /** @@ -172,6 +126,11 @@ class Payment extends ContentEntityBase implements PaymentInterface { $line_item->setPayment($this); $this->lineItems[$line_item->getName()] = $line_item; + + $line_items = $this->getLineItems(); + $line_items[] = $line_item; + $this->set('line_items', $line_items); + return $this; } @@ -220,7 +179,7 @@ class Payment extends ContentEntityBase implements PaymentInterface { foreach ($statuses as $status) { $status->setPayment($this); } - $this->statuses = array_values($statuses); + $this->get('payment_statuses')->setValue($statuses, FALSE); return $this; } @@ -265,7 +224,9 @@ class Payment extends ContentEntityBase implements PaymentInterface { */ public function setPaymentMethod(PluginPaymentMethodInterface $payment_method) { $payment_method->setPayment($this); - $this->method = $payment_method; + /** @var \Drupal\payment\Plugin\Field\FieldType\PluginBagItemBase $payment_type_item */ + $payment_type_item = $this->get('payment_method')[0]; + $payment_type_item->setContainedPluginInstance($payment_method); return $this; } @@ -274,7 +235,10 @@ class Payment extends ContentEntityBase implements PaymentInterface { * {@inheritdoc} */ public function getPaymentMethod() { - return $this->method; + /** @var \Drupal\payment\Plugin\Field\FieldType\PluginBagItemBase $payment_type_item */ + $payment_type_item = $this->get('payment_method')[0]; + + return $payment_type_item->getContainedPluginInstance(); } /** @@ -351,39 +315,6 @@ class Payment extends ContentEntityBase implements PaymentInterface { /** * {@inheritdoc} */ - public static function postLoad(EntityStorageInterface $storage, array &$entities) { - /** @var \Drupal\payment\Entity\PaymentInterface[] $entities */ - foreach ($entities as $payment) { - if ($payment->getPaymentMethod()) { - $payment->getPaymentMethod()->setPayment($payment); - } - } - /** @var \Drupal\payment\Entity\Payment\PaymentStorageInterface $storage */ - $storage->loadLineItems($entities); - $storage->loadPaymentStatuses($entities); - } - - /** - * {@inheritdoc} - */ - public function postSave(EntityStorageInterface $storage, $update = TRUE) { - /** @var \Drupal\payment\Entity\Payment\PaymentStorageInterface $storage */ - $storage->saveLineItems($this->getLineItems()); - $storage->savePaymentStatuses($this->getPaymentStatuses()); - } - - /** - * {@inheritdoc} - */ - public static function postDelete(EntityStorageInterface $storage, array $entities) { - /** @var \Drupal\payment\Entity\Payment\PaymentStorageInterface $storage */ - $storage->deleteLineItems(array_keys($entities)); - $storage->deletePaymentStatuses(array_keys($entities)); - } - - /** - * {@inheritdoc} - */ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields['bundle'] = BaseFieldDefinition::create('string') ->setLabel(t('Payment type')) @@ -403,6 +334,16 @@ class Payment extends ContentEntityBase implements PaymentInterface { ->setSettings(array( 'target_type' => 'user', )); + $fields['line_items'] = BaseFieldDefinition::create('payment_line_item') + ->setLabel(t('Line items')) + ->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED); + $fields['payment_method'] = BaseFieldDefinition::create('payment_method') + ->setLabel(t('Payment method')); + $fields['payment_statuses'] = BaseFieldDefinition::create('payment_status') + ->setLabel(t('Payment statuses')) + ->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED); + $fields['payment_type'] = BaseFieldDefinition::create('payment_type') + ->setLabel(t('Payment type')); $fields['uuid'] = BaseFieldDefinition::create('uuid') ->setLabel(t('Universally Unique ID')) ->setReadOnly(TRUE); @@ -410,33 +351,4 @@ class Payment extends ContentEntityBase implements PaymentInterface { return $fields; } - /** - * Clones the instance. - */ - public function __clone() { - parent::__clone(); - // Clone the payment type. - $this->type = clone $this->type; - $this->type->setPayment($this); - - // Clone the payment method. - if ($this->getPaymentMethod()) { - $this->setPaymentMethod(clone $this->getPaymentMethod()); - } - - // Clone the line items. - $cloned_line_items = []; - foreach ($this->getLineItems() as $line_item) { - $cloned_line_items[] = clone $line_item; - } - $this->setLineItems($cloned_line_items); - - // Clone the payment statuses. - $cloned_statuses = []; - foreach ($this->getPaymentStatuses() as $status) { - $cloned_statuses[] = clone $status; - } - $this->setPaymentStatuses($cloned_statuses); - } - } diff --git a/src/Entity/Payment/PaymentStorage.php b/src/Entity/Payment/PaymentStorage.php index 69fefa2..397c186 100644 --- a/src/Entity/Payment/PaymentStorage.php +++ b/src/Entity/Payment/PaymentStorage.php @@ -13,8 +13,6 @@ use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Entity\Sql\SqlContentEntityStorage; -use Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemManagerInterface; -use Drupal\payment\Plugin\Payment\Method\PaymentMethodManagerInterface; use Drupal\payment\Plugin\Payment\Status\PaymentStatusManagerInterface; use Drupal\payment\Plugin\Payment\Type\PaymentTypeManagerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -22,21 +20,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; /** * Handles storage for payment entities. */ -class PaymentStorage extends SqlContentEntityStorage implements PaymentStorageInterface { - - /** - * The payment line item manager. - * - * @var \Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemManagerInterface - */ - protected $paymentLineItemManager; - - /** - * The payment method manager. - * - * @var \Drupal\payment\Plugin\Payment\Method\PaymentMethodManagerInterface - */ - protected $paymentMethodManager; +class PaymentStorage extends SqlContentEntityStorage { /** * The payment status manager. @@ -63,19 +47,13 @@ class PaymentStorage extends SqlContentEntityStorage implements PaymentStorageIn * The entity manager. * @param \Drupal\Core\Cache\CacheBackendInterface $cache * The entity cache. - * @param \Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemManagerInterface $payment_line_item_manager - * The payment line item manager. - * @param \Drupal\payment\Plugin\Payment\Method\PaymentMethodManagerInterface $payment_method_manager - * The payment method manager. * @param \Drupal\payment\Plugin\Payment\Status\PaymentStatusManagerInterface $payment_status_manager * The payment status manager. * @param \Drupal\payment\Plugin\Payment\Type\PaymentTypeManagerInterface $payment_type_manager * The payment type manager. */ - public function __construct(EntityTypeInterface $entity_type, Connection $database, EntityManagerInterface $entity_manager, CacheBackendInterface $cache, PaymentLineItemManagerInterface $payment_line_item_manager, PaymentMethodManagerInterface $payment_method_manager, PaymentStatusManagerInterface $payment_status_manager, PaymentTypeManagerInterface $payment_type_manager) { + public function __construct(EntityTypeInterface $entity_type, Connection $database, EntityManagerInterface $entity_manager, CacheBackendInterface $cache, PaymentStatusManagerInterface $payment_status_manager, PaymentTypeManagerInterface $payment_type_manager) { parent::__construct($entity_type, $database, $entity_manager, $cache); - $this->paymentLineItemManager = $payment_line_item_manager; - $this->paymentMethodManager = $payment_method_manager; $this->paymentStatusManager = $payment_status_manager; $this->paymentTypeManager = $payment_type_manager; } @@ -84,7 +62,7 @@ class PaymentStorage extends SqlContentEntityStorage implements PaymentStorageIn * {@inheritdoc} */ public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { - return new static($entity_type, $container->get('database'), $container->get('entity.manager'), $container->get('cache.entity'), $container->get('plugin.manager.payment.line_item'), $container->get('plugin.manager.payment.method'), $container->get('plugin.manager.payment.status'), $container->get('plugin.manager.payment.type')); + return new static($entity_type, $container->get('database'), $container->get('entity.manager'), $container->get('cache.entity'), $container->get('plugin.manager.payment.status'), $container->get('plugin.manager.payment.type')); } /** @@ -93,6 +71,9 @@ class PaymentStorage extends SqlContentEntityStorage implements PaymentStorageIn public function create(array $values = []) { /** @var \Drupal\payment\Entity\PaymentInterface $payment */ $payment = parent::create($values); + $payment_type = $this->paymentTypeManager->createInstance($values['bundle']); + $payment_type->setPayment($payment); + $payment->get('payment_type')->setValue($payment_type); $status = $this->paymentStatusManager->createInstance('payment_created') ->setCreated(time()); $payment->setPaymentStatus($status); @@ -104,6 +85,7 @@ class PaymentStorage extends SqlContentEntityStorage implements PaymentStorageIn * {@inheritdoc} */ protected function buildQuery($ids, $revision_id = FALSE) { + // @todo What does this code do? $query = $this->database->select('payment', 'payment'); $query->addTag('payment_load_multiple'); $query->fields('payment'); @@ -117,159 +99,20 @@ class PaymentStorage extends SqlContentEntityStorage implements PaymentStorageIn /** * {@inheritdoc} */ - function mapFromStorageRecords(array $records) { - foreach ($records as $id => $record) { - $payment_method = $record->payment_method_id ? $this->paymentMethodManager->createInstance($record->payment_method_id, unserialize($record->payment_method_configuration)) : NULL; - $payment_type = $this->paymentTypeManager->createInstance($record->payment_type_id, unserialize($record->payment_type_configuration)); - $records[$id] = (object) array( - 'currency' => $record->currency, - 'id' => (int) $record->id, - 'owner' => (int) $record->owner, - 'method' => $payment_method, - 'type' => $payment_type, - 'bundle' => $payment_type->getPluginId(), - 'uuid' => $record->uuid, - ); - } - - return parent::mapFromStorageRecords($records); - } - - /** - * {@inheritdoc} - */ protected function mapToStorageRecord(ContentEntityInterface $entity, $table_name = NULL) { /** @var \Drupal\payment\Entity\PaymentInterface $payment */ $payment = $entity; - $record = new \stdClass(); - $record->bundle = $payment->bundle(); - $record->currency = $payment->getCurrencyCode(); - $record->id = $payment->id(); - $record->first_payment_status_id = current($payment->getPaymentStatuses())->getId(); - $record->last_payment_status_id = $payment->getPaymentStatus()->getId(); - $record->owner = $payment->getOwnerId(); - $record->payment_method_configuration = serialize($payment->getPaymentMethod() ? $payment->getPaymentMethod()->getConfiguration() : []); - $record->payment_method_id = $payment->getPaymentMethod() ? $payment->getPaymentMethod()->getPluginId() : NULL; - $record->payment_type_configuration = serialize($payment->getPaymentType()->getConfiguration()); - $record->payment_type_id = $payment->getPaymentType()->getPluginId(); - $record->uuid = $payment->uuid(); - - return $record; - } - - /** - * {@inheritdoc} - */ - public function loadLineItems(array $entities) { - /** @var \Drupal\payment\Entity\PaymentInterface[] $entities */ - $result = $this->database->select('payment_line_item', 'pli') - ->fields('pli', array('payment_id', 'plugin_configuration', 'plugin_id')) - ->condition('payment_id', array_keys($entities)) - ->execute(); - while ($line_item_data = $result->fetchAssoc()) { - /** @var \Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemInterface $line_item */ - $line_item = $this->paymentLineItemManager->createInstance($line_item_data['plugin_id'], unserialize($line_item_data['plugin_configuration'])); - $line_item->setPayment($entities[$line_item_data['payment_id']]); - $entities[$line_item_data['payment_id']]->setLineItem($line_item); - } - } - - /** - * {@inheritdoc} - */ - public function saveLineItems(array $line_items) { - /** @var \Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemInterface[] $line_items */ - if ($line_items) { - $this->deleteLineItems(array(reset($line_items)->getPayment()->id())); - $query = $this->database->insert('payment_line_item') - ->fields(array('amount', 'amount_total', 'currency_code', 'name', 'payment_id', 'plugin_configuration', 'plugin_id', 'quantity')); - foreach ($line_items as $line_item) { - $query->values(array( - 'amount' => $line_item->getAmount(), - 'amount_total' => $line_item->getTotalAmount(), - 'currency_code' => $line_item->getCurrencyCode(), - 'name' => $line_item->getName(), - 'payment_id' => $line_item->getPayment()->id(), - 'plugin_configuration' => serialize($line_item->getConfiguration()), - 'plugin_id' => $line_item->getPluginId(), - 'quantity' => $line_item->getQuantity(), - )); - } - $query->execute(); - } - } - - /** - * {@inheritdoc} - */ - public function deleteLineItems(array $ids) { - $this->database->delete('payment_line_item') - ->condition('payment_id', $ids) - ->execute(); - } - - /** - * {@inheritdoc} - */ - public function loadPaymentStatuses(array $entities) { - /** @var \Drupal\payment\Entity\PaymentInterface[] $entities */ - $result = $this->database->select('payment_status', 'ps') - ->fields('ps') - ->condition('payment_id', array_keys($entities)) - ->orderBy('id', 'ASC') - ->execute(); - $statuses= array_fill_keys(array_keys($entities), []); - while ($status_data = $result->fetchAssoc()) { - $status = $this->paymentStatusManager->createInstance($status_data['plugin_id']); - $status->setCreated((int) $status_data['created']); - $status->setId((int) $status_data['id']); - $status->setPayment($entities[$status_data['payment_id']]); - - $statuses[$status->getPayment()->id()][] = $status; - } - foreach ($entities as $payment) { - $payment->setPaymentStatuses($statuses[$payment->id()]); + $record = parent::mapToStorageRecord($entity, $table_name); + $deltas = []; + foreach ($payment->get('payment_statuses') as $delta => $item) { + $deltas[] = $delta; } - } + $record->first_payment_status_delta = min($deltas); + $record->last_payment_status_delta = max($deltas); + debug($record); - /** - * {@inheritdoc} - */ - public function savePaymentStatuses(array $statuses) { - /** @var \Drupal\payment\Plugin\Payment\Status\PaymentStatusInterface[] $statuses */ - if ($statuses) { - foreach ($statuses as $status) { - // Statuses cannot be edited, so only save the ones without an ID. - if (!$status->getId()) { - $record = array( - 'created' => $status->getCreated(), - 'payment_id' => $status->getPayment()->id(), - 'plugin_id' => $status->getPluginId(), - ); - $id = $this->database->insert('payment_status') - ->fields($record) - ->execute(); - $status->setId($id); - } - } - $this->database->update('payment') - ->condition('id', reset($statuses)->getPayment()->id()) - ->fields(array( - 'first_payment_status_id' => reset($statuses)->getId(), - 'last_payment_status_id' => end($statuses)->getId(), - )) - ->execute(); - } - } - - /** - * {@inheritdoc} - */ - public function deletePaymentStatuses(array $ids) { - $this->database->delete('payment_status') - ->condition('payment_id', $ids) - ->execute(); + return $record; } } diff --git a/src/Entity/Payment/PaymentStorageInterface.php b/src/Entity/Payment/PaymentStorageInterface.php deleted file mode 100644 index 3655ba6..0000000 --- a/src/Entity/Payment/PaymentStorageInterface.php +++ /dev/null @@ -1,71 +0,0 @@ - array( - 'description' => "The {payment_status_item}.id of this payment's first status item.", + 'first_payment_status_delta' => array( + 'description' => "The {payment__payment_statuses}.delta of this payment's first status item.", 'type' => 'int', 'unsigned' => TRUE, 'default' => 0, 'not null' => TRUE, ), - 'last_payment_status_id' => array( - 'description' => "The {payment_status_item}.id of this payment's most recent status item.", + 'last_payment_status_delta' => array( + 'description' => "The {payment__payment_statuses}.delta of this payment's most recent status item.", 'type' => 'int', 'unsigned' => TRUE, 'default' => 0, 'not null' => TRUE, ), - 'payment_method_configuration' => array( - 'type' => 'blob', - 'not null' => TRUE, - 'serialize' => TRUE, - ), - 'payment_method_id' => array( - 'type' => 'varchar', - 'length' => 255, - ), - 'payment_type_configuration' => array( - 'type' => 'blob', - 'not null' => TRUE, - 'serialize' => TRUE, - ), - 'payment_type_id' => array( - 'type' => 'varchar', - 'length' => 255, - ), ); $schema['payment']['foreign keys'] += array( - 'first_payment_status_id' => array( - 'table' => 'payment_status_item', + 'first_payment_status_delta' => array( + 'table' => 'payment__payment_statuses', 'columns' => array( - 'first_payment_status_id' => 'id', + 'first_payment_status_delta' => 'delta', ), ), - 'last_payment_status_id' => array( - 'table' => 'payment_status_item', + 'last_payment_status_delta' => array( + 'table' => 'payment__payment_statuses', 'columns' => array( - 'last_payment_status_id' => 'id', + 'last_payment_status_delta' => 'delta', ), ), 'owner' => array( @@ -83,8 +68,6 @@ class PaymentStorageSchema extends SqlContentEntityStorageSchema { ), ), ); - - return $schema; } } diff --git a/src/Entity/PaymentInterface.php b/src/Entity/PaymentInterface.php index 10fe99f..435b46f 100644 --- a/src/Entity/PaymentInterface.php +++ b/src/Entity/PaymentInterface.php @@ -108,8 +108,7 @@ interface PaymentInterface extends ContentEntityInterface, EntityChangedInterfac /** * Sets/replaces all statuses without notifications. * - * @param array $statuses - * \Drupal\payment\Plugin\Payment\Status\PaymentStatusInterface objects. + * @param \Drupal\payment\Plugin\Payment\Status\PaymentStatusInterface[] $statuses * * @return \Drupal\payment\Entity\PaymentInterface */ diff --git a/src/Plugin/DataType/ArrayData.php b/src/Plugin/DataType/ArrayData.php new file mode 100644 index 0000000..b89033e --- /dev/null +++ b/src/Plugin/DataType/ArrayData.php @@ -0,0 +1,36 @@ +getPluginManager()->hasDefinition($plugin_instance->getPluginId())) { + throw new \Exception(sprintf('Plugin manager %s does not have a definition for plugin %s.', get_class($this->getPluginManager()), $plugin_instance->getPluginId())); + } + if (!$plugin_instance instanceof FieldTypePluginInterface) { + throw new \Exception(sprintf('%s must implement \Drupal\payment\Plugin\Payment\FieldTypePluginInterface if it is to be contained by a field item.', get_class($plugin_instance))); + } + } + + /** * Creates a plugin instance. * * @param string $plugin_id * @param mixed[] $plugin_configuration * * @return \Drupal\Component\Plugin\PluginInspectionInterface - * - * @throws \Exception */ protected function createContainedPluginInstance($plugin_id, array $plugin_configuration = []) { + /** @var \Drupal\payment\Plugin\Payment\FieldTypePluginInterface $plugin_instance */ $plugin_instance = $this->getPluginManager()->createInstance($plugin_id, $plugin_configuration); - if (!$plugin_instance instanceof FieldTypePluginInterface) { - throw new \Exception(sprintf('%s must implement \Drupal\payment\Plugin\Payment\FieldTypePluginInterface if it is to be contained by a field item.', get_class($plugin_instance))); - } + $this->validatePluginInstance($plugin_instance); $plugin_instance->setFieldItem($this); return $plugin_instance; @@ -67,11 +81,7 @@ abstract class PluginBagItemBase extends FieldItemBase { * The plugin or NULL of no plugin ID was configured yet. */ public function getContainedPluginInstance() { - if (!$this->pluginInstance && $this->getContainedPluginId()) { - $this->pluginInstance = $this->createContainedPluginInstance($this->getContainedPluginId(), $this->getContainedPluginConfiguration()); - } - - return $this->pluginInstance; + return $this->get('plugin_instance')->getValue(); } /** @@ -82,11 +92,7 @@ abstract class PluginBagItemBase extends FieldItemBase { * @return $this */ public function setContainedPluginInstance(PluginInspectionInterface $plugin_instance) { - if ($this->pluginInstance) { - $this->pluginInstance->unsetFieldItem(); - } - $this->pluginInstance = $plugin_instance; - $this->setContainedPluginId($plugin_instance->getPluginId()); + $this->get('plugin_instance')->setValue($plugin_instance); return $this; } @@ -97,12 +103,7 @@ abstract class PluginBagItemBase extends FieldItemBase { * @return $this */ public function resetContainedPluginInstance() { - if ($this->pluginInstance) { - $this->pluginInstance->unsetFieldItem(); - } - $this->pluginInstance = NULL; - $this->get('plugin_id')->applyDefaultValue(); - $this->get('plugin_configuration')->setValue(array()); + $this->get('plugin_instance')->applyDefaultValue(); return $this; } @@ -159,9 +160,9 @@ abstract class PluginBagItemBase extends FieldItemBase { * @return $this */ public function _setContainedPluginConfigurationFromContainedPlugin(array $configuration) { - $this->calledFromContainedPlugin = TRUE; + $this->synchronizing = TRUE; $this->setContainedPluginConfiguration($configuration); - $this->calledFromContainedPlugin = FALSE; + $this->synchronizing = FALSE; return $this; } @@ -172,8 +173,10 @@ abstract class PluginBagItemBase extends FieldItemBase { public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) { $properties['plugin_id'] = DataDefinition::create('string') ->setLabel(t('Plugin ID')); - $properties['plugin_configuration'] = MapDataDefinition::create('any') + $properties['plugin_configuration'] = MapDataDefinition::create('payment_array') ->setLabel(t('Plugin configuration')); + $properties['plugin_instance'] = MapDataDefinition::create('any') + ->setLabel(t('Plugin instance')); return $properties; } @@ -183,25 +186,62 @@ abstract class PluginBagItemBase extends FieldItemBase { */ public function onChange($property_name) { if ($property_name == 'plugin_id') { - if ($this->getPluginManager()->hasDefinition($this->getContainedPluginId())) { - $this->pluginInstance = $this->createContainedPluginInstance($this->getContainedPluginId()); + if ($this->get($property_name)->getValue()) { + $plugin_instance = $this->createContainedPluginInstance($this->getContainedPluginId()); + if ($this->previouslyContainedPluginInstance) { + $this->previouslyContainedPluginInstance->unsetFieldItem(); + } + $this->previouslyContainedPluginInstance = $plugin_instance; + $this->get('plugin_instance')->setValue($plugin_instance, FALSE); + if ($plugin_instance instanceof ConfigurablePluginInterface) { + $this->get('plugin_configuration')->setValue($plugin_instance->getConfiguration(), FALSE); + } + else { + $this->get('plugin_configuration')->applyDefaultValue(FALSE); + } + } + else { + $this->get('plugin_instance')->applyDefaultValue(FALSE); + $this->get('plugin_configuration')->applyDefaultValue(FALSE); + } + } + + if ($property_name == 'plugin_configuration' && !$this->synchronizing) { + /** @var \Drupal\Component\Plugin\ConfigurablePluginInterface $plugin_instance */ + $plugin_instance = $this->getContainedPluginInstance(); + if ($plugin_instance instanceof ConfigurablePluginInterface) { + $plugin_instance->setConfiguration($this->get($property_name)->getValue()); } else { - $this->pluginInstance = NULL; + $this->get('plugin_configuration')->applyDefaultValue(FALSE); } - $this->setContainedPluginConfiguration([]); } - if ($property_name == 'plugin_configuration' && !$this->calledFromContainedPlugin && $this->getPluginManager()->hasDefinition($this->getContainedPluginId())) { - $class = $this->getPluginManager()->getDefinition($this->getContainedPluginId())['class']; - if (in_array('Drupal\Component\Plugin\ConfigurablePluginInterface', class_implements($class))) { - /** @var \Drupal\Component\Plugin\ConfigurablePluginInterface $plugin */ - $plugin = $this->pluginInstance; - $plugin->setConfiguration($this->get($property_name)->getValue()); + + if ($property_name == 'plugin_instance') { + if ($this->previouslyContainedPluginInstance) { + $this->previouslyContainedPluginInstance->unsetFieldItem(); + } + $plugin_instance = $this->getContainedPluginInstance(); + $this->previouslyContainedPluginInstance = $plugin_instance; + if ($plugin_instance) { + $plugin_instance->setFieldItem($this); + $this->validatePluginInstance($plugin_instance); + $this->get('plugin_id') + ->setValue($plugin_instance->getPluginId(), FALSE); + if ($plugin_instance instanceof ConfigurablePluginInterface) { + $this->get('plugin_configuration') + ->setValue($plugin_instance->getConfiguration(), FALSE); + } + else { + $this->get('plugin_configuration')->applyDefaultValue(FALSE); + } } else { - $this->writePropertyValue($property_name, []); + $this->get('plugin_id')->applyDefaultValue(FALSE); + $this->get('plugin_configuration')->applyDefaultValue(FALSE); } } + parent::onChange($property_name); } @@ -209,7 +249,7 @@ abstract class PluginBagItemBase extends FieldItemBase { * {@inheritdoc} */ public static function mainPropertyName() { - return NULL; + return 'plugin_instance'; } /** @@ -238,4 +278,32 @@ abstract class PluginBagItemBase extends FieldItemBase { return $schema; } + /** + * {@inheritdoc} + */ + public function isEmpty() { + return !$this->getContainedPluginInstance(); + } + + /** + * {@inheritdoc} + */ + public function setValue($values, $notify = TRUE) { + if (!is_array($values)) { + $this->get('plugin_instance')->setValue($values); + return; + } + parent::setValue($values, $notify); + } + + /** + * {@inheritdoc} + */ + public function __clone() { + $plugin_instance = $this->get('plugin_instance')->getValue(); + if (is_object($plugin_instance)) { + $this->get('plugin_instance')->setValue(clone $plugin_instance, FALSE); + } + } + } diff --git a/src/Plugin/Field/FieldType/PluginBagItemList.php b/src/Plugin/Field/FieldType/PluginBagItemList.php new file mode 100644 index 0000000..1b73d7f --- /dev/null +++ b/src/Plugin/Field/FieldType/PluginBagItemList.php @@ -0,0 +1,28 @@ +list as $delta => $item) { + $cloned_items[$delta] = clone $item; + } + $this->list = $cloned_items; + } + +} diff --git a/src/Plugin/Payment/Method/Unavailable.php b/src/Plugin/Payment/Method/Unavailable.php index 0fcf81e..65caf78 100644 --- a/src/Plugin/Payment/Method/Unavailable.php +++ b/src/Plugin/Payment/Method/Unavailable.php @@ -10,6 +10,8 @@ use Drupal\Component\Plugin\PluginBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Session\AccountInterface; use Drupal\payment\Entity\PaymentInterface; +use Drupal\payment\Plugin\Payment\FieldTypePluginInterface; +use Drupal\payment\Plugin\Payment\FieldTypePluginTrait; /** * A payment method controller that essentially disables payment methods. @@ -25,7 +27,9 @@ use Drupal\payment\Entity\PaymentInterface; * module = "payment" * ) */ -class Unavailable extends PluginBase implements PaymentMethodInterface { +class Unavailable extends PluginBase implements PaymentMethodInterface, FieldTypePluginInterface { + + use FieldTypePluginTrait; /** * The payment this payment method is for. diff --git a/src/Tests/Entity/PaymentUnitTest.php b/src/Tests/Entity/PaymentUnitTest.php index 14718f2..b6dda0b 100644 --- a/src/Tests/Entity/PaymentUnitTest.php +++ b/src/Tests/Entity/PaymentUnitTest.php @@ -69,7 +69,7 @@ class PaymentUnitTest extends KernelTestBase { * Tests getChangedTime(). */ protected function testGetChangedTime() { - $status = $this->statusManager->createInstance('payment_succes'); + $status = $this->statusManager->createInstance('payment_success'); $this->payment->setPaymentStatus($status); $this->assertIdentical($this->payment->getChangedTime(), $status->getCreated()); } diff --git a/src/Tests/Plugin/Field/FieldType/PluginBagItemBaseTest.php b/src/Tests/Plugin/Field/FieldType/PluginBagItemBaseTest.php index 0891756..d07a716 100644 --- a/src/Tests/Plugin/Field/FieldType/PluginBagItemBaseTest.php +++ b/src/Tests/Plugin/Field/FieldType/PluginBagItemBaseTest.php @@ -9,6 +9,7 @@ namespace Drupal\payment\Tests\Plugin\Field\FieldType; use Drupal\Core\Field\BaseFieldDefinition; use Drupal\payment_test\Plugin\PluginTest\MockConfigurablePlugin; +use Drupal\payment_test\Plugin\PluginTest\MockManager; use Drupal\simpletest\KernelTestBase; /** @@ -21,7 +22,7 @@ class PluginBagItemBaseTest extends KernelTestBase { /** * {@inheritdoc} */ - public static $modules = ['payment_test', 'plugin_test']; + public static $modules = ['payment', 'payment_test', 'plugin_test']; /** * The field item under test. @@ -61,12 +62,14 @@ class PluginBagItemBaseTest extends KernelTestBase { $this->assertEqual($this->fieldItem->getContainedPluginId(), $plugin_id); $this->fieldItem->setContainedPluginConfiguration($plugin_configuration); $this->assertEqual($this->fieldItem->getContainedPluginConfiguration(), []); + $this->assertEqual($this->fieldItem->getContainedPluginInstance()->getPluginId(), $plugin_id); // Test setting values and auto-instantiation for a configurable plugin. $this->fieldItem->setContainedPluginId($plugin_id_configurable); $this->assertEqual($this->fieldItem->getContainedPluginId(), $plugin_id_configurable); $this->fieldItem->setContainedPluginConfiguration($plugin_configuration); $this->assertEqual($this->fieldItem->getContainedPluginConfiguration(), $plugin_configuration); + $this->assertEqual($this->fieldItem->getContainedPluginInstance()->getPluginId(), $plugin_id_configurable); /** @var \Drupal\payment_test\Plugin\PluginTest\MockConfigurablePlugin $plugin_instance_a */ $plugin_instance_a = $this->fieldItem->getContainedPluginInstance(); $this->assertTrue($plugin_instance_a instanceof MockConfigurablePlugin); @@ -85,6 +88,7 @@ class PluginBagItemBaseTest extends KernelTestBase { $this->assertNull($this->fieldItem->getContainedPluginInstance()); // Test setting values again and auto-instantiation. + $this->fieldItem->resetContainedPluginInstance(); $this->fieldItem->setContainedPluginId($plugin_id_configurable); $this->assertEqual($this->fieldItem->getContainedPluginId(), $plugin_id_configurable); $this->fieldItem->setContainedPluginConfiguration($plugin_configuration); @@ -109,6 +113,31 @@ class PluginBagItemBaseTest extends KernelTestBase { // any effect on the field item. $plugin_instance_a->setConfiguration($altered_plugin_configuration_a); $this->assertEqual($this->fieldItem->getContainedPluginConfiguration(), $altered_plugin_configuration_b); + + // Test feedback from the plugin back to the field item. + $plugin_manager = new MockManager(); + /** @var \Drupal\payment_test\Plugin\PluginTest\MockConfigurablePlugin $plugin_instance_c */ + $plugin_configuration_c = $plugin_configuration + [ + 'qux' => $this->randomMachineName(), + ]; + $plugin_instance_c = $plugin_manager->createInstance($plugin_id_configurable, $plugin_configuration_c); + $this->fieldItem->setContainedPluginInstance($plugin_instance_c); + $this->assertEqual(spl_object_hash($this->fieldItem->getContainedPluginInstance()), spl_object_hash($plugin_instance_c)); + $this->assertEqual($this->fieldItem->getContainedPluginConfiguration(), $plugin_configuration_c); + $altered_plugin_configuration_c = $plugin_configuration_c + [ + 'foobar' => $this->randomMachineName(), + ]; + $plugin_instance_c->setConfiguration($altered_plugin_configuration_c); + $this->assertEqual($this->fieldItem->getContainedPluginConfiguration(), $altered_plugin_configuration_c); + + // Test setting the main property. + /** @var \Drupal\payment_test\Plugin\PluginTest\MockConfigurablePlugin $plugin_instance_d */ + $plugin_instance_d = $plugin_manager->createInstance($plugin_id_configurable); + $plugin_instance_d->setConfiguration([ + 'oman' => '42', + ]); + $this->fieldItem->setValue($plugin_instance_d); + $this->assertEqual(spl_object_hash($this->fieldItem->getContainedPluginInstance()), spl_object_hash($plugin_instance_d)); } }