PriceListItem.php 10.1 KB
Newer Older
Andreas Radloff's avatar
Andreas Radloff committed
1
2
3
4
<?php

namespace Drupal\commerce_pricelist\Entity;

5
use Drupal\commerce\PurchasableEntityInterface;
6
7
use Drupal\commerce_price\Price;
use Drupal\commerce\Entity\CommerceContentEntityBase;
8
use Drupal\Core\Cache\Cache;
9
10
use Drupal\Core\Entity\EntityMalformedException;
use Drupal\Core\Entity\EntityStorageInterface;
Andreas Radloff's avatar
Andreas Radloff committed
11
12
13
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Entity\EntityChangedTrait;
use Drupal\Core\Entity\EntityTypeInterface;
14
use Drupal\user\EntityOwnerTrait;
Andreas Radloff's avatar
Andreas Radloff committed
15
16

/**
17
 * Defines the price list item entity.
Andreas Radloff's avatar
Andreas Radloff committed
18
 *
19
 * Called a "price" in the UI for UX reasons.
Andreas Radloff's avatar
Andreas Radloff committed
20
21
 *
 * @ContentEntityType(
22
 *   id = "commerce_pricelist_item",
Andreas Radloff's avatar
Andreas Radloff committed
23
 *   label = @Translation("Price list item"),
24
25
26
 *   label_collection = @Translation("Prices"),
 *   label_singular = @Translation("price"),
 *   label_plural = @Translation("prices"),
27
 *   label_count = @PluralTranslation(
28
29
 *     singular = "@count price",
 *     plural = "@count prices",
30
 *   ),
Andreas Radloff's avatar
Andreas Radloff committed
31
 *   handlers = {
32
33
 *     "event" = "Drupal\commerce_pricelist\Event\PriceListItemEvent",
 *     "storage" = "Drupal\commerce\CommerceContentEntityStorage",
34
 *     "list_builder" = "Drupal\commerce_pricelist\PriceListItemListBuilder",
Andreas Radloff's avatar
Andreas Radloff committed
35
 *     "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
36
 *     "views_data" = "Drupal\commerce\CommerceEntityViewsData",
Andreas Radloff's avatar
Andreas Radloff committed
37
 *     "form" = {
38
39
 *       "add" = "Drupal\commerce_pricelist\Form\PriceListItemForm",
 *       "edit" = "Drupal\commerce_pricelist\Form\PriceListItemForm",
40
 *       "duplicate" = "Drupal\commerce_pricelist\Form\PriceListItemForm",
41
42
 *       "delete" = "Drupal\commerce_pricelist\Form\PriceListItemDeleteForm",
 *     },
43
44
45
 *     "local_task_provider" = {
 *       "default" = "Drupal\entity\Menu\DefaultEntityLocalTaskProvider",
 *     },
46
47
 *     "route_provider" = {
 *       "default" = "Drupal\commerce_pricelist\PriceListItemRouteProvider",
Andreas Radloff's avatar
Andreas Radloff committed
48
49
 *     },
 *   },
50
51
 *   admin_permission = "administer commerce_pricelist",
 *   base_table = "commerce_pricelist_item",
Andreas Radloff's avatar
Andreas Radloff committed
52
53
 *   entity_keys = {
 *     "id" = "id",
54
 *     "bundle" = "type",
Andreas Radloff's avatar
Andreas Radloff committed
55
 *     "uuid" = "uuid",
56
 *     "status" = "status",
57
58
 *     "owner" = "uid",
 *     "uid" = "uid",
Andreas Radloff's avatar
Andreas Radloff committed
59
 *   },
60
61
62
 *   links = {
 *     "add-form" = "/price-list/{commerce_pricelist}/prices/add",
 *     "edit-form" = "/price-list/{commerce_pricelist}/prices/{commerce_pricelist_item}/edit",
63
 *     "duplicate-form" = "/price-list/{commerce_pricelist}/prices/{commerce_pricelist_item}/duplicate",
64
 *     "delete-form" = "/price-list/{commerce_pricelist}/prices/{commerce_pricelist_item}/delete",
65
66
 *     "export-form" = "/price-list/{commerce_pricelist}/prices/export",
 *     "import-form" = "/price-list/{commerce_pricelist}/prices/import",
67
68
 *     "collection" = "/price-list/{commerce_pricelist}/prices",
 *   },
69
 *   field_ui_base_route = "entity.commerce_pricelist_item.bundle_page"
Andreas Radloff's avatar
Andreas Radloff committed
70
71
 * )
 */
72
class PriceListItem extends CommerceContentEntityBase implements PriceListItemInterface {
73

Andreas Radloff's avatar
Andreas Radloff committed
74
  use EntityChangedTrait;
75
  use EntityOwnerTrait;
76

Andreas Radloff's avatar
Andreas Radloff committed
77
78
79
  /**
   * {@inheritdoc}
   */
80
81
82
83
  protected function urlRouteParameters($rel) {
    $uri_route_parameters = parent::urlRouteParameters($rel);
    $uri_route_parameters['commerce_pricelist'] = $this->getPriceListId();
    return $uri_route_parameters;
84
85
86
87
88
  }

