WrappedEntityBase.php 6.18 KB
Newer Older
e0ipso's avatar
e0ipso committed
1
2
3
4
5
<?php

namespace Drupal\typed_entity\WrappedEntities;

use Drupal\Core\Entity\EntityInterface;
6
7
use Drupal\Core\Entity\EntityViewBuilderInterface;
use Drupal\Core\Render\RenderableInterface;
e0ipso's avatar
e0ipso committed
8
use Drupal\typed_entity\RepositoryManager;
e0ipso's avatar
e0ipso committed
9
use Symfony\Component\DependencyInjection\ContainerInterface;
e0ipso's avatar
e0ipso committed
10

e0ipso's avatar
e0ipso committed
11
12
/**
 * Base class all wrapped entities should extend from.
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
 *
 * Wrapped entities are useful to organize the business logic around entities.
 * Any custom logic that applies to an entity should live here, not in hooks.
 * This is not limited to logic related to how an entity is rendered. However
 * business logic related to rendering are a very common use case.
 *
 * Wrapped entities can be rendered directly in Twig. Print them normally in
 * your template. Put the wrapped entity in the $variables inside of your pre-
 * processor, then use that variable name in Twig. Ex: {{ wrapped_entity }}. Do
 * not forget to set the view mode first.
 *
 * @code
 *   $wrapped_entity->setViewMode('card_medium');
 *   $variables['wrapped_entity'] = $wrapped_entity;
 * @endcode
 *
 * @code
 *   {# Print render the entity with the configured view mode #}
 *   {{ wrapped_entity }}
 * @endcode
 *
 * In your wrapped entity class you can override ::toRenderable to tweak how the
 * entity is rendered.
 *
 * @code
 *   public function toRenderable() {
 *     $build = parent::toRenderable();
 *     // Customize how the entity is rendered.
 *     return ['foo' => ['#markup' => 'Bar is baz.'], 'entity' => $build];
 *   }
 * @endcode
 *
 * @see https://www.lullabot.com/articles/maintainable-code-drupal-wrapped-entities
e0ipso's avatar
e0ipso committed
46
 */
47
48
49
50
51
52
53
54
55
abstract class WrappedEntityBase implements WrappedEntityInterface, RenderableInterface {

  /**
   * The view mode to render this wrapped entity.
   *
   * @var string
   */
  protected $viewMode = 'default';

56
57
58
59
60
61
62
  /**
   * The entity.
   *
   * @var \Drupal\Core\Entity\EntityInterface
   */
  protected $entity;

63
64
65
66
67
68
  /**
   * The view builder.
   *
   * @var \Drupal\Core\Entity\EntityViewBuilderInterface
   */
  protected $viewBuilder;
e0ipso's avatar
e0ipso committed
69
70

  /**
71
   * The repository manager.
e0ipso's avatar
e0ipso committed
72
   *
73
   * @var \Drupal\typed_entity\RepositoryManager
e0ipso's avatar
e0ipso committed
74
   */
75
  protected $repositoryManager;
e0ipso's avatar
e0ipso committed
76
77
78

  /**
   * WrappedEntityBase constructor.
79
80
81
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity to wrap.
e0ipso's avatar
e0ipso committed
82
   */
83
  public function __construct(EntityInterface $entity) {
e0ipso's avatar
e0ipso committed
84
85
86
    $this->entity = $entity;
  }

e0ipso's avatar
e0ipso committed
87
88
89
90
  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, EntityInterface $entity) {
91
    return new static($entity);
e0ipso's avatar
e0ipso committed
92
93
  }

