Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
90.91% covered (success)
90.91%
10 / 11
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
PrimaryEntityReferenceFieldItemList
90.91% covered (success)
90.91%
10 / 11
66.67% covered (warning)
66.67%
2 / 3
6.03
0.00% covered (danger)
0.00%
0 / 1
 __get
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
 preSave
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 primary
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3declare(strict_types=1);
4
5namespace Drupal\primary_entity_reference\Plugin\Field;
6
7use Drupal\Core\Field\EntityReferenceFieldItemList;
8use Drupal\Core\Field\EntityReferenceFieldItemListInterface;
9
10/**
11 * Defines an item list class for entity reference fields.
12 */
13class PrimaryEntityReferenceFieldItemList extends EntityReferenceFieldItemList implements EntityReferenceFieldItemListInterface {
14
15  /**
16   * Magic method to get the primary item.
17   */
18  public function __get($name) {
19    // This enables $item->primary to call $this->primary()
20    if ($name === 'primary') {
21      return $this->primary();
22    }
23
24    // Fallback to parent for other dynamic properties.
25    return parent::__get($name);
26  }
27
28  /**
29   * {@inheritdoc}
30   */
31  public function preSave() {
32    usort($this->list, function ($a, $b) {
33      // Explicit casting ensures consistent integer comparison regardless of
34      // the actual data type, providing defense-in-depth.
35      return (int) $b->get('primary')->getValue() <=> (int) $a->get('primary')->getValue();
36    });
37
38    parent::preSave();
39  }
40
41  /**
42   * Gets the primary item, or the first item if none marked.
43   *
44   * @return \Drupal\Core\Field\FieldItemInterface|null
45   *   The primary item, or NULL if none exist.
46   */
47  public function primary() {
48    foreach ($this->list as $item) {
49      if ($item->get('primary')->getValue()) {
50        return $item;
51      }
52    }
53    // Fallback to first item.
54    return $this->list[0] ?? NULL;
55  }
56
57}