  /**
   * {@inheritdoc}
   */
89
90
91
92
  public function label() {
    if ($this->isNew()) {
      return '';
    }
93
94
    $purchasable_entity = $this->getPurchasableEntity();
    $purchasable_entity_label = $purchasable_entity ? $purchasable_entity->label() : '';
95
96
97
    $currency_formatter = \Drupal::service('commerce_price.currency_formatter');
    $price = $this->getPrice();
    $formatted_price = $currency_formatter->format($price->getNumber(), $price->getCurrencyCode());
98

99
    return sprintf('%s: %s', $purchasable_entity_label, $formatted_price);
100
101
102
103
104
  }

  /**
   * {@inheritdoc}
   */
105
106
  public function getPriceList() {
    return $this->get('price_list_id')->entity;
Andreas Radloff's avatar
Andreas Radloff committed
107
108
109
110
111
  }

  /**
   * {@inheritdoc}
   */
112
113
  public function getPriceListId() {
    return $this->get('price_list_id')->target_id;
Andreas Radloff's avatar
Andreas Radloff committed
114
115
  }

116
117
118
  /**
   * {@inheritdoc}
   */
119
120
  public function getPurchasableEntity() {
    return $this->getTranslatedReferencedEntity('purchasable_entity');
121
122
123
124
125
  }

  /**
   * {@inheritdoc}
   */
126
127
  public function setPurchasableEntity(PurchasableEntityInterface $purchasable_entity) {
    return $this->set('purchasable_entity', $purchasable_entity);
128
129
  }

Andreas Radloff's avatar
Andreas Radloff committed
130
131
132
  /**
   * {@inheritdoc}
   */
133
134
  public function getPurchasableEntityId() {
    return $this->get('purchasable_entity')->target_id;
Andreas Radloff's avatar
Andreas Radloff committed
135
136
137
138
139
  }

  /**
   * {@inheritdoc}
   */
140
141
  public function setPurchasableEntityId($purchasable_entity_id) {
    return $this->set('purchasable_entity', $purchasable_entity_id);
Andreas Radloff's avatar
Andreas Radloff committed
142
143
  }

144
145
146
  /**
   * {@inheritdoc}
   */
147
148
  public function getQuantity() {
    return $this->get('quantity')->value;
149
150
151
152
153
  }

  /**
   * {@inheritdoc}
   */
154
155
  public function setQuantity($quantity) {
    $this->set('quantity', (string) $quantity);
156
157
158
    return $this;
  }

159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
  /**
   * {@inheritdoc}
   */
  public function getListPrice() {
    if (!$this->get('list_price')->isEmpty()) {
      return $this->get('list_price')->first()->toPrice();
    }
  }

  /**
   * {@inheritdoc}
   */
  public function setListPrice(Price $list_price) {
    return $this->set('list_price', $list_price);
  }

Andreas Radloff's avatar
Andreas Radloff committed
175
176
177
  /**
   * {@inheritdoc}
   */
Andreas Radloff's avatar
Andreas Radloff committed
178
  public function getPrice() {
179
180
181
182
183
184
185
186
    if (!$this->get('price')->isEmpty()) {
      return $this->get('price')->first()->toPrice();
    }
  }

  /**
   * {@inheritdoc}
   */
187
188
  public function setPrice(Price $price) {
    return $this->set('price', $price);
189
190
191
192
193
  }

  /**
   * {@inheritdoc}
   */
194
  public function isEnabled() {
Andreas Radloff's avatar
Andreas Radloff committed
195
196
197
198
199
200
    return (bool) $this->getEntityKey('status');
  }

  /**
   * {@inheritdoc}
   */
201
202
  public function setEnabled($enabled) {
    $this->set('status', (bool) $enabled);
Andreas Radloff's avatar
Andreas Radloff committed
203
204
205
    return $this;
  }

206
207
208
209
210
211
212
213
214
215
216
217
  /**
   * {@inheritdoc}
   */
  public function preSave(EntityStorageInterface $storage) {
    parent::preSave($storage);

    $price_list_id = $this->getPriceListId();
    if (empty($price_list_id)) {
      throw new EntityMalformedException(sprintf('Required price list item field "price_list_id" is empty.'));
    }
  }

218
219
220
221
222
223
224
225
226
227
228
229
  /**
   * {@inheritdoc}
   */
  public function postSave(EntityStorageInterface $storage, $update = TRUE) {
    parent::postSave($storage, $update);

    if ($purchasable_entity = $this->getPurchasableEntity()) {
      // Invalidate caches to allow the new pricing to come into effect.
      Cache::invalidateTags($purchasable_entity->getCacheTagsToInvalidate());
    }
  }

Andreas Radloff's avatar
Andreas Radloff committed
230
231
232
233
  /**
   * {@inheritdoc}
   */
  public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
234
    $fields = parent::baseFieldDefinitions($entity_type);
235
236
237
238
239
    $fields += static::ownerBaseFieldDefinitions($entity_type);

