commerce_api-8.x-1.x-dev/src/Plugin/Field/FieldType/OrderProfileItemList.php
src/Plugin/Field/FieldType/OrderProfileItemList.php
<?php
declare(strict_types=1);
namespace Drupal\commerce_api\Plugin\Field\FieldType;
use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\Core\Field\FieldItemList;
use Drupal\Core\TypedData\ComputedItemListTrait;
use Drupal\profile\Entity\Profile;
use Drupal\profile\Entity\ProfileInterface;
final class OrderProfileItemList extends FieldItemList {
use ComputedItemListTrait;
/**
* {@inheritdoc}
*/
protected function computeValue() {
$profile = $this->getProfile();
$value = [
'entity' => $profile,
];
$property_definitions = $this->getDataDefinition()->getPropertyDefinitions();
foreach ($profile->getFieldDefinitions() as $field_name => $field_definition) {
if (!isset($property_definitions[$field_name])) {
continue;
}
if ($profile->get($field_name)->isEmpty()) {
continue;
}
$value[$field_name] = $profile->get($field_name)->first()->getValue();
}
$this->list[0] = $this->createItem(0, $value);
}
/**
* {@inheritdoc}
*/
public function setValue($values, $notify = TRUE) {
$profile = NULL;
// Only set the profile if actual values were passed.
if (is_array($values) && !isset($values['entity'])) {
$values['entity'] = $this->getProfile();
$profile = $values['entity'];
}
parent::setValue($values, $notify);
// Make sure to mark this as computed, overriding the method prevents
// ComputedItemListTrait::setValue from running, which performs this flag.
$this->valueComputed = TRUE;
// Computed values are ignored.
if ($profile && is_array($values)) {
foreach ($values as $property_name => $property_value) {
if ($property_name === 'entity') {
continue;
}
$profile->set($property_name, $property_value);
}
}
$order = $this->getEntity();
assert($order instanceof OrderInterface);
$profile_type = $this->getSetting('profile_type') ?: 'billing';
if ($profile_type === 'billing') {
// Note that we don't call setBillingProfile() here on purpose so we can
// support nullifying the profile.
$order->set('billing_profile', $profile);
}
else {
$order->setData('shipping_profile', $profile);
}
}
/**
* {@inheritdoc}
*/
public function onChange($delta) {
parent::onChange($delta);
// When the field value is set via the magic setter, only the onChange()
// method is invoked but not setValue().
$this->setValue($this->list[$delta]->getValue());
}
/**
* {@inheritdoc}
*/
public function applyDefaultValue($notify = TRUE) {
$this->computeValue();
return $this;
}
/**
* Get the profile for the field.
*
* @return \Drupal\profile\Entity\ProfileInterface
* The profile.
*/
private function getProfile(): ProfileInterface {
$order = $this->getEntity();
assert($order instanceof OrderInterface);
$profile_type = $this->getSetting('profile_type') ?: 'billing';
$collected_profiles = $order->collectProfiles();
$profile = $collected_profiles[$profile_type] ?? NULL;
if ($profile === NULL) {
$profile = Profile::create([
'type' => $this->getSetting('profile_bundle'),
'uid' => 0,
]);
}
return $profile;
}
}