e0ipso's avatar
e0ipso committed
94
95
96
97
98
99
100
101
102
  /**
   * {@inheritdoc}
   */
  public function getEntity(): EntityInterface {
    assert($this->entity instanceof EntityInterface);
    return $this->entity;
  }

  /**
e0ipso's avatar
e0ipso committed
103
   * {@inheritdoc}
e0ipso's avatar
e0ipso committed
104
105
106
107
108
109
   */
  public function label(): string {
    return $this->getEntity()->label();
  }

  /**
e0ipso's avatar
e0ipso committed
110
   * {@inheritdoc}
e0ipso's avatar
e0ipso committed
111
112
113
114
115
116
   */
  public function owner(): ?WrappedEntityInterface {
    $owner_key = $this->getEntity()->getEntityType()->getKey('owner');
    if (!$owner_key) {
      return NULL;
    }
117
    return $this->wrapReference($owner_key);
e0ipso's avatar
e0ipso committed
118
119
  }

120
121
122
123
124
125
126
127
128
129
130
131
132
133
  /**
   * Sets the view mode for the entity in preparation to render the wrapper.
   *
   * @param string $view_mode
   *   The view mode.
   */
  public function setViewMode(string $view_mode): void {
    $this->viewMode = $view_mode;
  }

  /**
   * {@inheritdoc}
   */
  public function toRenderable(): array {
134
    return $this->viewBuilder()->view($this->getEntity(), $this->viewMode);
135
136
  }

137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
  /**
   * Wraps all the entities referenced by the field name.
   *
   * @param string $field_name
   *   The name of the entity reference field.
   *
   * @return \Drupal\typed_entity\WrappedEntities\WrappedEntityInterface[]
   *   The wrapped referenced entities.
   *
   * @throws \Drupal\typed_entity\InvalidValueException
   */
  public function wrapReferences(string $field_name): array {
    $references = [];
    foreach ($this->getEntity()->{$field_name} as $item) {
      $target_entity = $item->entity;
      if (!$target_entity instanceof EntityInterface) {
        continue;
      }
155
      $references[] = $this->repositoryManager()->wrap($target_entity);
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
    }

    return $references;
  }

  /**
   * Wraps the first entity referenced by the field name.
   *
   * @param string $field_name
   *   The name of the entity reference field.
   *
   * @return \Drupal\typed_entity\WrappedEntities\WrappedEntityInterface
   *   The wrapped referenced entity.
   *
   * @throws \Drupal\typed_entity\InvalidValueException
   */
  public function wrapReference(string $field_name): ?WrappedEntityInterface {
    $target_entity = $this->getEntity()->{$field_name}->entity;
    if (!$target_entity instanceof EntityInterface) {
      return NULL;
    }
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
    return $this->repositoryManager()->wrap($target_entity);
  }

  /**
   * Lazy initialized of the repository manager.
   *
   * @return \Drupal\typed_entity\RepositoryManager
   *   The repository manager.
   */
  protected function repositoryManager(): RepositoryManager {
    if (!$this->repositoryManager) {
      $this->repositoryManager = \Drupal::service(RepositoryManager::class);
    }
    return $this->repositoryManager;
  }

  /**
   * Lazy initialized of the view builder.
   *
   * @return \Drupal\Core\Entity\EntityViewBuilderInterface
   *   The repository manager.
   */
  protected function viewBuilder(): EntityViewBuilderInterface {
    if (!$this->viewBuilder) {
      $entity = $this->getEntity()->getEntityTypeId();
      $entity_type_manager = \Drupal::entityTypeManager();
      $this->viewBuilder = $entity_type_manager->getViewBuilder($entity);
    }
    return $this->viewBuilder;
  }

  /**
   * Sets the view builder.
   *
   * This is mostly here for testing ergonomics.
   *
   * @param \Drupal\Core\Entity\EntityViewBuilderInterface $view_builder
   *   The view builder.
   */
  public function setViewBuilder(EntityViewBuilderInterface $view_builder): void {
    $this->viewBuilder = $view_builder;
  }

  /**
   * Sets the repository manager.
   *
   * This is mostly here for testing ergonomics.
   *
   * @param \Drupal\typed_entity\RepositoryManager $repository_manager
   *   The manager.
   */
  public function setRepositoryManager(RepositoryManager $repository_manager): void {
    $this->repositoryManager = $repository_manager;
230
231
  }

e0ipso's avatar
e0ipso committed
232
}