    $fields['uid']
      ->setLabel(t('Owner'))
      ->setDescription(t('The user that owns this price list item.'));
240

Andreas Radloff's avatar
Andreas Radloff committed
241
242
    $fields['price_list_id'] = BaseFieldDefinition::create('entity_reference')
      ->setLabel(t('Price list'))
243
244
      ->setDescription(t('The parent price list.'))
      ->setSetting('target_type', 'commerce_pricelist')
245
246
      ->setDisplayConfigurable('form', TRUE)
      ->setRequired(TRUE)
247
      ->setReadOnly(TRUE);
Andreas Radloff's avatar
Andreas Radloff committed
248

249
250
251
    $fields['purchasable_entity'] = BaseFieldDefinition::create('entity_reference')
      ->setLabel(t('Purchasable entity'))
      ->setDescription(t('The purchasable entity.'))
Andreas Radloff's avatar
Andreas Radloff committed
252
      ->setRequired(TRUE)
253
      ->setDisplayConfigurable('form', TRUE)
Andreas Radloff's avatar
Andreas Radloff committed
254
      ->setDisplayOptions('form', [
Andreas Radloff's avatar
Andreas Radloff committed
255
256
257
258
259
260
261
        'type' => 'entity_reference_autocomplete',
        'weight' => -1,
        'settings' => [
          'match_operator' => 'CONTAINS',
          'size' => '60',
          'placeholder' => '',
        ],
262
      ]);
263
264
265
266
267
    // Provide a default target_type for Views, which uses
    // base field definitions without bundle overrides.
    if (\Drupal::moduleHandler()->moduleExists('commerce_product')) {
      $fields['purchasable_entity']->setSetting('target_type', 'commerce_product_variation');
    }
268

269
    $fields['quantity'] = BaseFieldDefinition::create('decimal')
270
      ->setLabel(t('Quantity'))
271
      ->setDescription(t('The quantity tier.'))
272
      ->setRequired(TRUE)
273
274
275
      ->setSetting('unsigned', TRUE)
      ->setSetting('min', 0)
      ->setDefaultValue(1)
276
      ->setDisplayConfigurable('form', TRUE)
277
      ->setDisplayOptions('form', [
278
279
        'type' => 'commerce_quantity',
      ]);
Andreas Radloff's avatar
Andreas Radloff committed
280

281
282
283
284
285
286
287
    $fields['list_price'] = BaseFieldDefinition::create('commerce_price')
      ->setLabel(t('List price'))
      ->setDescription(t('The list price.'))
      ->setDisplayOptions('view', [
        'label' => 'above',
        'type' => 'commerce_price_default',
      ])
288
      ->setDisplayConfigurable('form', TRUE)
289
      ->setDisplayOptions('form', [
290
        'type' => 'commerce_list_price',
291
292
      ]);

Andreas Radloff's avatar
Andreas Radloff committed
293
294
    $fields['price'] = BaseFieldDefinition::create('commerce_price')
      ->setLabel(t('Price'))
295
      ->setDescription(t('The price.'))
296
      ->setRequired(TRUE)
Andreas Radloff's avatar
Andreas Radloff committed
297
298
299
300
      ->setDisplayOptions('view', [
        'label' => 'above',
        'type' => 'commerce_price_default',
      ])
301
      ->setDisplayConfigurable('form', TRUE)
Andreas Radloff's avatar
Andreas Radloff committed
302
303
      ->setDisplayOptions('form', [
        'type' => 'commerce_price_default',
304
      ]);
305

306
    $fields['status'] = BaseFieldDefinition::create('boolean')
307
      ->setLabel(t('Status'))
308
      ->setDescription(t('Whether the price list item is enabled.'))
309
      ->setDefaultValue(TRUE)
310
311
312
313
314
      ->setRequired(TRUE)
      ->setSettings([
        'on_label' => t('Enabled'),
        'off_label' => t('Disabled'),
      ])
315
      ->setDisplayConfigurable('form', TRUE)
316
      ->setDisplayOptions('form', [
317
        'type' => 'options_buttons',
318
      ]);
Andreas Radloff's avatar
Andreas Radloff committed
319
320
321

    $fields['changed'] = BaseFieldDefinition::create('changed')
      ->setLabel(t('Changed'))
322
      ->setDescription(t('The time when the price list item was last edited.'))
323
      ->setTranslatable(TRUE);
Andreas Radloff's avatar
Andreas Radloff committed
324
325
326
327

    return $fields;
  }

328
329
330
331
  /**
   * {@inheritdoc}
   */
  public static function bundleFieldDefinitions(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
332
    $purchasable_entity_type = \Drupal::entityTypeManager()->getDefinition($bundle);
333
    $fields = [];
334
335
336
    $fields['purchasable_entity'] = clone $base_field_definitions['purchasable_entity'];
    $fields['purchasable_entity']->setSetting('target_type', $purchasable_entity_type->id());
    $fields['purchasable_entity']->setLabel($purchasable_entity_type->getLabel());
337
338
339
340

    return $fields;
  }

Andreas Radloff's avatar
Andreas Radloff committed
341
}