Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 /**
|
Chris@0
|
4 * @file
|
Chris@0
|
5 * Hooks and documentation related to entities.
|
Chris@0
|
6 */
|
Chris@0
|
7
|
Chris@0
|
8 use Drupal\Core\Access\AccessResult;
|
Chris@0
|
9 use Drupal\Core\Entity\ContentEntityInterface;
|
Chris@0
|
10 use Drupal\Core\Entity\DynamicallyFieldableEntityStorageInterface;
|
Chris@0
|
11 use Drupal\Core\Field\BaseFieldDefinition;
|
Chris@18
|
12 use Drupal\Core\Field\FieldDefinition;
|
Chris@0
|
13 use Drupal\Core\Render\Element;
|
Chris@0
|
14 use Drupal\language\Entity\ContentLanguageSettings;
|
Chris@0
|
15 use Drupal\node\Entity\NodeType;
|
Chris@0
|
16
|
Chris@0
|
17 /**
|
Chris@0
|
18 * @defgroup entity_crud Entity CRUD, editing, and view hooks
|
Chris@0
|
19 * @{
|
Chris@0
|
20 * Hooks used in various entity operations.
|
Chris@0
|
21 *
|
Chris@0
|
22 * Entity create, read, update, and delete (CRUD) operations are performed by
|
Chris@0
|
23 * entity storage classes; see the
|
Chris@0
|
24 * @link entity_api Entity API topic @endlink for more information. Most
|
Chris@0
|
25 * entities use or extend the default classes:
|
Chris@0
|
26 * \Drupal\Core\Entity\Sql\SqlContentEntityStorage for content entities, and
|
Chris@0
|
27 * \Drupal\Core\Config\Entity\ConfigEntityStorage for configuration entities.
|
Chris@0
|
28 * For these entities, there is a set of hooks that is invoked for each
|
Chris@0
|
29 * CRUD operation, which module developers can implement to affect these
|
Chris@0
|
30 * operations; these hooks are actually invoked from methods on
|
Chris@0
|
31 * \Drupal\Core\Entity\EntityStorageBase.
|
Chris@0
|
32 *
|
Chris@0
|
33 * For content entities, viewing and rendering are handled by a view builder
|
Chris@0
|
34 * class; see the @link entity_api Entity API topic @endlink for more
|
Chris@0
|
35 * information. Most view builders extend or use the default class
|
Chris@0
|
36 * \Drupal\Core\Entity\EntityViewBuilder.
|
Chris@0
|
37 *
|
Chris@0
|
38 * Entity editing (including adding new entities) is handled by entity form
|
Chris@0
|
39 * classes; see the @link entity_api Entity API topic @endlink for more
|
Chris@0
|
40 * information. Most entity editing forms extend base classes
|
Chris@0
|
41 * \Drupal\Core\Entity\EntityForm or \Drupal\Core\Entity\ContentEntityForm.
|
Chris@0
|
42 * Note that many other operations, such as confirming deletion of entities,
|
Chris@0
|
43 * also use entity form classes.
|
Chris@0
|
44 *
|
Chris@0
|
45 * This topic lists all of the entity CRUD and view operations, and the hooks
|
Chris@0
|
46 * and other operations that are invoked (in order) for each operation. Some
|
Chris@0
|
47 * notes:
|
Chris@0
|
48 * - Whenever an entity hook is invoked, there is both a type-specific entity
|
Chris@0
|
49 * hook, and a generic entity hook. For instance, during a create operation on
|
Chris@0
|
50 * a node, first hook_node_create() and then hook_entity_create() would be
|
Chris@0
|
51 * invoked.
|
Chris@0
|
52 * - The entity-type-specific hooks are represented in the list below as
|
Chris@0
|
53 * hook_ENTITY_TYPE_... (hook_ENTITY_TYPE_create() in this example). To
|
Chris@0
|
54 * implement one of these hooks for an entity whose machine name is "foo",
|
Chris@0
|
55 * define a function called mymodule_foo_create(), for instance. Also note
|
Chris@0
|
56 * that the entity or array of entities that are passed into a specific-type
|
Chris@0
|
57 * hook are of the specific entity class, not the generic Entity class, so in
|
Chris@0
|
58 * your implementation, you can make the $entity argument something like $node
|
Chris@0
|
59 * and give it a specific type hint (which should normally be to the specific
|
Chris@0
|
60 * interface, such as \Drupal\Node\NodeInterface for nodes).
|
Chris@0
|
61 * - $storage in the code examples is assumed to be an entity storage
|
Chris@0
|
62 * class. See the @link entity_api Entity API topic @endlink for
|
Chris@0
|
63 * information on how to instantiate the correct storage class for an
|
Chris@0
|
64 * entity type.
|
Chris@0
|
65 * - $view_builder in the code examples is assumed to be an entity view builder
|
Chris@0
|
66 * class. See the @link entity_api Entity API topic @endlink for
|
Chris@0
|
67 * information on how to instantiate the correct view builder class for
|
Chris@0
|
68 * an entity type.
|
Chris@0
|
69 * - During many operations, static methods are called on the entity class,
|
Chris@0
|
70 * which implements \Drupal\Entity\EntityInterface.
|
Chris@0
|
71 *
|
Chris@14
|
72 * @section entities_revisions_translations Entities, revisions and translations
|
Chris@14
|
73 * A content entity can have multiple stored variants: based on its definition,
|
Chris@14
|
74 * it can be revisionable, translatable, or both.
|
Chris@14
|
75 *
|
Chris@14
|
76 * A revisionable entity can keep track of the changes that affect its data. In
|
Chris@14
|
77 * fact all previous revisions of the entity can be stored and made available as
|
Chris@14
|
78 * "historical" information. The "default" revision is the canonical variant of
|
Chris@14
|
79 * the entity, the one that is loaded when no specific revision is requested.
|
Chris@14
|
80 * Only changes to the default revision may be performed without triggering the
|
Chris@14
|
81 * creation of a new revision, in any other case revision data is not supposed
|
Chris@14
|
82 * to change. Aside from historical revisions, there can be "pending" revisions,
|
Chris@14
|
83 * that contain changes that did not make their way into the default revision.
|
Chris@14
|
84 * Typically these revisions contain data that is waiting for some form of
|
Chris@14
|
85 * approval, before being accepted as canonical.
|
Chris@14
|
86 * @see \Drupal\Core\Entity\RevisionableInterface
|
Chris@14
|
87 * @see \Drupal\Core\Entity\RevisionableStorageInterface
|
Chris@14
|
88 *
|
Chris@14
|
89 * A translatable entity can contain multiple translations of the same content.
|
Chris@14
|
90 * Content entity data is stored via fields, and each field can have one version
|
Chris@14
|
91 * for each enabled language. Some fields may be defined as untranslatable,
|
Chris@14
|
92 * which means that their values are shared among all translations. The
|
Chris@14
|
93 * "default" translation is the canonical variant of the entity, the one whose
|
Chris@14
|
94 * content will be accessible in the entity field data. Other translations
|
Chris@14
|
95 * can be instantiated from the default one. Every translation has an "active
|
Chris@14
|
96 * language" that is used to determine which field translation values should be
|
Chris@14
|
97 * handled. Typically the default translation's active language is the language
|
Chris@14
|
98 * of the content that was originally entered and served as source for the other
|
Chris@14
|
99 * translations.
|
Chris@14
|
100 * @see \Drupal\Core\Entity\TranslatableInterface
|
Chris@14
|
101 * @see \Drupal\Core\Entity\TranslatableStorageInterface
|
Chris@14
|
102 *
|
Chris@14
|
103 * An entity that is both revisionable and translatable has all the features
|
Chris@14
|
104 * described above: every revision can contain one or more translations. The
|
Chris@14
|
105 * canonical variant of the entity is the default translation of the default
|
Chris@14
|
106 * revision. Any revision will be initially loaded as the default translation,
|
Chris@14
|
107 * the other revision translations can be instantiated from this one. If a
|
Chris@14
|
108 * translation has changes in a certain revision, the translation is considered
|
Chris@14
|
109 * "affected" by that revision, and will be flagged as such via the
|
Chris@14
|
110 * "revision_translation_affected" field. With the built-in UI, every time a new
|
Chris@14
|
111 * revision is saved, the changes for the edited translations will be stored,
|
Chris@14
|
112 * while all field values for the other translations will be copied as-is.
|
Chris@14
|
113 * However, if multiple translations of the default revision are being
|
Chris@14
|
114 * subsequently modified without creating a new revision when saving, they will
|
Chris@14
|
115 * all be affected by the default revision. Additionally, all revision
|
Chris@14
|
116 * translations will be affected when saving a revision containing changes for
|
Chris@14
|
117 * untranslatable fields. On the other hand, pending revisions are not supposed
|
Chris@14
|
118 * to contain multiple affected translations, even when they are being
|
Chris@14
|
119 * manipulated via the API.
|
Chris@14
|
120 * @see \Drupal\Core\Entity\TranslatableRevisionableInterface
|
Chris@14
|
121 * @see \Drupal\Core\Entity\TranslatableRevisionableStorageInterface
|
Chris@14
|
122 *
|
Chris@0
|
123 * @section create Create operations
|
Chris@0
|
124 * To create an entity:
|
Chris@0
|
125 * @code
|
Chris@0
|
126 * $entity = $storage->create();
|
Chris@0
|
127 *
|
Chris@0
|
128 * // Add code here to set properties on the entity.
|
Chris@0
|
129 *
|
Chris@0
|
130 * // Until you call save(), the entity is just in memory.
|
Chris@0
|
131 * $entity->save();
|
Chris@0
|
132 * @endcode
|
Chris@0
|
133 * There is also a shortcut method on entity classes, which creates an entity
|
Chris@0
|
134 * with an array of provided property values: \Drupal\Core\Entity::create().
|
Chris@0
|
135 *
|
Chris@0
|
136 * Hooks invoked during the create operation:
|
Chris@0
|
137 * - hook_ENTITY_TYPE_create()
|
Chris@0
|
138 * - hook_entity_create()
|
Chris@14
|
139 * - When handling content entities, if a new translation is added to the entity
|
Chris@14
|
140 * object:
|
Chris@14
|
141 * - hook_ENTITY_TYPE_translation_create()
|
Chris@14
|
142 * - hook_entity_translation_create()
|
Chris@0
|
143 *
|
Chris@0
|
144 * See @ref save below for the save portion of the operation.
|
Chris@0
|
145 *
|
Chris@0
|
146 * @section load Read/Load operations
|
Chris@0
|
147 * To load (read) a single entity:
|
Chris@0
|
148 * @code
|
Chris@0
|
149 * $entity = $storage->load($id);
|
Chris@0
|
150 * @endcode
|
Chris@0
|
151 * To load multiple entities:
|
Chris@0
|
152 * @code
|
Chris@0
|
153 * $entities = $storage->loadMultiple($ids);
|
Chris@0
|
154 * @endcode
|
Chris@0
|
155 * Since load() calls loadMultiple(), these are really the same operation.
|
Chris@0
|
156 * Here is the order of hooks and other operations that take place during
|
Chris@0
|
157 * entity loading:
|
Chris@0
|
158 * - Entity is loaded from storage.
|
Chris@0
|
159 * - postLoad() is called on the entity class, passing in all of the loaded
|
Chris@0
|
160 * entities.
|
Chris@0
|
161 * - hook_entity_load()
|
Chris@0
|
162 * - hook_ENTITY_TYPE_load()
|
Chris@0
|
163 *
|
Chris@0
|
164 * When an entity is loaded, normally the default entity revision is loaded.
|
Chris@0
|
165 * It is also possible to load a different revision, for entities that support
|
Chris@0
|
166 * revisions, with this code:
|
Chris@0
|
167 * @code
|
Chris@0
|
168 * $entity = $storage->loadRevision($revision_id);
|
Chris@0
|
169 * @endcode
|
Chris@0
|
170 * This involves the same hooks and operations as regular entity loading.
|
Chris@0
|
171 *
|
Chris@14
|
172 * The "latest revision" of an entity is the most recently created one,
|
Chris@14
|
173 * regardless of it being default or pending. If the entity is translatable,
|
Chris@14
|
174 * revision translations are not taken into account either. In other words, any
|
Chris@14
|
175 * time a new revision is created, that becomes the latest revision for the
|
Chris@14
|
176 * entity overall, regardless of the affected translations. To load the latest
|
Chris@14
|
177 * revision of an entity:
|
Chris@14
|
178 * @code
|
Chris@14
|
179 * $revision_id = $storage->getLatestRevisionId($entity_id);
|
Chris@14
|
180 * $entity = $storage->loadRevision($revision_id);
|
Chris@14
|
181 * @endcode
|
Chris@14
|
182 * As usual, if the entity is translatable, this code instantiates into $entity
|
Chris@14
|
183 * the default translation of the revision, even if the latest revision contains
|
Chris@14
|
184 * only changes to a different translation:
|
Chris@14
|
185 * @code
|
Chris@14
|
186 * $is_default = $entity->isDefaultTranslation(); // returns TRUE
|
Chris@14
|
187 * @endcode
|
Chris@0
|
188 *
|
Chris@14
|
189 * The "latest translation-affected revision" is the most recently created one
|
Chris@14
|
190 * that affects the specified translation. For example, when a new revision
|
Chris@14
|
191 * introducing some changes to an English translation is saved, that becomes the
|
Chris@14
|
192 * new "latest revision". However, if an existing Italian translation was not
|
Chris@14
|
193 * affected by those changes, then the "latest translation-affected revision"
|
Chris@14
|
194 * for Italian remains what it was. To load the Italian translation at its
|
Chris@14
|
195 * latest translation-affected revision:
|
Chris@14
|
196 * @code
|
Chris@14
|
197 * $revision_id = $storage->getLatestTranslationAffectedRevisionId($entity_id, 'it');
|
Chris@14
|
198 * $it_translation = $storage->loadRevision($revision_id)->getTranslation('it');
|
Chris@14
|
199 * @endcode
|
Chris@0
|
200 *
|
Chris@0
|
201 * @section save Save operations
|
Chris@0
|
202 * To update an existing entity, you will need to load it, change properties,
|
Chris@0
|
203 * and then save; as described above, when creating a new entity, you will also
|
Chris@0
|
204 * need to save it. Here is the order of hooks and other events that happen
|
Chris@0
|
205 * during an entity save:
|
Chris@0
|
206 * - preSave() is called on the entity object, and field objects.
|
Chris@0
|
207 * - hook_ENTITY_TYPE_presave()
|
Chris@0
|
208 * - hook_entity_presave()
|
Chris@0
|
209 * - Entity is saved to storage.
|
Chris@0
|
210 * - For updates on content entities, if there is a translation added that
|
Chris@0
|
211 * was not previously present:
|
Chris@0
|
212 * - hook_ENTITY_TYPE_translation_insert()
|
Chris@0
|
213 * - hook_entity_translation_insert()
|
Chris@0
|
214 * - For updates on content entities, if there was a translation removed:
|
Chris@0
|
215 * - hook_ENTITY_TYPE_translation_delete()
|
Chris@0
|
216 * - hook_entity_translation_delete()
|
Chris@0
|
217 * - postSave() is called on the entity object.
|
Chris@0
|
218 * - hook_ENTITY_TYPE_insert() (new) or hook_ENTITY_TYPE_update() (update)
|
Chris@0
|
219 * - hook_entity_insert() (new) or hook_entity_update() (update)
|
Chris@0
|
220 *
|
Chris@0
|
221 * Some specific entity types invoke hooks during preSave() or postSave()
|
Chris@0
|
222 * operations. Examples:
|
Chris@0
|
223 * - Field configuration preSave(): hook_field_storage_config_update_forbid()
|
Chris@0
|
224 * - Node postSave(): hook_node_access_records() and
|
Chris@0
|
225 * hook_node_access_records_alter()
|
Chris@0
|
226 * - Config entities that are acting as entity bundles in postSave():
|
Chris@0
|
227 * hook_entity_bundle_create()
|
Chris@0
|
228 * - Comment: hook_comment_publish() and hook_comment_unpublish() as
|
Chris@0
|
229 * appropriate.
|
Chris@0
|
230 *
|
Chris@14
|
231 * Note that all translations available for the entity are stored during a save
|
Chris@14
|
232 * operation. When saving a new revision, a copy of every translation is stored,
|
Chris@14
|
233 * regardless of it being affected by the revision.
|
Chris@14
|
234 *
|
Chris@0
|
235 * @section edit Editing operations
|
Chris@0
|
236 * When an entity's add/edit form is used to add or edit an entity, there
|
Chris@0
|
237 * are several hooks that are invoked:
|
Chris@0
|
238 * - hook_entity_prepare_form()
|
Chris@0
|
239 * - hook_ENTITY_TYPE_prepare_form()
|
Chris@0
|
240 * - hook_entity_form_display_alter() (for content entities only)
|
Chris@0
|
241 *
|
Chris@0
|
242 * @section delete Delete operations
|
Chris@0
|
243 * To delete one or more entities, load them and then delete them:
|
Chris@0
|
244 * @code
|
Chris@0
|
245 * $entities = $storage->loadMultiple($ids);
|
Chris@0
|
246 * $storage->delete($entities);
|
Chris@0
|
247 * @endcode
|
Chris@0
|
248 *
|
Chris@0
|
249 * During the delete operation, the following hooks and other events happen:
|
Chris@0
|
250 * - preDelete() is called on the entity class.
|
Chris@0
|
251 * - hook_ENTITY_TYPE_predelete()
|
Chris@0
|
252 * - hook_entity_predelete()
|
Chris@0
|
253 * - Entity and field information is removed from storage.
|
Chris@0
|
254 * - postDelete() is called on the entity class.
|
Chris@0
|
255 * - hook_ENTITY_TYPE_delete()
|
Chris@0
|
256 * - hook_entity_delete()
|
Chris@0
|
257 *
|
Chris@0
|
258 * Some specific entity types invoke hooks during the delete process. Examples:
|
Chris@0
|
259 * - Entity bundle postDelete(): hook_entity_bundle_delete()
|
Chris@0
|
260 *
|
Chris@0
|
261 * Individual revisions of an entity can also be deleted:
|
Chris@0
|
262 * @code
|
Chris@0
|
263 * $storage->deleteRevision($revision_id);
|
Chris@0
|
264 * @endcode
|
Chris@0
|
265 * This operation invokes the following operations and hooks:
|
Chris@0
|
266 * - Revision is loaded (see @ref load above).
|
Chris@0
|
267 * - Revision and field information is removed from the database.
|
Chris@0
|
268 * - hook_ENTITY_TYPE_revision_delete()
|
Chris@0
|
269 * - hook_entity_revision_delete()
|
Chris@0
|
270 *
|
Chris@0
|
271 * @section view View/render operations
|
Chris@0
|
272 * To make a render array for a loaded entity:
|
Chris@0
|
273 * @code
|
Chris@0
|
274 * // You can omit the language ID if the default language is being used.
|
Chris@0
|
275 * $build = $view_builder->view($entity, 'view_mode_name', $language->getId());
|
Chris@0
|
276 * @endcode
|
Chris@0
|
277 * You can also use the viewMultiple() method to view multiple entities.
|
Chris@0
|
278 *
|
Chris@0
|
279 * Hooks invoked during the operation of building a render array:
|
Chris@0
|
280 * - hook_entity_view_mode_alter()
|
Chris@0
|
281 * - hook_ENTITY_TYPE_build_defaults_alter()
|
Chris@0
|
282 * - hook_entity_build_defaults_alter()
|
Chris@0
|
283 *
|
Chris@0
|
284 * View builders for some types override these hooks, notably:
|
Chris@0
|
285 * - The Tour view builder does not invoke any hooks.
|
Chris@0
|
286 * - The Block view builder invokes hook_block_view_alter() and
|
Chris@0
|
287 * hook_block_view_BASE_BLOCK_ID_alter(). Note that in other view builders,
|
Chris@0
|
288 * the view alter hooks are run later in the process.
|
Chris@0
|
289 *
|
Chris@0
|
290 * During the rendering operation, the default entity viewer runs the following
|
Chris@0
|
291 * hooks and operations in the pre-render step:
|
Chris@0
|
292 * - hook_entity_view_display_alter()
|
Chris@0
|
293 * - hook_entity_prepare_view()
|
Chris@0
|
294 * - Entity fields are loaded, and render arrays are built for them using
|
Chris@0
|
295 * their formatters.
|
Chris@0
|
296 * - hook_entity_display_build_alter()
|
Chris@0
|
297 * - hook_ENTITY_TYPE_view()
|
Chris@0
|
298 * - hook_entity_view()
|
Chris@0
|
299 * - hook_ENTITY_TYPE_view_alter()
|
Chris@0
|
300 * - hook_entity_view_alter()
|
Chris@0
|
301 *
|
Chris@0
|
302 * Some specific builders have specific hooks:
|
Chris@0
|
303 * - The Node view builder invokes hook_node_links_alter().
|
Chris@0
|
304 * - The Comment view builder invokes hook_comment_links_alter().
|
Chris@0
|
305 *
|
Chris@0
|
306 * After this point in rendering, the theme system takes over. See the
|
Chris@0
|
307 * @link theme_render Theme system and render API topic @endlink for more
|
Chris@0
|
308 * information.
|
Chris@0
|
309 *
|
Chris@0
|
310 * @section misc Other entity hooks
|
Chris@0
|
311 * Some types of entities invoke hooks for specific operations:
|
Chris@0
|
312 * - Searching nodes:
|
Chris@0
|
313 * - hook_ranking()
|
Chris@0
|
314 * - Query is executed to find matching nodes
|
Chris@0
|
315 * - Resulting node is loaded
|
Chris@0
|
316 * - Node render array is built
|
Chris@0
|
317 * - comment_node_update_index() is called (this adds "N comments" text)
|
Chris@0
|
318 * - hook_node_search_result()
|
Chris@0
|
319 * - Search indexing nodes:
|
Chris@0
|
320 * - Node is loaded
|
Chris@0
|
321 * - Node render array is built
|
Chris@0
|
322 * - hook_node_update_index()
|
Chris@0
|
323 * @}
|
Chris@0
|
324 */
|
Chris@0
|
325
|
Chris@0
|
326 /**
|
Chris@0
|
327 * @defgroup entity_api Entity API
|
Chris@0
|
328 * @{
|
Chris@0
|
329 * Describes how to define and manipulate content and configuration entities.
|
Chris@0
|
330 *
|
Chris@0
|
331 * Entities, in Drupal, are objects that are used for persistent storage of
|
Chris@0
|
332 * content and configuration information. See the
|
Chris@0
|
333 * @link info_types Information types topic @endlink for an overview of the
|
Chris@0
|
334 * different types of information, and the
|
Chris@0
|
335 * @link config_api Configuration API topic @endlink for more about the
|
Chris@0
|
336 * configuration API.
|
Chris@0
|
337 *
|
Chris@0
|
338 * Each entity is an instance of a particular "entity type". Some content entity
|
Chris@0
|
339 * types have sub-types, which are known as "bundles", while for other entity
|
Chris@0
|
340 * types, there is only a single bundle. For example, the Node content entity
|
Chris@0
|
341 * type, which is used for the main content pages in Drupal, has bundles that
|
Chris@0
|
342 * are known as "content types", while the User content type, which is used for
|
Chris@0
|
343 * user accounts, has only one bundle.
|
Chris@0
|
344 *
|
Chris@0
|
345 * The sections below have more information about entities and the Entity API;
|
Chris@0
|
346 * for more detailed information, see
|
Chris@0
|
347 * https://www.drupal.org/developing/api/entity.
|
Chris@0
|
348 *
|
Chris@0
|
349 * @section define Defining an entity type
|
Chris@0
|
350 * Entity types are defined by modules, using Drupal's Plugin API (see the
|
Chris@0
|
351 * @link plugin_api Plugin API topic @endlink for more information about plugins
|
Chris@0
|
352 * in general). Here are the steps to follow to define a new entity type:
|
Chris@0
|
353 * - Choose a unique machine name, or ID, for your entity type. This normally
|
Chris@0
|
354 * starts with (or is the same as) your module's machine name. It should be
|
Chris@0
|
355 * as short as possible, and may not exceed 32 characters.
|
Chris@0
|
356 * - Define an interface for your entity's get/set methods, usually extending
|
Chris@0
|
357 * either \Drupal\Core\Config\Entity\ConfigEntityInterface or
|
Chris@0
|
358 * \Drupal\Core\Entity\ContentEntityInterface.
|
Chris@0
|
359 * - Define a class for your entity, implementing your interface and extending
|
Chris@0
|
360 * either \Drupal\Core\Config\Entity\ConfigEntityBase or
|
Chris@0
|
361 * \Drupal\Core\Entity\ContentEntityBase, with annotation for
|
Chris@0
|
362 * \@ConfigEntityType or \@ContentEntityType in its documentation block.
|
Chris@0
|
363 * If you are defining a content entity type, it is recommended to extend the
|
Chris@0
|
364 * \Drupal\Core\Entity\EditorialContentEntityBase base class in order to get
|
Chris@0
|
365 * out-of-the-box support for Entity API's revisioning and publishing
|
Chris@0
|
366 * features, which will allow your entity type to be used with Drupal's
|
Chris@0
|
367 * editorial workflow provided by the Content Moderation module.
|
Chris@12
|
368 * - In the annotation, the 'id' property gives the entity type ID, and the
|
Chris@12
|
369 * 'label' property gives the human-readable name of the entity type. If you
|
Chris@12
|
370 * are defining a content entity type that uses bundles, the 'bundle_label'
|
Chris@12
|
371 * property gives the human-readable name to use for a bundle of this entity
|
Chris@12
|
372 * type (for example, "Content type" for the Node entity).
|
Chris@0
|
373 * - The annotation will refer to several handler classes, which you will also
|
Chris@0
|
374 * need to define:
|
Chris@0
|
375 * - list_builder: Define a class that extends
|
Chris@0
|
376 * \Drupal\Core\Config\Entity\ConfigEntityListBuilder (for configuration
|
Chris@0
|
377 * entities) or \Drupal\Core\Entity\EntityListBuilder (for content
|
Chris@0
|
378 * entities), to provide an administrative overview for your entities.
|
Chris@0
|
379 * - add and edit forms, or default form: Define a class (or two) that
|
Chris@0
|
380 * extend(s) \Drupal\Core\Entity\EntityForm to provide add and edit forms
|
Chris@0
|
381 * for your entities. For content entities, base class
|
Chris@0
|
382 * \Drupal\Core\Entity\ContentEntityForm is a better starting point.
|
Chris@0
|
383 * - delete form: Define a class that extends
|
Chris@0
|
384 * \Drupal\Core\Entity\EntityConfirmFormBase to provide a delete
|
Chris@0
|
385 * confirmation form for your entities.
|
Chris@0
|
386 * - view_builder: For content entities and config entities that need to be
|
Chris@0
|
387 * viewed, define a class that implements
|
Chris@0
|
388 * \Drupal\Core\Entity\EntityViewBuilderInterface (usually extending
|
Chris@0
|
389 * \Drupal\Core\Entity\EntityViewBuilder), to display a single entity.
|
Chris@0
|
390 * - translation: For translatable content entities (if the 'translatable'
|
Chris@12
|
391 * annotation property has value TRUE), define a class that extends
|
Chris@0
|
392 * \Drupal\content_translation\ContentTranslationHandler, to translate
|
Chris@0
|
393 * the content. Configuration translation is handled automatically by the
|
Chris@0
|
394 * Configuration Translation module, without the need of a handler class.
|
Chris@0
|
395 * - access: If your configuration entity has complex permissions, you might
|
Chris@0
|
396 * need an access control handling, implementing
|
Chris@12
|
397 * \Drupal\Core\Entity\EntityAccessControlHandlerInterface, but most
|
Chris@12
|
398 * entities can just use the 'admin_permission' annotation property
|
Chris@12
|
399 * instead. Note that if you are creating your own access control handler,
|
Chris@12
|
400 * you should override the checkAccess() and checkCreateAccess() methods,
|
Chris@12
|
401 * not access().
|
Chris@0
|
402 * - storage: A class implementing
|
Chris@0
|
403 * \Drupal\Core\Entity\EntityStorageInterface. If not specified, content
|
Chris@0
|
404 * entities will use \Drupal\Core\Entity\Sql\SqlContentEntityStorage, and
|
Chris@0
|
405 * config entities will use \Drupal\Core\Config\Entity\ConfigEntityStorage.
|
Chris@0
|
406 * You can extend one of these classes to provide custom behavior.
|
Chris@0
|
407 * - views_data: A class implementing \Drupal\views\EntityViewsDataInterface
|
Chris@0
|
408 * to provide views data for the entity type. You can autogenerate most of
|
Chris@0
|
409 * the views data by extending \Drupal\views\EntityViewsData.
|
Chris@0
|
410 * - For content entities, the annotation will refer to a number of database
|
Chris@0
|
411 * tables and their fields. These annotation properties, such as 'base_table',
|
Chris@0
|
412 * 'data_table', 'entity_keys', etc., are documented on
|
Chris@0
|
413 * \Drupal\Core\Entity\EntityType.
|
Chris@0
|
414 * - For content entities that are displayed on their own pages, the annotation
|
Chris@0
|
415 * will refer to a 'uri_callback' function, which takes an object of the
|
Chris@0
|
416 * entity interface you have defined as its parameter, and returns routing
|
Chris@0
|
417 * information for the entity page; see node_uri() for an example. You will
|
Chris@0
|
418 * also need to add a corresponding route to your module's routing.yml file;
|
Chris@0
|
419 * see the entity.node.canonical route in node.routing.yml for an example, and see
|
Chris@0
|
420 * @ref sec_routes below for some notes.
|
Chris@0
|
421 * - Optionally, instead of defining routes, routes can be auto generated by
|
Chris@0
|
422 * providing a route handler. See @ref sec_routes. Otherwise, define routes
|
Chris@0
|
423 * and links for the various URLs associated with the entity.
|
Chris@0
|
424 * These go into the 'links' annotation, with the link type as the key, and
|
Chris@0
|
425 * the path of this link template as the value. The corresponding route
|
Chris@0
|
426 * requires the following route name:
|
Chris@0
|
427 * "entity.$entity_type_id.$link_template_type". See @ref sec_routes below for
|
Chris@0
|
428 * some routing notes. Typical link types are:
|
Chris@0
|
429 * - canonical: Default link, either to view (if entities are viewed on their
|
Chris@0
|
430 * own pages) or edit the entity.
|
Chris@0
|
431 * - delete-form: Confirmation form to delete the entity.
|
Chris@0
|
432 * - edit-form: Editing form.
|
Chris@0
|
433 * - Other link types specific to your entity type can also be defined.
|
Chris@12
|
434 * - If your content entity is fieldable, provide the 'field_ui_base_route'
|
Chris@12
|
435 * annotation property, giving the name of the route that the Manage Fields,
|
Chris@12
|
436 * Manage Display, and Manage Form Display pages from the Field UI module
|
Chris@12
|
437 * will be attached to. This is usually the bundle settings edit page, or an
|
Chris@12
|
438 * entity type settings page if there are no bundles.
|
Chris@0
|
439 * - If your content entity has bundles, you will also need to define a second
|
Chris@0
|
440 * plugin to handle the bundles. This plugin is itself a configuration entity
|
Chris@0
|
441 * type, so follow the steps here to define it. The machine name ('id'
|
Chris@12
|
442 * annotation property) of this configuration entity class goes into the
|
Chris@12
|
443 * 'bundle_entity_type' annotation property on the entity type class. For
|
Chris@12
|
444 * example, for the Node entity, the bundle class is
|
Chris@12
|
445 * \Drupal\node\Entity\NodeType, whose machine name is 'node_type'. This is
|
Chris@12
|
446 * the annotation property 'bundle_entity_type' on the
|
Chris@12
|
447 * \Drupal\node\Entity\Node class. Also, the
|
Chris@12
|
448 * bundle config entity type annotation must have a 'bundle_of' property,
|
Chris@0
|
449 * giving the machine name of the entity type it is acting as a bundle for.
|
Chris@0
|
450 * These machine names are considered permanent, they may not be renamed.
|
Chris@12
|
451 * - Additional annotation properties can be seen on entity class examples such
|
Chris@12
|
452 * as \Drupal\node\Entity\Node (content) and \Drupal\user\Entity\Role
|
Chris@12
|
453 * (configuration). These annotation properties are documented on
|
Chris@0
|
454 * \Drupal\Core\Entity\EntityType.
|
Chris@0
|
455 *
|
Chris@0
|
456 * @section sec_routes Entity routes
|
Chris@0
|
457 * Entity routes can be defined in *.routing.yml files, like any other route:
|
Chris@0
|
458 * see the @link routing Routing API @endlink topic for more information.
|
Chris@0
|
459 * Another option for entity routes is to use a route provider class, and
|
Chris@0
|
460 * reference it in the annotations on the entity class: see the end of this
|
Chris@0
|
461 * section for an example.
|
Chris@0
|
462 *
|
Chris@0
|
463 * It's possible to use both a YAML file and a provider class for entity
|
Chris@0
|
464 * routes, at the same time. Avoid duplicating route names between the two:
|
Chris@0
|
465 * if a duplicate route name is found in both locations, the one in the YAML
|
Chris@0
|
466 * file takes precedence; regardless, such duplication can be confusing.
|
Chris@0
|
467 *
|
Chris@0
|
468 * Here's an example YAML route specification, for the block configure form:
|
Chris@0
|
469 * @code
|
Chris@0
|
470 * entity.block.edit_form:
|
Chris@0
|
471 * path: '/admin/structure/block/manage/{block}'
|
Chris@0
|
472 * defaults:
|
Chris@0
|
473 * _entity_form: 'block.default'
|
Chris@0
|
474 * _title: 'Configure block'
|
Chris@0
|
475 * requirements:
|
Chris@0
|
476 * _entity_access: 'block.update'
|
Chris@0
|
477 * @endcode
|
Chris@0
|
478 * Some notes on this example:
|
Chris@0
|
479 * - path: The {block} in the path is a placeholder, which (for an entity) must
|
Chris@0
|
480 * always take the form of {machine_name_of_entity_type}. In the URL, the
|
Chris@0
|
481 * placeholder value will be the ID of an entity item. When the route is used,
|
Chris@0
|
482 * the entity system will load the corresponding entity item and pass it in as
|
Chris@0
|
483 * an object to the controller for the route.
|
Chris@0
|
484 * - defaults: For entity form routes, use _entity_form rather than the generic
|
Chris@0
|
485 * _controller or _form. The value is composed of the entity type machine name
|
Chris@0
|
486 * and a form handler type from the entity annotation (see @ref define above
|
Chris@0
|
487 * more more on handlers and annotation). So, in this example, block.default
|
Chris@0
|
488 * refers to the 'default' form handler on the block entity type, whose
|
Chris@0
|
489 * annotation contains:
|
Chris@0
|
490 * @code
|
Chris@0
|
491 * handlers = {
|
Chris@0
|
492 * "form" = {
|
Chris@0
|
493 * "default" = "Drupal\block\BlockForm",
|
Chris@0
|
494 * @endcode
|
Chris@0
|
495 * If instead of YAML you want to use a route provider class:
|
Chris@0
|
496 * - \Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider provides canonical,
|
Chris@0
|
497 * edit-form, and delete-form routes.
|
Chris@0
|
498 * - \Drupal\Core\Entity\Routing\AdminHtmlRouteProvider provides the same
|
Chris@0
|
499 * routes, set up to use the administrative theme for edit and delete pages.
|
Chris@0
|
500 * - You can also create your own class, extending one of these two classes if
|
Chris@0
|
501 * you only want to modify their behaviour slightly.
|
Chris@0
|
502 *
|
Chris@0
|
503 * To register any route provider class, add lines like the following to your
|
Chris@0
|
504 * entity class annotation:
|
Chris@0
|
505 * @code
|
Chris@0
|
506 * handlers = {
|
Chris@0
|
507 * "route_provider" = {
|
Chris@0
|
508 * "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
|
Chris@0
|
509 * @endcode
|
Chris@0
|
510 *
|
Chris@0
|
511 * @section bundle Defining a content entity bundle
|
Chris@0
|
512 * For entity types that use bundles, such as Node (bundles are content types)
|
Chris@0
|
513 * and Taxonomy (bundles are vocabularies), modules and install profiles can
|
Chris@0
|
514 * define bundles by supplying default configuration in their config/install
|
Chris@0
|
515 * directories. (See the @link config_api Configuration API topic @endlink for
|
Chris@0
|
516 * general information about configuration.)
|
Chris@0
|
517 *
|
Chris@0
|
518 * There are several good examples of this in Drupal Core:
|
Chris@0
|
519 * - The Forum module defines a content type in node.type.forum.yml and a
|
Chris@0
|
520 * vocabulary in taxonomy.vocabulary.forums.yml
|
Chris@0
|
521 * - The Book module defines a content type in node.type.book.yml
|
Chris@0
|
522 * - The Standard install profile defines Page and Article content types in
|
Chris@0
|
523 * node.type.page.yml and node.type.article.yml, a Tags vocabulary in
|
Chris@0
|
524 * taxonomy.vocabulary.tags.yml, and a Node comment type in
|
Chris@0
|
525 * comment.type.comment.yml. This profile's configuration is especially
|
Chris@0
|
526 * instructive, because it also adds several fields to the Article type, and
|
Chris@0
|
527 * it sets up view and form display modes for the node types.
|
Chris@0
|
528 *
|
Chris@0
|
529 * @section load_query Loading, querying, and rendering entities
|
Chris@0
|
530 * To load entities, use the entity storage manager, which is an object
|
Chris@0
|
531 * implementing \Drupal\Core\Entity\EntityStorageInterface that you can
|
Chris@0
|
532 * retrieve with:
|
Chris@0
|
533 * @code
|
Chris@18
|
534 * $storage = \Drupal::entityTypeManager()->getStorage('your_entity_type');
|
Chris@0
|
535 * // Or if you have a $container variable:
|
Chris@18
|
536 * $storage = $container->get('entity_type.manager')->getStorage('your_entity_type');
|
Chris@0
|
537 * @endcode
|
Chris@0
|
538 * Here, 'your_entity_type' is the machine name of your entity type ('id'
|
Chris@12
|
539 * annotation property on the entity class), and note that you should use
|
Chris@12
|
540 * dependency injection to retrieve this object if possible. See the
|
Chris@0
|
541 * @link container Services and Dependency Injection topic @endlink for more
|
Chris@0
|
542 * about how to properly retrieve services.
|
Chris@0
|
543 *
|
Chris@0
|
544 * To query to find entities to load, use an entity query, which is a object
|
Chris@0
|
545 * implementing \Drupal\Core\Entity\Query\QueryInterface that you can retrieve
|
Chris@0
|
546 * with:
|
Chris@0
|
547 * @code
|
Chris@0
|
548 * // Simple query:
|
Chris@0
|
549 * $query = \Drupal::entityQuery('your_entity_type');
|
Chris@0
|
550 * // Or, if you have a $container variable:
|
Chris@0
|
551 * $storage = $container->get('entity_type.manager')->getStorage('your_entity_type');
|
Chris@0
|
552 * $query = $storage->getQuery();
|
Chris@0
|
553 * @endcode
|
Chris@0
|
554 * If you need aggregation, there is an aggregate query available, which
|
Chris@0
|
555 * implements \Drupal\Core\Entity\Query\QueryAggregateInterface:
|
Chris@0
|
556 * @code
|
Chris@0
|
557 * $query \Drupal::entityQueryAggregate('your_entity_type');
|
Chris@0
|
558 * // Or:
|
Chris@0
|
559 * $query = $storage->getAggregateQuery('your_entity_type');
|
Chris@0
|
560 * @endcode
|
Chris@0
|
561 *
|
Chris@0
|
562 * In either case, you can then add conditions to your query, using methods
|
Chris@0
|
563 * like condition(), exists(), etc. on $query; add sorting, pager, and range
|
Chris@0
|
564 * if needed, and execute the query to return a list of entity IDs that match
|
Chris@0
|
565 * the query.
|
Chris@0
|
566 *
|
Chris@0
|
567 * Here is an example, using the core File entity:
|
Chris@0
|
568 * @code
|
Chris@0
|
569 * $fids = Drupal::entityQuery('file')
|
Chris@0
|
570 * ->condition('status', FILE_STATUS_PERMANENT, '<>')
|
Chris@0
|
571 * ->condition('changed', REQUEST_TIME - $age, '<')
|
Chris@0
|
572 * ->range(0, 100)
|
Chris@0
|
573 * ->execute();
|
Chris@0
|
574 * $files = $storage->loadMultiple($fids);
|
Chris@0
|
575 * @endcode
|
Chris@0
|
576 *
|
Chris@0
|
577 * The normal way of viewing entities is by using a route, as described in the
|
Chris@0
|
578 * sections above. If for some reason you need to render an entity in code in a
|
Chris@0
|
579 * particular view mode, you can use an entity view builder, which is an object
|
Chris@0
|
580 * implementing \Drupal\Core\Entity\EntityViewBuilderInterface that you can
|
Chris@0
|
581 * retrieve with:
|
Chris@0
|
582 * @code
|
Chris@0
|
583 * $view_builder = \Drupal::entityManager()->getViewBuilder('your_entity_type');
|
Chris@0
|
584 * // Or if you have a $container variable:
|
Chris@0
|
585 * $view_builder = $container->get('entity.manager')->getViewBuilder('your_entity_type');
|
Chris@0
|
586 * @endcode
|
Chris@0
|
587 * Then, to build and render the entity:
|
Chris@0
|
588 * @code
|
Chris@0
|
589 * // You can omit the language ID, by default the current content language will
|
Chris@0
|
590 * // be used. If no translation is available for the current language, fallback
|
Chris@0
|
591 * // rules will be used.
|
Chris@0
|
592 * $build = $view_builder->view($entity, 'view_mode_name', $language->getId());
|
Chris@0
|
593 * // $build is a render array.
|
Chris@16
|
594 * $rendered = \Drupal::service('renderer')->render($build);
|
Chris@0
|
595 * @endcode
|
Chris@0
|
596 *
|
Chris@0
|
597 * @section sec_access Access checking on entities
|
Chris@0
|
598 * Entity types define their access permission scheme in their annotation.
|
Chris@0
|
599 * Access permissions can be quite complex, so you should not assume any
|
Chris@0
|
600 * particular permission scheme. Instead, once you have an entity object
|
Chris@0
|
601 * loaded, you can check for permission for a particular operation (such as
|
Chris@0
|
602 * 'view') at the entity or field level by calling:
|
Chris@0
|
603 * @code
|
Chris@0
|
604 * $entity->access($operation);
|
Chris@0
|
605 * $entity->nameOfField->access($operation);
|
Chris@0
|
606 * @endcode
|
Chris@0
|
607 * The interface related to access checking in entities and fields is
|
Chris@0
|
608 * \Drupal\Core\Access\AccessibleInterface.
|
Chris@0
|
609 *
|
Chris@0
|
610 * The default entity access control handler invokes two hooks while checking
|
Chris@0
|
611 * access on a single entity: hook_entity_access() is invoked first, and
|
Chris@0
|
612 * then hook_ENTITY_TYPE_access() (where ENTITY_TYPE is the machine name
|
Chris@0
|
613 * of the entity type). If no module returns a TRUE or FALSE value from
|
Chris@0
|
614 * either of these hooks, then the entity's default access checking takes
|
Chris@0
|
615 * place. For create operations (creating a new entity), the hooks that
|
Chris@0
|
616 * are invoked are hook_entity_create_access() and
|
Chris@0
|
617 * hook_ENTITY_TYPE_create_access() instead.
|
Chris@0
|
618 *
|
Chris@0
|
619 * The Node entity type has a complex system for determining access, which
|
Chris@0
|
620 * developers can interact with. This is described in the
|
Chris@0
|
621 * @link node_access Node access topic. @endlink
|
Chris@0
|
622 *
|
Chris@0
|
623 * @see i18n
|
Chris@0
|
624 * @see entity_crud
|
Chris@18
|
625 * @see \Drupal\Core\Entity\EntityRepositoryInterface::getTranslationFromContext()
|
Chris@0
|
626 * @}
|
Chris@0
|
627 */
|
Chris@0
|
628
|
Chris@0
|
629 /**
|
Chris@0
|
630 * @addtogroup hooks
|
Chris@0
|
631 * @{
|
Chris@0
|
632 */
|
Chris@0
|
633
|
Chris@0
|
634 /**
|
Chris@0
|
635 * Control entity operation access.
|
Chris@0
|
636 *
|
Chris@0
|
637 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
638 * The entity to check access to.
|
Chris@0
|
639 * @param string $operation
|
Chris@0
|
640 * The operation that is to be performed on $entity.
|
Chris@0
|
641 * @param \Drupal\Core\Session\AccountInterface $account
|
Chris@0
|
642 * The account trying to access the entity.
|
Chris@0
|
643 *
|
Chris@0
|
644 * @return \Drupal\Core\Access\AccessResultInterface
|
Chris@0
|
645 * The access result. The final result is calculated by using
|
Chris@0
|
646 * \Drupal\Core\Access\AccessResultInterface::orIf() on the result of every
|
Chris@0
|
647 * hook_entity_access() and hook_ENTITY_TYPE_access() implementation, and the
|
Chris@0
|
648 * result of the entity-specific checkAccess() method in the entity access
|
Chris@0
|
649 * control handler. Be careful when writing generalized access checks shared
|
Chris@0
|
650 * between routing and entity checks: routing uses the andIf() operator. So
|
Chris@0
|
651 * returning an isNeutral() does not determine entity access at all but it
|
Chris@0
|
652 * always ends up denying access while routing.
|
Chris@0
|
653 *
|
Chris@0
|
654 * @see \Drupal\Core\Entity\EntityAccessControlHandler
|
Chris@0
|
655 * @see hook_entity_create_access()
|
Chris@0
|
656 * @see hook_ENTITY_TYPE_access()
|
Chris@0
|
657 *
|
Chris@0
|
658 * @ingroup entity_api
|
Chris@0
|
659 */
|
Chris@0
|
660 function hook_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account) {
|
Chris@0
|
661 // No opinion.
|
Chris@0
|
662 return AccessResult::neutral();
|
Chris@0
|
663 }
|
Chris@0
|
664
|
Chris@0
|
665 /**
|
Chris@0
|
666 * Control entity operation access for a specific entity type.
|
Chris@0
|
667 *
|
Chris@0
|
668 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
669 * The entity to check access to.
|
Chris@0
|
670 * @param string $operation
|
Chris@0
|
671 * The operation that is to be performed on $entity.
|
Chris@0
|
672 * @param \Drupal\Core\Session\AccountInterface $account
|
Chris@0
|
673 * The account trying to access the entity.
|
Chris@0
|
674 *
|
Chris@0
|
675 * @return \Drupal\Core\Access\AccessResultInterface
|
Chris@0
|
676 * The access result. hook_entity_access() has detailed documentation.
|
Chris@0
|
677 *
|
Chris@0
|
678 * @see \Drupal\Core\Entity\EntityAccessControlHandler
|
Chris@0
|
679 * @see hook_ENTITY_TYPE_create_access()
|
Chris@0
|
680 * @see hook_entity_access()
|
Chris@0
|
681 *
|
Chris@0
|
682 * @ingroup entity_api
|
Chris@0
|
683 */
|
Chris@0
|
684 function hook_ENTITY_TYPE_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account) {
|
Chris@0
|
685 // No opinion.
|
Chris@0
|
686 return AccessResult::neutral();
|
Chris@0
|
687 }
|
Chris@0
|
688
|
Chris@0
|
689 /**
|
Chris@0
|
690 * Control entity create access.
|
Chris@0
|
691 *
|
Chris@0
|
692 * @param \Drupal\Core\Session\AccountInterface $account
|
Chris@0
|
693 * The account trying to access the entity.
|
Chris@0
|
694 * @param array $context
|
Chris@0
|
695 * An associative array of additional context values. By default it contains
|
Chris@0
|
696 * language and the entity type ID:
|
Chris@0
|
697 * - entity_type_id - the entity type ID.
|
Chris@0
|
698 * - langcode - the current language code.
|
Chris@0
|
699 * @param string $entity_bundle
|
Chris@0
|
700 * The entity bundle name.
|
Chris@0
|
701 *
|
Chris@0
|
702 * @return \Drupal\Core\Access\AccessResultInterface
|
Chris@0
|
703 * The access result.
|
Chris@0
|
704 *
|
Chris@0
|
705 * @see \Drupal\Core\Entity\EntityAccessControlHandler
|
Chris@0
|
706 * @see hook_entity_access()
|
Chris@0
|
707 * @see hook_ENTITY_TYPE_create_access()
|
Chris@0
|
708 *
|
Chris@0
|
709 * @ingroup entity_api
|
Chris@0
|
710 */
|
Chris@0
|
711 function hook_entity_create_access(\Drupal\Core\Session\AccountInterface $account, array $context, $entity_bundle) {
|
Chris@0
|
712 // No opinion.
|
Chris@0
|
713 return AccessResult::neutral();
|
Chris@0
|
714 }
|
Chris@0
|
715
|
Chris@0
|
716 /**
|
Chris@0
|
717 * Control entity create access for a specific entity type.
|
Chris@0
|
718 *
|
Chris@0
|
719 * @param \Drupal\Core\Session\AccountInterface $account
|
Chris@0
|
720 * The account trying to access the entity.
|
Chris@0
|
721 * @param array $context
|
Chris@0
|
722 * An associative array of additional context values. By default it contains
|
Chris@0
|
723 * language:
|
Chris@0
|
724 * - langcode - the current language code.
|
Chris@0
|
725 * @param string $entity_bundle
|
Chris@0
|
726 * The entity bundle name.
|
Chris@0
|
727 *
|
Chris@0
|
728 * @return \Drupal\Core\Access\AccessResultInterface
|
Chris@0
|
729 * The access result.
|
Chris@0
|
730 *
|
Chris@0
|
731 * @see \Drupal\Core\Entity\EntityAccessControlHandler
|
Chris@0
|
732 * @see hook_ENTITY_TYPE_access()
|
Chris@0
|
733 * @see hook_entity_create_access()
|
Chris@0
|
734 *
|
Chris@0
|
735 * @ingroup entity_api
|
Chris@0
|
736 */
|
Chris@0
|
737 function hook_ENTITY_TYPE_create_access(\Drupal\Core\Session\AccountInterface $account, array $context, $entity_bundle) {
|
Chris@0
|
738 // No opinion.
|
Chris@0
|
739 return AccessResult::neutral();
|
Chris@0
|
740 }
|
Chris@0
|
741
|
Chris@0
|
742 /**
|
Chris@0
|
743 * Add to entity type definitions.
|
Chris@0
|
744 *
|
Chris@0
|
745 * Modules may implement this hook to add information to defined entity types,
|
Chris@0
|
746 * as defined in \Drupal\Core\Entity\EntityTypeInterface.
|
Chris@0
|
747 *
|
Chris@0
|
748 * To alter existing information or to add information dynamically, use
|
Chris@0
|
749 * hook_entity_type_alter().
|
Chris@0
|
750 *
|
Chris@0
|
751 * @param \Drupal\Core\Entity\EntityTypeInterface[] $entity_types
|
Chris@0
|
752 * An associative array of all entity type definitions, keyed by the entity
|
Chris@0
|
753 * type name. Passed by reference.
|
Chris@0
|
754 *
|
Chris@0
|
755 * @see \Drupal\Core\Entity\Entity
|
Chris@0
|
756 * @see \Drupal\Core\Entity\EntityTypeInterface
|
Chris@0
|
757 * @see hook_entity_type_alter()
|
Chris@0
|
758 */
|
Chris@0
|
759 function hook_entity_type_build(array &$entity_types) {
|
Chris@0
|
760 /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
|
Chris@0
|
761 // Add a form for a custom node form without overriding the default
|
Chris@0
|
762 // node form. To override the default node form, use hook_entity_type_alter().
|
Chris@0
|
763 $entity_types['node']->setFormClass('mymodule_foo', 'Drupal\mymodule\NodeFooForm');
|
Chris@0
|
764 }
|
Chris@0
|
765
|
Chris@0
|
766 /**
|
Chris@0
|
767 * Alter the entity type definitions.
|
Chris@0
|
768 *
|
Chris@0
|
769 * Modules may implement this hook to alter the information that defines an
|
Chris@0
|
770 * entity type. All properties that are available in
|
Chris@0
|
771 * \Drupal\Core\Entity\Annotation\EntityType and all the ones additionally
|
Chris@0
|
772 * provided by modules can be altered here.
|
Chris@0
|
773 *
|
Chris@0
|
774 * Do not use this hook to add information to entity types, unless one of the
|
Chris@0
|
775 * following is true:
|
Chris@0
|
776 * - You are filling in default values.
|
Chris@0
|
777 * - You need to dynamically add information only in certain circumstances.
|
Chris@0
|
778 * - Your hook needs to run after hook_entity_type_build() implementations.
|
Chris@0
|
779 * Use hook_entity_type_build() instead in all other cases.
|
Chris@0
|
780 *
|
Chris@0
|
781 * @param \Drupal\Core\Entity\EntityTypeInterface[] $entity_types
|
Chris@0
|
782 * An associative array of all entity type definitions, keyed by the entity
|
Chris@0
|
783 * type name. Passed by reference.
|
Chris@0
|
784 *
|
Chris@0
|
785 * @see \Drupal\Core\Entity\Entity
|
Chris@0
|
786 * @see \Drupal\Core\Entity\EntityTypeInterface
|
Chris@0
|
787 */
|
Chris@0
|
788 function hook_entity_type_alter(array &$entity_types) {
|
Chris@0
|
789 /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
|
Chris@0
|
790 // Set the controller class for nodes to an alternate implementation of the
|
Chris@0
|
791 // Drupal\Core\Entity\EntityStorageInterface interface.
|
Chris@0
|
792 $entity_types['node']->setStorageClass('Drupal\mymodule\MyCustomNodeStorage');
|
Chris@0
|
793 }
|
Chris@0
|
794
|
Chris@0
|
795 /**
|
Chris@0
|
796 * Alter the view modes for entity types.
|
Chris@0
|
797 *
|
Chris@0
|
798 * @param array $view_modes
|
Chris@0
|
799 * An array of view modes, keyed first by entity type, then by view mode name.
|
Chris@0
|
800 *
|
Chris@18
|
801 * @see \Drupal\Core\Entity\EntityDisplayRepositoryInterface::getAllViewModes()
|
Chris@18
|
802 * @see \Drupal\Core\Entity\EntityDisplayRepositoryInterface::getViewModes()
|
Chris@0
|
803 */
|
Chris@0
|
804 function hook_entity_view_mode_info_alter(&$view_modes) {
|
Chris@0
|
805 $view_modes['user']['full']['status'] = TRUE;
|
Chris@0
|
806 }
|
Chris@0
|
807
|
Chris@0
|
808 /**
|
Chris@0
|
809 * Describe the bundles for entity types.
|
Chris@0
|
810 *
|
Chris@0
|
811 * @return array
|
Chris@0
|
812 * An associative array of all entity bundles, keyed by the entity
|
Chris@0
|
813 * type name, and then the bundle name, with the following keys:
|
Chris@0
|
814 * - label: The human-readable name of the bundle.
|
Chris@17
|
815 * - uri_callback: (optional) The same as the 'uri_callback' key defined for
|
Chris@18
|
816 * the entity type in the EntityTypeManager, but for the bundle only. When
|
Chris@17
|
817 * determining the URI of an entity, if a 'uri_callback' is defined for both
|
Chris@17
|
818 * the entity type and the bundle, the one for the bundle is used.
|
Chris@0
|
819 * - translatable: (optional) A boolean value specifying whether this bundle
|
Chris@0
|
820 * has translation support enabled. Defaults to FALSE.
|
Chris@0
|
821 *
|
Chris@0
|
822 * @see \Drupal\Core\Entity\EntityTypeBundleInfo::getBundleInfo()
|
Chris@0
|
823 * @see hook_entity_bundle_info_alter()
|
Chris@0
|
824 */
|
Chris@0
|
825 function hook_entity_bundle_info() {
|
Chris@0
|
826 $bundles['user']['user']['label'] = t('User');
|
Chris@0
|
827 return $bundles;
|
Chris@0
|
828 }
|
Chris@0
|
829
|
Chris@0
|
830 /**
|
Chris@0
|
831 * Alter the bundles for entity types.
|
Chris@0
|
832 *
|
Chris@0
|
833 * @param array $bundles
|
Chris@0
|
834 * An array of bundles, keyed first by entity type, then by bundle name.
|
Chris@0
|
835 *
|
Chris@0
|
836 * @see Drupal\Core\Entity\EntityTypeBundleInfo::getBundleInfo()
|
Chris@0
|
837 * @see hook_entity_bundle_info()
|
Chris@0
|
838 */
|
Chris@0
|
839 function hook_entity_bundle_info_alter(&$bundles) {
|
Chris@0
|
840 $bundles['user']['user']['label'] = t('Full account');
|
Chris@0
|
841 }
|
Chris@0
|
842
|
Chris@0
|
843 /**
|
Chris@0
|
844 * Act on entity_bundle_create().
|
Chris@0
|
845 *
|
Chris@0
|
846 * This hook is invoked after the operation has been performed.
|
Chris@0
|
847 *
|
Chris@0
|
848 * @param string $entity_type_id
|
Chris@0
|
849 * The type of $entity; e.g. 'node' or 'user'.
|
Chris@0
|
850 * @param string $bundle
|
Chris@0
|
851 * The name of the bundle.
|
Chris@0
|
852 *
|
Chris@0
|
853 * @see entity_crud
|
Chris@0
|
854 */
|
Chris@0
|
855 function hook_entity_bundle_create($entity_type_id, $bundle) {
|
Chris@0
|
856 // When a new bundle is created, the menu needs to be rebuilt to add the
|
Chris@0
|
857 // Field UI menu item tabs.
|
Chris@0
|
858 \Drupal::service('router.builder')->setRebuildNeeded();
|
Chris@0
|
859 }
|
Chris@0
|
860
|
Chris@0
|
861 /**
|
Chris@0
|
862 * Act on entity_bundle_delete().
|
Chris@0
|
863 *
|
Chris@0
|
864 * This hook is invoked after the operation has been performed.
|
Chris@0
|
865 *
|
Chris@0
|
866 * @param string $entity_type_id
|
Chris@0
|
867 * The type of entity; for example, 'node' or 'user'.
|
Chris@0
|
868 * @param string $bundle
|
Chris@0
|
869 * The bundle that was just deleted.
|
Chris@0
|
870 *
|
Chris@0
|
871 * @ingroup entity_crud
|
Chris@0
|
872 */
|
Chris@0
|
873 function hook_entity_bundle_delete($entity_type_id, $bundle) {
|
Chris@0
|
874 // Remove the settings associated with the bundle in my_module.settings.
|
Chris@0
|
875 $config = \Drupal::config('my_module.settings');
|
Chris@0
|
876 $bundle_settings = $config->get('bundle_settings');
|
Chris@0
|
877 if (isset($bundle_settings[$entity_type_id][$bundle])) {
|
Chris@0
|
878 unset($bundle_settings[$entity_type_id][$bundle]);
|
Chris@0
|
879 $config->set('bundle_settings', $bundle_settings);
|
Chris@0
|
880 }
|
Chris@0
|
881 }
|
Chris@0
|
882
|
Chris@0
|
883 /**
|
Chris@0
|
884 * Acts when creating a new entity.
|
Chris@0
|
885 *
|
Chris@0
|
886 * This hook runs after a new entity object has just been instantiated.
|
Chris@0
|
887 *
|
Chris@0
|
888 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
889 * The entity object.
|
Chris@0
|
890 *
|
Chris@0
|
891 * @ingroup entity_crud
|
Chris@0
|
892 * @see hook_ENTITY_TYPE_create()
|
Chris@0
|
893 */
|
Chris@0
|
894 function hook_entity_create(\Drupal\Core\Entity\EntityInterface $entity) {
|
Chris@0
|
895 \Drupal::logger('example')->info('Entity created: @label', ['@label' => $entity->label()]);
|
Chris@0
|
896 }
|
Chris@0
|
897
|
Chris@0
|
898 /**
|
Chris@0
|
899 * Acts when creating a new entity of a specific type.
|
Chris@0
|
900 *
|
Chris@0
|
901 * This hook runs after a new entity object has just been instantiated.
|
Chris@0
|
902 *
|
Chris@0
|
903 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
904 * The entity object.
|
Chris@0
|
905 *
|
Chris@0
|
906 * @ingroup entity_crud
|
Chris@0
|
907 * @see hook_entity_create()
|
Chris@0
|
908 */
|
Chris@0
|
909 function hook_ENTITY_TYPE_create(\Drupal\Core\Entity\EntityInterface $entity) {
|
Chris@0
|
910 \Drupal::logger('example')->info('ENTITY_TYPE created: @label', ['@label' => $entity->label()]);
|
Chris@0
|
911 }
|
Chris@0
|
912
|
Chris@0
|
913 /**
|
Chris@17
|
914 * Respond to entity revision creation.
|
Chris@17
|
915 *
|
Chris@17
|
916 * @param \Drupal\Core\Entity\EntityInterface $new_revision
|
Chris@17
|
917 * The new revision that was created.
|
Chris@17
|
918 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@17
|
919 * The original entity that was used to create the revision from.
|
Chris@17
|
920 * @param bool|null $keep_untranslatable_fields
|
Chris@17
|
921 * Whether untranslatable field values were kept (TRUE) or copied from the
|
Chris@17
|
922 * default revision (FALSE) when generating a merged revision. If no value was
|
Chris@17
|
923 * explicitly specified (NULL), a default value of TRUE should be assumed if
|
Chris@17
|
924 * the provided entity is the default translation and untranslatable fields
|
Chris@17
|
925 * should only affect the default translation, FALSE otherwise.
|
Chris@17
|
926 *
|
Chris@17
|
927 * @ingroup entity_crud
|
Chris@17
|
928 * @see \Drupal\Core\Entity\RevisionableStorageInterface::createRevision()
|
Chris@17
|
929 * @see \Drupal\Core\Entity\TranslatableRevisionableStorageInterface::createRevision()
|
Chris@17
|
930 */
|
Chris@17
|
931 function hook_entity_revision_create(Drupal\Core\Entity\EntityInterface $new_revision, Drupal\Core\Entity\EntityInterface $entity, $keep_untranslatable_fields) {
|
Chris@17
|
932 // Retain the value from an untranslatable field, which are by default
|
Chris@17
|
933 // synchronized from the default revision.
|
Chris@17
|
934 $new_revision->set('untranslatable_field', $entity->get('untranslatable_field'));
|
Chris@17
|
935 }
|
Chris@17
|
936
|
Chris@17
|
937 /**
|
Chris@17
|
938 * Respond to entity revision creation.
|
Chris@17
|
939 *
|
Chris@17
|
940 * @param \Drupal\Core\Entity\EntityInterface $new_revision
|
Chris@17
|
941 * The new revision that was created.
|
Chris@17
|
942 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@17
|
943 * The original entity that was used to create the revision from.
|
Chris@17
|
944 * @param bool|null $keep_untranslatable_fields
|
Chris@17
|
945 * Whether untranslatable field values were kept (TRUE) or copied from the
|
Chris@17
|
946 * default revision (FALSE) when generating a merged revision. If no value was
|
Chris@17
|
947 * explicitly specified (NULL), a default value of TRUE should be assumed if
|
Chris@17
|
948 * the provided entity is the default translation and untranslatable fields
|
Chris@17
|
949 * should only affect the default translation, FALSE otherwise.
|
Chris@17
|
950 *
|
Chris@17
|
951 * @ingroup entity_crud
|
Chris@17
|
952 * @see \Drupal\Core\Entity\RevisionableStorageInterface::createRevision()
|
Chris@17
|
953 * @see \Drupal\Core\Entity\TranslatableRevisionableStorageInterface::createRevision()
|
Chris@17
|
954 */
|
Chris@17
|
955 function hook_ENTITY_TYPE_revision_create(Drupal\Core\Entity\EntityInterface $new_revision, Drupal\Core\Entity\EntityInterface $entity, $keep_untranslatable_fields) {
|
Chris@17
|
956 // Retain the value from an untranslatable field, which are by default
|
Chris@17
|
957 // synchronized from the default revision.
|
Chris@17
|
958 $new_revision->set('untranslatable_field', $entity->get('untranslatable_field'));
|
Chris@17
|
959 }
|
Chris@17
|
960
|
Chris@17
|
961 /**
|
Chris@18
|
962 * Act on an array of entity IDs before they are loaded.
|
Chris@18
|
963 *
|
Chris@18
|
964 * This hook can be used by modules that need, for example, to return a
|
Chris@18
|
965 * different revision than the default one.
|
Chris@18
|
966 *
|
Chris@18
|
967 * @param array $ids
|
Chris@18
|
968 * An array of entity IDs that have to be loaded.
|
Chris@18
|
969 * @param string $entity_type_id
|
Chris@18
|
970 * The type of entities being loaded (i.e. node, user, comment).
|
Chris@18
|
971 *
|
Chris@18
|
972 * @return \Drupal\Core\Entity\EntityInterface[]
|
Chris@18
|
973 * An array of pre-loaded entity objects.
|
Chris@18
|
974 *
|
Chris@18
|
975 * @ingroup entity_crud
|
Chris@18
|
976 */
|
Chris@18
|
977 function hook_entity_preload(array $ids, $entity_type_id) {
|
Chris@18
|
978 $entities = [];
|
Chris@18
|
979
|
Chris@18
|
980 foreach ($ids as $id) {
|
Chris@18
|
981 $entities[] = mymodule_swap_revision($id);
|
Chris@18
|
982 }
|
Chris@18
|
983
|
Chris@18
|
984 return $entities;
|
Chris@18
|
985 }
|
Chris@18
|
986
|
Chris@18
|
987 /**
|
Chris@0
|
988 * Act on entities when loaded.
|
Chris@0
|
989 *
|
Chris@0
|
990 * This is a generic load hook called for all entity types loaded via the
|
Chris@0
|
991 * entity API.
|
Chris@0
|
992 *
|
Chris@0
|
993 * hook_entity_storage_load() should be used to load additional data for
|
Chris@0
|
994 * content entities.
|
Chris@0
|
995 *
|
Chris@0
|
996 * @param \Drupal\Core\Entity\EntityInterface[] $entities
|
Chris@0
|
997 * The entities keyed by entity ID.
|
Chris@0
|
998 * @param string $entity_type_id
|
Chris@0
|
999 * The type of entities being loaded (i.e. node, user, comment).
|
Chris@0
|
1000 *
|
Chris@0
|
1001 * @ingroup entity_crud
|
Chris@0
|
1002 * @see hook_ENTITY_TYPE_load()
|
Chris@0
|
1003 */
|
Chris@0
|
1004 function hook_entity_load(array $entities, $entity_type_id) {
|
Chris@0
|
1005 foreach ($entities as $entity) {
|
Chris@0
|
1006 $entity->foo = mymodule_add_something($entity);
|
Chris@0
|
1007 }
|
Chris@0
|
1008 }
|
Chris@0
|
1009
|
Chris@0
|
1010 /**
|
Chris@0
|
1011 * Act on entities of a specific type when loaded.
|
Chris@0
|
1012 *
|
Chris@0
|
1013 * @param array $entities
|
Chris@0
|
1014 * The entities keyed by entity ID.
|
Chris@0
|
1015 *
|
Chris@0
|
1016 * @ingroup entity_crud
|
Chris@0
|
1017 * @see hook_entity_load()
|
Chris@0
|
1018 */
|
Chris@0
|
1019 function hook_ENTITY_TYPE_load($entities) {
|
Chris@0
|
1020 foreach ($entities as $entity) {
|
Chris@0
|
1021 $entity->foo = mymodule_add_something($entity);
|
Chris@0
|
1022 }
|
Chris@0
|
1023 }
|
Chris@0
|
1024
|
Chris@0
|
1025 /**
|
Chris@0
|
1026 * Act on content entities when loaded from the storage.
|
Chris@0
|
1027 *
|
Chris@0
|
1028 * The results of this hook will be cached.
|
Chris@0
|
1029 *
|
Chris@0
|
1030 * @param \Drupal\Core\Entity\EntityInterface[] $entities
|
Chris@0
|
1031 * The entities keyed by entity ID.
|
Chris@0
|
1032 * @param string $entity_type
|
Chris@0
|
1033 * The type of entities being loaded (i.e. node, user, comment).
|
Chris@0
|
1034 *
|
Chris@0
|
1035 * @see hook_entity_load()
|
Chris@0
|
1036 */
|
Chris@0
|
1037 function hook_entity_storage_load(array $entities, $entity_type) {
|
Chris@0
|
1038 foreach ($entities as $entity) {
|
Chris@0
|
1039 $entity->foo = mymodule_add_something_uncached($entity);
|
Chris@0
|
1040 }
|
Chris@0
|
1041 }
|
Chris@0
|
1042
|
Chris@0
|
1043 /**
|
Chris@0
|
1044 * Act on content entities of a given type when loaded from the storage.
|
Chris@0
|
1045 *
|
Chris@0
|
1046 * The results of this hook will be cached if the entity type supports it.
|
Chris@0
|
1047 *
|
Chris@0
|
1048 * @param \Drupal\Core\Entity\EntityInterface[] $entities
|
Chris@0
|
1049 * The entities keyed by entity ID.
|
Chris@0
|
1050 *
|
Chris@0
|
1051 * @see hook_entity_storage_load()
|
Chris@0
|
1052 */
|
Chris@0
|
1053 function hook_ENTITY_TYPE_storage_load(array $entities) {
|
Chris@0
|
1054 foreach ($entities as $entity) {
|
Chris@0
|
1055 $entity->foo = mymodule_add_something_uncached($entity);
|
Chris@0
|
1056 }
|
Chris@0
|
1057 }
|
Chris@0
|
1058
|
Chris@0
|
1059 /**
|
Chris@0
|
1060 * Act on an entity before it is created or updated.
|
Chris@0
|
1061 *
|
Chris@0
|
1062 * You can get the original entity object from $entity->original when it is an
|
Chris@0
|
1063 * update of the entity.
|
Chris@0
|
1064 *
|
Chris@0
|
1065 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
1066 * The entity object.
|
Chris@0
|
1067 *
|
Chris@0
|
1068 * @ingroup entity_crud
|
Chris@0
|
1069 * @see hook_ENTITY_TYPE_presave()
|
Chris@0
|
1070 */
|
Chris@0
|
1071 function hook_entity_presave(Drupal\Core\Entity\EntityInterface $entity) {
|
Chris@0
|
1072 if ($entity instanceof ContentEntityInterface && $entity->isTranslatable()) {
|
Chris@0
|
1073 $route_match = \Drupal::routeMatch();
|
Chris@0
|
1074 \Drupal::service('content_translation.synchronizer')->synchronizeFields($entity, $entity->language()->getId(), $route_match->getParameter('source_langcode'));
|
Chris@0
|
1075 }
|
Chris@0
|
1076 }
|
Chris@0
|
1077
|
Chris@0
|
1078 /**
|
Chris@0
|
1079 * Act on a specific type of entity before it is created or updated.
|
Chris@0
|
1080 *
|
Chris@0
|
1081 * You can get the original entity object from $entity->original when it is an
|
Chris@0
|
1082 * update of the entity.
|
Chris@0
|
1083 *
|
Chris@0
|
1084 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
1085 * The entity object.
|
Chris@0
|
1086 *
|
Chris@0
|
1087 * @ingroup entity_crud
|
Chris@0
|
1088 * @see hook_entity_presave()
|
Chris@0
|
1089 */
|
Chris@0
|
1090 function hook_ENTITY_TYPE_presave(Drupal\Core\Entity\EntityInterface $entity) {
|
Chris@0
|
1091 if ($entity->isTranslatable()) {
|
Chris@0
|
1092 $route_match = \Drupal::routeMatch();
|
Chris@0
|
1093 \Drupal::service('content_translation.synchronizer')->synchronizeFields($entity, $entity->language()->getId(), $route_match->getParameter('source_langcode'));
|
Chris@0
|
1094 }
|
Chris@0
|
1095 }
|
Chris@0
|
1096
|
Chris@0
|
1097 /**
|
Chris@0
|
1098 * Respond to creation of a new entity.
|
Chris@0
|
1099 *
|
Chris@0
|
1100 * This hook runs once the entity has been stored. Note that hook
|
Chris@0
|
1101 * implementations may not alter the stored entity data.
|
Chris@0
|
1102 *
|
Chris@0
|
1103 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
1104 * The entity object.
|
Chris@0
|
1105 *
|
Chris@0
|
1106 * @ingroup entity_crud
|
Chris@0
|
1107 * @see hook_ENTITY_TYPE_insert()
|
Chris@0
|
1108 */
|
Chris@0
|
1109 function hook_entity_insert(Drupal\Core\Entity\EntityInterface $entity) {
|
Chris@0
|
1110 // Insert the new entity into a fictional table of all entities.
|
Chris@18
|
1111 \Drupal::database()->insert('example_entity')
|
Chris@0
|
1112 ->fields([
|
Chris@0
|
1113 'type' => $entity->getEntityTypeId(),
|
Chris@0
|
1114 'id' => $entity->id(),
|
Chris@0
|
1115 'created' => REQUEST_TIME,
|
Chris@0
|
1116 'updated' => REQUEST_TIME,
|
Chris@0
|
1117 ])
|
Chris@0
|
1118 ->execute();
|
Chris@0
|
1119 }
|
Chris@0
|
1120
|
Chris@0
|
1121 /**
|
Chris@0
|
1122 * Respond to creation of a new entity of a particular type.
|
Chris@0
|
1123 *
|
Chris@0
|
1124 * This hook runs once the entity has been stored. Note that hook
|
Chris@0
|
1125 * implementations may not alter the stored entity data.
|
Chris@0
|
1126 *
|
Chris@0
|
1127 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
1128 * The entity object.
|
Chris@0
|
1129 *
|
Chris@0
|
1130 * @ingroup entity_crud
|
Chris@0
|
1131 * @see hook_entity_insert()
|
Chris@0
|
1132 */
|
Chris@0
|
1133 function hook_ENTITY_TYPE_insert(Drupal\Core\Entity\EntityInterface $entity) {
|
Chris@0
|
1134 // Insert the new entity into a fictional table of this type of entity.
|
Chris@18
|
1135 \Drupal::database()->insert('example_entity')
|
Chris@0
|
1136 ->fields([
|
Chris@0
|
1137 'id' => $entity->id(),
|
Chris@0
|
1138 'created' => REQUEST_TIME,
|
Chris@0
|
1139 'updated' => REQUEST_TIME,
|
Chris@0
|
1140 ])
|
Chris@0
|
1141 ->execute();
|
Chris@0
|
1142 }
|
Chris@0
|
1143
|
Chris@0
|
1144 /**
|
Chris@0
|
1145 * Respond to updates to an entity.
|
Chris@0
|
1146 *
|
Chris@0
|
1147 * This hook runs once the entity storage has been updated. Note that hook
|
Chris@0
|
1148 * implementations may not alter the stored entity data. Get the original entity
|
Chris@0
|
1149 * object from $entity->original.
|
Chris@0
|
1150 *
|
Chris@0
|
1151 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
1152 * The entity object.
|
Chris@0
|
1153 *
|
Chris@0
|
1154 * @ingroup entity_crud
|
Chris@0
|
1155 * @see hook_ENTITY_TYPE_update()
|
Chris@0
|
1156 */
|
Chris@0
|
1157 function hook_entity_update(Drupal\Core\Entity\EntityInterface $entity) {
|
Chris@0
|
1158 // Update the entity's entry in a fictional table of all entities.
|
Chris@18
|
1159 \Drupal::database()->update('example_entity')
|
Chris@0
|
1160 ->fields([
|
Chris@0
|
1161 'updated' => REQUEST_TIME,
|
Chris@0
|
1162 ])
|
Chris@0
|
1163 ->condition('type', $entity->getEntityTypeId())
|
Chris@0
|
1164 ->condition('id', $entity->id())
|
Chris@0
|
1165 ->execute();
|
Chris@0
|
1166 }
|
Chris@0
|
1167
|
Chris@0
|
1168 /**
|
Chris@0
|
1169 * Respond to updates to an entity of a particular type.
|
Chris@0
|
1170 *
|
Chris@0
|
1171 * This hook runs once the entity storage has been updated. Note that hook
|
Chris@0
|
1172 * implementations may not alter the stored entity data. Get the original entity
|
Chris@0
|
1173 * object from $entity->original.
|
Chris@0
|
1174 *
|
Chris@0
|
1175 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
1176 * The entity object.
|
Chris@0
|
1177 *
|
Chris@0
|
1178 * @ingroup entity_crud
|
Chris@0
|
1179 * @see hook_entity_update()
|
Chris@0
|
1180 */
|
Chris@0
|
1181 function hook_ENTITY_TYPE_update(Drupal\Core\Entity\EntityInterface $entity) {
|
Chris@0
|
1182 // Update the entity's entry in a fictional table of this type of entity.
|
Chris@18
|
1183 \Drupal::database()->update('example_entity')
|
Chris@0
|
1184 ->fields([
|
Chris@0
|
1185 'updated' => REQUEST_TIME,
|
Chris@0
|
1186 ])
|
Chris@0
|
1187 ->condition('id', $entity->id())
|
Chris@0
|
1188 ->execute();
|
Chris@0
|
1189 }
|
Chris@0
|
1190
|
Chris@0
|
1191 /**
|
Chris@0
|
1192 * Acts when creating a new entity translation.
|
Chris@0
|
1193 *
|
Chris@0
|
1194 * This hook runs after a new entity translation object has just been
|
Chris@0
|
1195 * instantiated.
|
Chris@0
|
1196 *
|
Chris@0
|
1197 * @param \Drupal\Core\Entity\EntityInterface $translation
|
Chris@0
|
1198 * The entity object.
|
Chris@0
|
1199 *
|
Chris@0
|
1200 * @ingroup entity_crud
|
Chris@0
|
1201 * @see hook_ENTITY_TYPE_translation_create()
|
Chris@0
|
1202 */
|
Chris@0
|
1203 function hook_entity_translation_create(\Drupal\Core\Entity\EntityInterface $translation) {
|
Chris@0
|
1204 \Drupal::logger('example')->info('Entity translation created: @label', ['@label' => $translation->label()]);
|
Chris@0
|
1205 }
|
Chris@0
|
1206
|
Chris@0
|
1207 /**
|
Chris@0
|
1208 * Acts when creating a new entity translation of a specific type.
|
Chris@0
|
1209 *
|
Chris@0
|
1210 * This hook runs after a new entity translation object has just been
|
Chris@0
|
1211 * instantiated.
|
Chris@0
|
1212 *
|
Chris@0
|
1213 * @param \Drupal\Core\Entity\EntityInterface $translation
|
Chris@0
|
1214 * The entity object.
|
Chris@0
|
1215 *
|
Chris@0
|
1216 * @ingroup entity_crud
|
Chris@0
|
1217 * @see hook_entity_translation_create()
|
Chris@0
|
1218 */
|
Chris@0
|
1219 function hook_ENTITY_TYPE_translation_create(\Drupal\Core\Entity\EntityInterface $translation) {
|
Chris@0
|
1220 \Drupal::logger('example')->info('ENTITY_TYPE translation created: @label', ['@label' => $translation->label()]);
|
Chris@0
|
1221 }
|
Chris@0
|
1222
|
Chris@0
|
1223 /**
|
Chris@0
|
1224 * Respond to creation of a new entity translation.
|
Chris@0
|
1225 *
|
Chris@0
|
1226 * This hook runs once the entity translation has been stored. Note that hook
|
Chris@0
|
1227 * implementations may not alter the stored entity translation data.
|
Chris@0
|
1228 *
|
Chris@0
|
1229 * @param \Drupal\Core\Entity\EntityInterface $translation
|
Chris@0
|
1230 * The entity object of the translation just stored.
|
Chris@0
|
1231 *
|
Chris@0
|
1232 * @ingroup entity_crud
|
Chris@0
|
1233 * @see hook_ENTITY_TYPE_translation_insert()
|
Chris@0
|
1234 */
|
Chris@0
|
1235 function hook_entity_translation_insert(\Drupal\Core\Entity\EntityInterface $translation) {
|
Chris@0
|
1236 $variables = [
|
Chris@0
|
1237 '@language' => $translation->language()->getName(),
|
Chris@0
|
1238 '@label' => $translation->getUntranslated()->label(),
|
Chris@0
|
1239 ];
|
Chris@0
|
1240 \Drupal::logger('example')->notice('The @language translation of @label has just been stored.', $variables);
|
Chris@0
|
1241 }
|
Chris@0
|
1242
|
Chris@0
|
1243 /**
|
Chris@0
|
1244 * Respond to creation of a new entity translation of a particular type.
|
Chris@0
|
1245 *
|
Chris@0
|
1246 * This hook runs once the entity translation has been stored. Note that hook
|
Chris@0
|
1247 * implementations may not alter the stored entity translation data.
|
Chris@0
|
1248 *
|
Chris@0
|
1249 * @param \Drupal\Core\Entity\EntityInterface $translation
|
Chris@0
|
1250 * The entity object of the translation just stored.
|
Chris@0
|
1251 *
|
Chris@0
|
1252 * @ingroup entity_crud
|
Chris@0
|
1253 * @see hook_entity_translation_insert()
|
Chris@0
|
1254 */
|
Chris@0
|
1255 function hook_ENTITY_TYPE_translation_insert(\Drupal\Core\Entity\EntityInterface $translation) {
|
Chris@0
|
1256 $variables = [
|
Chris@0
|
1257 '@language' => $translation->language()->getName(),
|
Chris@0
|
1258 '@label' => $translation->getUntranslated()->label(),
|
Chris@0
|
1259 ];
|
Chris@0
|
1260 \Drupal::logger('example')->notice('The @language translation of @label has just been stored.', $variables);
|
Chris@0
|
1261 }
|
Chris@0
|
1262
|
Chris@0
|
1263 /**
|
Chris@0
|
1264 * Respond to entity translation deletion.
|
Chris@0
|
1265 *
|
Chris@0
|
1266 * This hook runs once the entity translation has been deleted from storage.
|
Chris@0
|
1267 *
|
Chris@0
|
1268 * @param \Drupal\Core\Entity\EntityInterface $translation
|
Chris@0
|
1269 * The original entity object.
|
Chris@0
|
1270 *
|
Chris@0
|
1271 * @ingroup entity_crud
|
Chris@0
|
1272 * @see hook_ENTITY_TYPE_translation_delete()
|
Chris@0
|
1273 */
|
Chris@0
|
1274 function hook_entity_translation_delete(\Drupal\Core\Entity\EntityInterface $translation) {
|
Chris@0
|
1275 $variables = [
|
Chris@0
|
1276 '@language' => $translation->language()->getName(),
|
Chris@0
|
1277 '@label' => $translation->label(),
|
Chris@0
|
1278 ];
|
Chris@0
|
1279 \Drupal::logger('example')->notice('The @language translation of @label has just been deleted.', $variables);
|
Chris@0
|
1280 }
|
Chris@0
|
1281
|
Chris@0
|
1282 /**
|
Chris@0
|
1283 * Respond to entity translation deletion of a particular type.
|
Chris@0
|
1284 *
|
Chris@0
|
1285 * This hook runs once the entity translation has been deleted from storage.
|
Chris@0
|
1286 *
|
Chris@0
|
1287 * @param \Drupal\Core\Entity\EntityInterface $translation
|
Chris@0
|
1288 * The original entity object.
|
Chris@0
|
1289 *
|
Chris@0
|
1290 * @ingroup entity_crud
|
Chris@0
|
1291 * @see hook_entity_translation_delete()
|
Chris@0
|
1292 */
|
Chris@0
|
1293 function hook_ENTITY_TYPE_translation_delete(\Drupal\Core\Entity\EntityInterface $translation) {
|
Chris@0
|
1294 $variables = [
|
Chris@0
|
1295 '@language' => $translation->language()->getName(),
|
Chris@0
|
1296 '@label' => $translation->label(),
|
Chris@0
|
1297 ];
|
Chris@0
|
1298 \Drupal::logger('example')->notice('The @language translation of @label has just been deleted.', $variables);
|
Chris@0
|
1299 }
|
Chris@0
|
1300
|
Chris@0
|
1301 /**
|
Chris@0
|
1302 * Act before entity deletion.
|
Chris@0
|
1303 *
|
Chris@0
|
1304 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
1305 * The entity object for the entity that is about to be deleted.
|
Chris@0
|
1306 *
|
Chris@0
|
1307 * @ingroup entity_crud
|
Chris@0
|
1308 * @see hook_ENTITY_TYPE_predelete()
|
Chris@0
|
1309 */
|
Chris@0
|
1310 function hook_entity_predelete(Drupal\Core\Entity\EntityInterface $entity) {
|
Chris@18
|
1311 $connection = \Drupal::database();
|
Chris@0
|
1312 // Count references to this entity in a custom table before they are removed
|
Chris@0
|
1313 // upon entity deletion.
|
Chris@0
|
1314 $id = $entity->id();
|
Chris@0
|
1315 $type = $entity->getEntityTypeId();
|
Chris@18
|
1316 $count = \Drupal::database()->select('example_entity_data')
|
Chris@0
|
1317 ->condition('type', $type)
|
Chris@0
|
1318 ->condition('id', $id)
|
Chris@0
|
1319 ->countQuery()
|
Chris@0
|
1320 ->execute()
|
Chris@0
|
1321 ->fetchField();
|
Chris@0
|
1322
|
Chris@0
|
1323 // Log the count in a table that records this statistic for deleted entities.
|
Chris@18
|
1324 $connection->merge('example_deleted_entity_statistics')
|
Chris@0
|
1325 ->key(['type' => $type, 'id' => $id])
|
Chris@0
|
1326 ->fields(['count' => $count])
|
Chris@0
|
1327 ->execute();
|
Chris@0
|
1328 }
|
Chris@0
|
1329
|
Chris@0
|
1330 /**
|
Chris@0
|
1331 * Act before entity deletion of a particular entity type.
|
Chris@0
|
1332 *
|
Chris@0
|
1333 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
1334 * The entity object for the entity that is about to be deleted.
|
Chris@0
|
1335 *
|
Chris@0
|
1336 * @ingroup entity_crud
|
Chris@0
|
1337 * @see hook_entity_predelete()
|
Chris@0
|
1338 */
|
Chris@0
|
1339 function hook_ENTITY_TYPE_predelete(Drupal\Core\Entity\EntityInterface $entity) {
|
Chris@18
|
1340 $connection = \Drupal::database();
|
Chris@0
|
1341 // Count references to this entity in a custom table before they are removed
|
Chris@0
|
1342 // upon entity deletion.
|
Chris@0
|
1343 $id = $entity->id();
|
Chris@0
|
1344 $type = $entity->getEntityTypeId();
|
Chris@18
|
1345 $count = \Drupal::database()->select('example_entity_data')
|
Chris@0
|
1346 ->condition('type', $type)
|
Chris@0
|
1347 ->condition('id', $id)
|
Chris@0
|
1348 ->countQuery()
|
Chris@0
|
1349 ->execute()
|
Chris@0
|
1350 ->fetchField();
|
Chris@0
|
1351
|
Chris@0
|
1352 // Log the count in a table that records this statistic for deleted entities.
|
Chris@18
|
1353 $connection->merge('example_deleted_entity_statistics')
|
Chris@0
|
1354 ->key(['type' => $type, 'id' => $id])
|
Chris@0
|
1355 ->fields(['count' => $count])
|
Chris@0
|
1356 ->execute();
|
Chris@0
|
1357 }
|
Chris@0
|
1358
|
Chris@0
|
1359 /**
|
Chris@0
|
1360 * Respond to entity deletion.
|
Chris@0
|
1361 *
|
Chris@0
|
1362 * This hook runs once the entity has been deleted from the storage.
|
Chris@0
|
1363 *
|
Chris@0
|
1364 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
1365 * The entity object for the entity that has been deleted.
|
Chris@0
|
1366 *
|
Chris@0
|
1367 * @ingroup entity_crud
|
Chris@0
|
1368 * @see hook_ENTITY_TYPE_delete()
|
Chris@0
|
1369 */
|
Chris@0
|
1370 function hook_entity_delete(Drupal\Core\Entity\EntityInterface $entity) {
|
Chris@0
|
1371 // Delete the entity's entry from a fictional table of all entities.
|
Chris@18
|
1372 \Drupal::database()->delete('example_entity')
|
Chris@0
|
1373 ->condition('type', $entity->getEntityTypeId())
|
Chris@0
|
1374 ->condition('id', $entity->id())
|
Chris@0
|
1375 ->execute();
|
Chris@0
|
1376 }
|
Chris@0
|
1377
|
Chris@0
|
1378 /**
|
Chris@0
|
1379 * Respond to entity deletion of a particular type.
|
Chris@0
|
1380 *
|
Chris@0
|
1381 * This hook runs once the entity has been deleted from the storage.
|
Chris@0
|
1382 *
|
Chris@0
|
1383 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
1384 * The entity object for the entity that has been deleted.
|
Chris@0
|
1385 *
|
Chris@0
|
1386 * @ingroup entity_crud
|
Chris@0
|
1387 * @see hook_entity_delete()
|
Chris@0
|
1388 */
|
Chris@0
|
1389 function hook_ENTITY_TYPE_delete(Drupal\Core\Entity\EntityInterface $entity) {
|
Chris@0
|
1390 // Delete the entity's entry from a fictional table of all entities.
|
Chris@18
|
1391 \Drupal::database()->delete('example_entity')
|
Chris@0
|
1392 ->condition('type', $entity->getEntityTypeId())
|
Chris@0
|
1393 ->condition('id', $entity->id())
|
Chris@0
|
1394 ->execute();
|
Chris@0
|
1395 }
|
Chris@0
|
1396
|
Chris@0
|
1397 /**
|
Chris@0
|
1398 * Respond to entity revision deletion.
|
Chris@0
|
1399 *
|
Chris@0
|
1400 * This hook runs once the entity revision has been deleted from the storage.
|
Chris@0
|
1401 *
|
Chris@0
|
1402 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
1403 * The entity object for the entity revision that has been deleted.
|
Chris@0
|
1404 *
|
Chris@0
|
1405 * @ingroup entity_crud
|
Chris@0
|
1406 * @see hook_ENTITY_TYPE_revision_delete()
|
Chris@0
|
1407 */
|
Chris@0
|
1408 function hook_entity_revision_delete(Drupal\Core\Entity\EntityInterface $entity) {
|
Chris@0
|
1409 $referenced_files_by_field = _editor_get_file_uuids_by_field($entity);
|
Chris@0
|
1410 foreach ($referenced_files_by_field as $field => $uuids) {
|
Chris@0
|
1411 _editor_delete_file_usage($uuids, $entity, 1);
|
Chris@0
|
1412 }
|
Chris@0
|
1413 }
|
Chris@0
|
1414
|
Chris@0
|
1415 /**
|
Chris@0
|
1416 * Respond to entity revision deletion of a particular type.
|
Chris@0
|
1417 *
|
Chris@0
|
1418 * This hook runs once the entity revision has been deleted from the storage.
|
Chris@0
|
1419 *
|
Chris@0
|
1420 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
1421 * The entity object for the entity revision that has been deleted.
|
Chris@0
|
1422 *
|
Chris@0
|
1423 * @ingroup entity_crud
|
Chris@0
|
1424 * @see hook_entity_revision_delete()
|
Chris@0
|
1425 */
|
Chris@0
|
1426 function hook_ENTITY_TYPE_revision_delete(Drupal\Core\Entity\EntityInterface $entity) {
|
Chris@0
|
1427 $referenced_files_by_field = _editor_get_file_uuids_by_field($entity);
|
Chris@0
|
1428 foreach ($referenced_files_by_field as $field => $uuids) {
|
Chris@0
|
1429 _editor_delete_file_usage($uuids, $entity, 1);
|
Chris@0
|
1430 }
|
Chris@0
|
1431 }
|
Chris@0
|
1432
|
Chris@0
|
1433 /**
|
Chris@0
|
1434 * Act on entities being assembled before rendering.
|
Chris@0
|
1435 *
|
Chris@0
|
1436 * @param &$build
|
Chris@0
|
1437 * A renderable array representing the entity content. The module may add
|
Chris@0
|
1438 * elements to $build prior to rendering. The structure of $build is a
|
Chris@16
|
1439 * renderable array as expected by
|
Chris@16
|
1440 * \Drupal\Core\Render\RendererInterface::render().
|
Chris@0
|
1441 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
1442 * The entity object.
|
Chris@0
|
1443 * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
|
Chris@0
|
1444 * The entity view display holding the display options configured for the
|
Chris@0
|
1445 * entity components.
|
Chris@0
|
1446 * @param $view_mode
|
Chris@0
|
1447 * The view mode the entity is rendered in.
|
Chris@0
|
1448 *
|
Chris@0
|
1449 * @see hook_entity_view_alter()
|
Chris@0
|
1450 * @see hook_ENTITY_TYPE_view()
|
Chris@0
|
1451 *
|
Chris@0
|
1452 * @ingroup entity_crud
|
Chris@0
|
1453 */
|
Chris@0
|
1454 function hook_entity_view(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode) {
|
Chris@0
|
1455 // Only do the extra work if the component is configured to be displayed.
|
Chris@0
|
1456 // This assumes a 'mymodule_addition' extra field has been defined for the
|
Chris@0
|
1457 // entity bundle in hook_entity_extra_field_info().
|
Chris@0
|
1458 if ($display->getComponent('mymodule_addition')) {
|
Chris@0
|
1459 $build['mymodule_addition'] = [
|
Chris@0
|
1460 '#markup' => mymodule_addition($entity),
|
Chris@0
|
1461 '#theme' => 'mymodule_my_additional_field',
|
Chris@0
|
1462 ];
|
Chris@0
|
1463 }
|
Chris@0
|
1464 }
|
Chris@0
|
1465
|
Chris@0
|
1466 /**
|
Chris@0
|
1467 * Act on entities of a particular type being assembled before rendering.
|
Chris@0
|
1468 *
|
Chris@0
|
1469 * @param &$build
|
Chris@0
|
1470 * A renderable array representing the entity content. The module may add
|
Chris@0
|
1471 * elements to $build prior to rendering. The structure of $build is a
|
Chris@16
|
1472 * renderable array as expected by
|
Chris@16
|
1473 * \Drupal\Core\Render\RendererInterface::render().
|
Chris@0
|
1474 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
1475 * The entity object.
|
Chris@0
|
1476 * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
|
Chris@0
|
1477 * The entity view display holding the display options configured for the
|
Chris@0
|
1478 * entity components.
|
Chris@0
|
1479 * @param $view_mode
|
Chris@0
|
1480 * The view mode the entity is rendered in.
|
Chris@0
|
1481 *
|
Chris@0
|
1482 * @see hook_ENTITY_TYPE_view_alter()
|
Chris@0
|
1483 * @see hook_entity_view()
|
Chris@0
|
1484 *
|
Chris@0
|
1485 * @ingroup entity_crud
|
Chris@0
|
1486 */
|
Chris@0
|
1487 function hook_ENTITY_TYPE_view(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode) {
|
Chris@0
|
1488 // Only do the extra work if the component is configured to be displayed.
|
Chris@0
|
1489 // This assumes a 'mymodule_addition' extra field has been defined for the
|
Chris@0
|
1490 // entity bundle in hook_entity_extra_field_info().
|
Chris@0
|
1491 if ($display->getComponent('mymodule_addition')) {
|
Chris@0
|
1492 $build['mymodule_addition'] = [
|
Chris@0
|
1493 '#markup' => mymodule_addition($entity),
|
Chris@0
|
1494 '#theme' => 'mymodule_my_additional_field',
|
Chris@0
|
1495 ];
|
Chris@0
|
1496 }
|
Chris@0
|
1497 }
|
Chris@0
|
1498
|
Chris@0
|
1499 /**
|
Chris@0
|
1500 * Alter the results of the entity build array.
|
Chris@0
|
1501 *
|
Chris@0
|
1502 * This hook is called after the content has been assembled in a structured
|
Chris@0
|
1503 * array and may be used for doing processing which requires that the complete
|
Chris@0
|
1504 * entity content structure has been built.
|
Chris@0
|
1505 *
|
Chris@0
|
1506 * If a module wishes to act on the rendered HTML of the entity rather than the
|
Chris@0
|
1507 * structured content array, it may use this hook to add a #post_render
|
Chris@0
|
1508 * callback. Alternatively, it could also implement hook_preprocess_HOOK() for
|
Chris@0
|
1509 * the particular entity type template, if there is one (e.g., node.html.twig).
|
Chris@0
|
1510 *
|
Chris@0
|
1511 * See the @link themeable Default theme implementations topic @endlink and
|
Chris@0
|
1512 * drupal_render() for details.
|
Chris@0
|
1513 *
|
Chris@0
|
1514 * @param array &$build
|
Chris@0
|
1515 * A renderable array representing the entity content.
|
Chris@0
|
1516 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
1517 * The entity object being rendered.
|
Chris@0
|
1518 * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
|
Chris@0
|
1519 * The entity view display holding the display options configured for the
|
Chris@0
|
1520 * entity components.
|
Chris@0
|
1521 *
|
Chris@0
|
1522 * @ingroup entity_crud
|
Chris@0
|
1523 *
|
Chris@0
|
1524 * @see hook_entity_view()
|
Chris@0
|
1525 * @see hook_ENTITY_TYPE_view_alter()
|
Chris@0
|
1526 */
|
Chris@0
|
1527 function hook_entity_view_alter(array &$build, Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
|
Chris@0
|
1528 if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) {
|
Chris@0
|
1529 // Change its weight.
|
Chris@0
|
1530 $build['an_additional_field']['#weight'] = -10;
|
Chris@0
|
1531
|
Chris@0
|
1532 // Add a #post_render callback to act on the rendered HTML of the entity.
|
Chris@0
|
1533 $build['#post_render'][] = 'my_module_node_post_render';
|
Chris@0
|
1534 }
|
Chris@0
|
1535 }
|
Chris@0
|
1536
|
Chris@0
|
1537 /**
|
Chris@0
|
1538 * Alter the results of the entity build array for a particular entity type.
|
Chris@0
|
1539 *
|
Chris@0
|
1540 * This hook is called after the content has been assembled in a structured
|
Chris@0
|
1541 * array and may be used for doing processing which requires that the complete
|
Chris@0
|
1542 * entity content structure has been built.
|
Chris@0
|
1543 *
|
Chris@0
|
1544 * If a module wishes to act on the rendered HTML of the entity rather than the
|
Chris@0
|
1545 * structured content array, it may use this hook to add a #post_render
|
Chris@0
|
1546 * callback. Alternatively, it could also implement hook_preprocess_HOOK() for
|
Chris@0
|
1547 * the particular entity type template, if there is one (e.g., node.html.twig).
|
Chris@0
|
1548 *
|
Chris@0
|
1549 * See the @link themeable Default theme implementations topic @endlink and
|
Chris@0
|
1550 * drupal_render() for details.
|
Chris@0
|
1551 *
|
Chris@0
|
1552 * @param array &$build
|
Chris@0
|
1553 * A renderable array representing the entity content.
|
Chris@0
|
1554 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
1555 * The entity object being rendered.
|
Chris@0
|
1556 * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
|
Chris@0
|
1557 * The entity view display holding the display options configured for the
|
Chris@0
|
1558 * entity components.
|
Chris@0
|
1559 *
|
Chris@0
|
1560 * @ingroup entity_crud
|
Chris@0
|
1561 *
|
Chris@0
|
1562 * @see hook_ENTITY_TYPE_view()
|
Chris@0
|
1563 * @see hook_entity_view_alter()
|
Chris@0
|
1564 */
|
Chris@0
|
1565 function hook_ENTITY_TYPE_view_alter(array &$build, Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
|
Chris@0
|
1566 if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) {
|
Chris@0
|
1567 // Change its weight.
|
Chris@0
|
1568 $build['an_additional_field']['#weight'] = -10;
|
Chris@0
|
1569
|
Chris@0
|
1570 // Add a #post_render callback to act on the rendered HTML of the entity.
|
Chris@0
|
1571 $build['#post_render'][] = 'my_module_node_post_render';
|
Chris@0
|
1572 }
|
Chris@0
|
1573 }
|
Chris@0
|
1574
|
Chris@0
|
1575 /**
|
Chris@0
|
1576 * Act on entities as they are being prepared for view.
|
Chris@0
|
1577 *
|
Chris@0
|
1578 * Allows you to operate on multiple entities as they are being prepared for
|
Chris@0
|
1579 * view. Only use this if attaching the data during the entity loading phase
|
Chris@0
|
1580 * is not appropriate, for example when attaching other 'entity' style objects.
|
Chris@0
|
1581 *
|
Chris@0
|
1582 * @param string $entity_type_id
|
Chris@0
|
1583 * The type of entities being viewed (i.e. node, user, comment).
|
Chris@0
|
1584 * @param array $entities
|
Chris@0
|
1585 * The entities keyed by entity ID.
|
Chris@0
|
1586 * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface[] $displays
|
Chris@0
|
1587 * The array of entity view displays holding the display options configured
|
Chris@0
|
1588 * for the entity components, keyed by bundle name.
|
Chris@0
|
1589 * @param string $view_mode
|
Chris@0
|
1590 * The view mode.
|
Chris@0
|
1591 *
|
Chris@0
|
1592 * @ingroup entity_crud
|
Chris@0
|
1593 */
|
Chris@0
|
1594 function hook_entity_prepare_view($entity_type_id, array $entities, array $displays, $view_mode) {
|
Chris@0
|
1595 // Load a specific node into the user object for later theming.
|
Chris@0
|
1596 if (!empty($entities) && $entity_type_id == 'user') {
|
Chris@0
|
1597 // Only do the extra work if the component is configured to be
|
Chris@0
|
1598 // displayed. This assumes a 'mymodule_addition' extra field has been
|
Chris@0
|
1599 // defined for the entity bundle in hook_entity_extra_field_info().
|
Chris@0
|
1600 $ids = [];
|
Chris@0
|
1601 foreach ($entities as $id => $entity) {
|
Chris@0
|
1602 if ($displays[$entity->bundle()]->getComponent('mymodule_addition')) {
|
Chris@0
|
1603 $ids[] = $id;
|
Chris@0
|
1604 }
|
Chris@0
|
1605 }
|
Chris@0
|
1606 if ($ids) {
|
Chris@0
|
1607 $nodes = mymodule_get_user_nodes($ids);
|
Chris@0
|
1608 foreach ($ids as $id) {
|
Chris@0
|
1609 $entities[$id]->user_node = $nodes[$id];
|
Chris@0
|
1610 }
|
Chris@0
|
1611 }
|
Chris@0
|
1612 }
|
Chris@0
|
1613 }
|
Chris@0
|
1614
|
Chris@0
|
1615 /**
|
Chris@0
|
1616 * Change the view mode of an entity that is being displayed.
|
Chris@0
|
1617 *
|
Chris@0
|
1618 * @param string $view_mode
|
Chris@0
|
1619 * The view_mode that is to be used to display the entity.
|
Chris@0
|
1620 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
1621 * The entity that is being viewed.
|
Chris@0
|
1622 * @param array $context
|
Chris@0
|
1623 * Array with additional context information, currently only contains the
|
Chris@0
|
1624 * langcode the entity is viewed in.
|
Chris@0
|
1625 *
|
Chris@0
|
1626 * @ingroup entity_crud
|
Chris@0
|
1627 */
|
Chris@0
|
1628 function hook_entity_view_mode_alter(&$view_mode, Drupal\Core\Entity\EntityInterface $entity, $context) {
|
Chris@0
|
1629 // For nodes, change the view mode when it is teaser.
|
Chris@0
|
1630 if ($entity->getEntityTypeId() == 'node' && $view_mode == 'teaser') {
|
Chris@0
|
1631 $view_mode = 'my_custom_view_mode';
|
Chris@0
|
1632 }
|
Chris@0
|
1633 }
|
Chris@0
|
1634
|
Chris@0
|
1635 /**
|
Chris@0
|
1636 * Alter entity renderable values before cache checking in drupal_render().
|
Chris@0
|
1637 *
|
Chris@0
|
1638 * Invoked for a specific entity type.
|
Chris@0
|
1639 *
|
Chris@0
|
1640 * The values in the #cache key of the renderable array are used to determine if
|
Chris@0
|
1641 * a cache entry exists for the entity's rendered output. Ideally only values
|
Chris@0
|
1642 * that pertain to caching should be altered in this hook.
|
Chris@0
|
1643 *
|
Chris@0
|
1644 * @param array &$build
|
Chris@0
|
1645 * A renderable array containing the entity's caching and view mode values.
|
Chris@0
|
1646 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
1647 * The entity that is being viewed.
|
Chris@0
|
1648 * @param string $view_mode
|
Chris@0
|
1649 * The view_mode that is to be used to display the entity.
|
Chris@0
|
1650 *
|
Chris@16
|
1651 * @see \Drupal\Core\Render\RendererInterface::render()
|
Chris@0
|
1652 * @see \Drupal\Core\Entity\EntityViewBuilder
|
Chris@0
|
1653 * @see hook_entity_build_defaults_alter()
|
Chris@0
|
1654 *
|
Chris@0
|
1655 * @ingroup entity_crud
|
Chris@0
|
1656 */
|
Chris@0
|
1657 function hook_ENTITY_TYPE_build_defaults_alter(array &$build, \Drupal\Core\Entity\EntityInterface $entity, $view_mode) {
|
Chris@0
|
1658
|
Chris@0
|
1659 }
|
Chris@0
|
1660
|
Chris@0
|
1661 /**
|
Chris@0
|
1662 * Alter entity renderable values before cache checking in drupal_render().
|
Chris@0
|
1663 *
|
Chris@0
|
1664 * The values in the #cache key of the renderable array are used to determine if
|
Chris@0
|
1665 * a cache entry exists for the entity's rendered output. Ideally only values
|
Chris@0
|
1666 * that pertain to caching should be altered in this hook.
|
Chris@0
|
1667 *
|
Chris@0
|
1668 * @param array &$build
|
Chris@0
|
1669 * A renderable array containing the entity's caching and view mode values.
|
Chris@0
|
1670 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
1671 * The entity that is being viewed.
|
Chris@0
|
1672 * @param string $view_mode
|
Chris@0
|
1673 * The view_mode that is to be used to display the entity.
|
Chris@0
|
1674 *
|
Chris@16
|
1675 * @see \Drupal\Core\Render\RendererInterface::render()
|
Chris@0
|
1676 * @see \Drupal\Core\Entity\EntityViewBuilder
|
Chris@0
|
1677 * @see hook_ENTITY_TYPE_build_defaults_alter()
|
Chris@0
|
1678 *
|
Chris@0
|
1679 * @ingroup entity_crud
|
Chris@0
|
1680 */
|
Chris@0
|
1681 function hook_entity_build_defaults_alter(array &$build, \Drupal\Core\Entity\EntityInterface $entity, $view_mode) {
|
Chris@0
|
1682
|
Chris@0
|
1683 }
|
Chris@0
|
1684
|
Chris@0
|
1685 /**
|
Chris@0
|
1686 * Alter the settings used for displaying an entity.
|
Chris@0
|
1687 *
|
Chris@0
|
1688 * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
|
Chris@0
|
1689 * The entity view display that will be used to display the entity
|
Chris@0
|
1690 * components.
|
Chris@0
|
1691 * @param array $context
|
Chris@0
|
1692 * An associative array containing:
|
Chris@0
|
1693 * - entity_type: The entity type, e.g., 'node' or 'user'.
|
Chris@0
|
1694 * - bundle: The bundle, e.g., 'page' or 'article'.
|
Chris@0
|
1695 * - view_mode: The view mode, e.g., 'full', 'teaser', etc.
|
Chris@0
|
1696 *
|
Chris@0
|
1697 * @ingroup entity_crud
|
Chris@0
|
1698 */
|
Chris@0
|
1699 function hook_entity_view_display_alter(\Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, array $context) {
|
Chris@0
|
1700 // Leave field labels out of the search index.
|
Chris@0
|
1701 if ($context['entity_type'] == 'node' && $context['view_mode'] == 'search_index') {
|
Chris@0
|
1702 foreach ($display->getComponents() as $name => $options) {
|
Chris@0
|
1703 if (isset($options['label'])) {
|
Chris@0
|
1704 $options['label'] = 'hidden';
|
Chris@0
|
1705 $display->setComponent($name, $options);
|
Chris@0
|
1706 }
|
Chris@0
|
1707 }
|
Chris@0
|
1708 }
|
Chris@0
|
1709 }
|
Chris@0
|
1710
|
Chris@0
|
1711 /**
|
Chris@0
|
1712 * Alter the render array generated by an EntityDisplay for an entity.
|
Chris@0
|
1713 *
|
Chris@0
|
1714 * @param array $build
|
Chris@0
|
1715 * The renderable array generated by the EntityDisplay.
|
Chris@0
|
1716 * @param array $context
|
Chris@0
|
1717 * An associative array containing:
|
Chris@0
|
1718 * - entity: The entity being rendered.
|
Chris@0
|
1719 * - view_mode: The view mode; for example, 'full' or 'teaser'.
|
Chris@0
|
1720 * - display: The EntityDisplay holding the display options.
|
Chris@0
|
1721 *
|
Chris@0
|
1722 * @ingroup entity_crud
|
Chris@0
|
1723 */
|
Chris@0
|
1724 function hook_entity_display_build_alter(&$build, $context) {
|
Chris@0
|
1725 // Append RDF term mappings on displayed taxonomy links.
|
Chris@0
|
1726 foreach (Element::children($build) as $field_name) {
|
Chris@0
|
1727 $element = &$build[$field_name];
|
Chris@0
|
1728 if ($element['#field_type'] == 'entity_reference' && $element['#formatter'] == 'entity_reference_label') {
|
Chris@0
|
1729 foreach ($element['#items'] as $delta => $item) {
|
Chris@0
|
1730 $term = $item->entity;
|
Chris@0
|
1731 if (!empty($term->rdf_mapping['rdftype'])) {
|
Chris@0
|
1732 $element[$delta]['#options']['attributes']['typeof'] = $term->rdf_mapping['rdftype'];
|
Chris@0
|
1733 }
|
Chris@0
|
1734 if (!empty($term->rdf_mapping['name']['predicates'])) {
|
Chris@0
|
1735 $element[$delta]['#options']['attributes']['property'] = $term->rdf_mapping['name']['predicates'];
|
Chris@0
|
1736 }
|
Chris@0
|
1737 }
|
Chris@0
|
1738 }
|
Chris@0
|
1739 }
|
Chris@0
|
1740 }
|
Chris@0
|
1741
|
Chris@0
|
1742 /**
|
Chris@0
|
1743 * Acts on an entity object about to be shown on an entity form.
|
Chris@0
|
1744 *
|
Chris@0
|
1745 * This can be typically used to pre-fill entity values or change the form state
|
Chris@0
|
1746 * before the entity form is built. It is invoked just once when first building
|
Chris@0
|
1747 * the entity form. Rebuilds will not trigger a new invocation.
|
Chris@0
|
1748 *
|
Chris@0
|
1749 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
1750 * The entity that is about to be shown on the form.
|
Chris@0
|
1751 * @param $operation
|
Chris@0
|
1752 * The current operation.
|
Chris@0
|
1753 * @param \Drupal\Core\Form\FormStateInterface $form_state
|
Chris@0
|
1754 * The current state of the form.
|
Chris@0
|
1755 *
|
Chris@0
|
1756 * @see \Drupal\Core\Entity\EntityForm::prepareEntity()
|
Chris@0
|
1757 * @see hook_ENTITY_TYPE_prepare_form()
|
Chris@0
|
1758 *
|
Chris@0
|
1759 * @ingroup entity_crud
|
Chris@0
|
1760 */
|
Chris@0
|
1761 function hook_entity_prepare_form(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Form\FormStateInterface $form_state) {
|
Chris@0
|
1762 if ($operation == 'edit') {
|
Chris@0
|
1763 $entity->label->value = 'Altered label';
|
Chris@0
|
1764 $form_state->set('label_altered', TRUE);
|
Chris@0
|
1765 }
|
Chris@0
|
1766 }
|
Chris@0
|
1767
|
Chris@0
|
1768 /**
|
Chris@0
|
1769 * Acts on a particular type of entity object about to be in an entity form.
|
Chris@0
|
1770 *
|
Chris@0
|
1771 * This can be typically used to pre-fill entity values or change the form state
|
Chris@0
|
1772 * before the entity form is built. It is invoked just once when first building
|
Chris@0
|
1773 * the entity form. Rebuilds will not trigger a new invocation.
|
Chris@0
|
1774 *
|
Chris@0
|
1775 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
1776 * The entity that is about to be shown on the form.
|
Chris@0
|
1777 * @param $operation
|
Chris@0
|
1778 * The current operation.
|
Chris@0
|
1779 * @param \Drupal\Core\Form\FormStateInterface $form_state
|
Chris@0
|
1780 * The current state of the form.
|
Chris@0
|
1781 *
|
Chris@0
|
1782 * @see \Drupal\Core\Entity\EntityForm::prepareEntity()
|
Chris@0
|
1783 * @see hook_entity_prepare_form()
|
Chris@0
|
1784 *
|
Chris@0
|
1785 * @ingroup entity_crud
|
Chris@0
|
1786 */
|
Chris@0
|
1787 function hook_ENTITY_TYPE_prepare_form(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Form\FormStateInterface $form_state) {
|
Chris@0
|
1788 if ($operation == 'edit') {
|
Chris@0
|
1789 $entity->label->value = 'Altered label';
|
Chris@0
|
1790 $form_state->set('label_altered', TRUE);
|
Chris@0
|
1791 }
|
Chris@0
|
1792 }
|
Chris@0
|
1793
|
Chris@0
|
1794 /**
|
Chris@0
|
1795 * Alter the settings used for displaying an entity form.
|
Chris@0
|
1796 *
|
Chris@0
|
1797 * @param \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display
|
Chris@0
|
1798 * The entity_form_display object that will be used to display the entity form
|
Chris@0
|
1799 * components.
|
Chris@0
|
1800 * @param array $context
|
Chris@0
|
1801 * An associative array containing:
|
Chris@0
|
1802 * - entity_type: The entity type, e.g., 'node' or 'user'.
|
Chris@0
|
1803 * - bundle: The bundle, e.g., 'page' or 'article'.
|
Chris@0
|
1804 * - form_mode: The form mode; e.g., 'default', 'profile', 'register', etc.
|
Chris@0
|
1805 *
|
Chris@0
|
1806 * @ingroup entity_crud
|
Chris@0
|
1807 */
|
Chris@0
|
1808 function hook_entity_form_display_alter(\Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display, array $context) {
|
Chris@0
|
1809 // Hide the 'user_picture' field from the register form.
|
Chris@0
|
1810 if ($context['entity_type'] == 'user' && $context['form_mode'] == 'register') {
|
Chris@0
|
1811 $form_display->setComponent('user_picture', [
|
Chris@0
|
1812 'region' => 'hidden',
|
Chris@0
|
1813 ]);
|
Chris@0
|
1814 }
|
Chris@0
|
1815 }
|
Chris@0
|
1816
|
Chris@0
|
1817 /**
|
Chris@0
|
1818 * Provides custom base field definitions for a content entity type.
|
Chris@0
|
1819 *
|
Chris@0
|
1820 * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
Chris@0
|
1821 * The entity type definition.
|
Chris@0
|
1822 *
|
Chris@0
|
1823 * @return \Drupal\Core\Field\FieldDefinitionInterface[]
|
Chris@0
|
1824 * An array of field definitions, keyed by field name.
|
Chris@0
|
1825 *
|
Chris@0
|
1826 * @see hook_entity_base_field_info_alter()
|
Chris@0
|
1827 * @see hook_entity_bundle_field_info()
|
Chris@0
|
1828 * @see hook_entity_bundle_field_info_alter()
|
Chris@0
|
1829 * @see \Drupal\Core\Field\FieldDefinitionInterface
|
Chris@18
|
1830 * @see \Drupal\Core\Entity\EntityFieldManagerInterface::getFieldDefinitions()
|
Chris@0
|
1831 */
|
Chris@0
|
1832 function hook_entity_base_field_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type) {
|
Chris@0
|
1833 if ($entity_type->id() == 'node') {
|
Chris@0
|
1834 $fields = [];
|
Chris@0
|
1835 $fields['mymodule_text'] = BaseFieldDefinition::create('string')
|
Chris@0
|
1836 ->setLabel(t('The text'))
|
Chris@0
|
1837 ->setDescription(t('A text property added by mymodule.'))
|
Chris@0
|
1838 ->setComputed(TRUE)
|
Chris@0
|
1839 ->setClass('\Drupal\mymodule\EntityComputedText');
|
Chris@0
|
1840
|
Chris@0
|
1841 return $fields;
|
Chris@0
|
1842 }
|
Chris@0
|
1843 }
|
Chris@0
|
1844
|
Chris@0
|
1845 /**
|
Chris@0
|
1846 * Alter base field definitions for a content entity type.
|
Chris@0
|
1847 *
|
Chris@0
|
1848 * @param \Drupal\Core\Field\FieldDefinitionInterface[] $fields
|
Chris@0
|
1849 * The array of base field definitions for the entity type.
|
Chris@0
|
1850 * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
Chris@0
|
1851 * The entity type definition.
|
Chris@0
|
1852 *
|
Chris@0
|
1853 * @see hook_entity_base_field_info()
|
Chris@0
|
1854 * @see hook_entity_bundle_field_info()
|
Chris@0
|
1855 * @see hook_entity_bundle_field_info_alter()
|
Chris@0
|
1856 *
|
Chris@0
|
1857 * @todo WARNING: This hook will be changed in
|
Chris@0
|
1858 * https://www.drupal.org/node/2346329.
|
Chris@0
|
1859 */
|
Chris@0
|
1860 function hook_entity_base_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type) {
|
Chris@0
|
1861 // Alter the mymodule_text field to use a custom class.
|
Chris@0
|
1862 if ($entity_type->id() == 'node' && !empty($fields['mymodule_text'])) {
|
Chris@0
|
1863 $fields['mymodule_text']->setClass('\Drupal\anothermodule\EntityComputedText');
|
Chris@0
|
1864 }
|
Chris@0
|
1865 }
|
Chris@0
|
1866
|
Chris@0
|
1867 /**
|
Chris@0
|
1868 * Provides field definitions for a specific bundle within an entity type.
|
Chris@0
|
1869 *
|
Chris@0
|
1870 * Bundle fields either have to override an existing base field, or need to
|
Chris@0
|
1871 * provide a field storage definition via hook_entity_field_storage_info()
|
Chris@0
|
1872 * unless they are computed.
|
Chris@0
|
1873 *
|
Chris@0
|
1874 * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
Chris@0
|
1875 * The entity type definition.
|
Chris@0
|
1876 * @param string $bundle
|
Chris@0
|
1877 * The bundle.
|
Chris@0
|
1878 * @param \Drupal\Core\Field\FieldDefinitionInterface[] $base_field_definitions
|
Chris@0
|
1879 * The list of base field definitions for the entity type.
|
Chris@0
|
1880 *
|
Chris@0
|
1881 * @return \Drupal\Core\Field\FieldDefinitionInterface[]
|
Chris@0
|
1882 * An array of bundle field definitions, keyed by field name.
|
Chris@0
|
1883 *
|
Chris@0
|
1884 * @see hook_entity_base_field_info()
|
Chris@0
|
1885 * @see hook_entity_base_field_info_alter()
|
Chris@0
|
1886 * @see hook_entity_field_storage_info()
|
Chris@0
|
1887 * @see hook_entity_field_storage_info_alter()
|
Chris@0
|
1888 * @see hook_entity_bundle_field_info_alter()
|
Chris@0
|
1889 * @see \Drupal\Core\Field\FieldDefinitionInterface
|
Chris@18
|
1890 * @see \Drupal\Core\Field\FieldDefinition
|
Chris@18
|
1891 * @see \Drupal\Core\Entity\EntityFieldManagerInterface::getFieldDefinitions()
|
Chris@0
|
1892 *
|
Chris@0
|
1893 * @todo WARNING: This hook will be changed in
|
Chris@0
|
1894 * https://www.drupal.org/node/2346347.
|
Chris@0
|
1895 */
|
Chris@0
|
1896 function hook_entity_bundle_field_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
|
Chris@0
|
1897 // Add a property only to nodes of the 'article' bundle.
|
Chris@0
|
1898 if ($entity_type->id() == 'node' && $bundle == 'article') {
|
Chris@0
|
1899 $fields = [];
|
Chris@18
|
1900 $storage_definitions = mymodule_entity_field_storage_info($entity_type);
|
Chris@18
|
1901 $fields['mymodule_bundle_field'] = FieldDefinition::createFromFieldStorageDefinition($storage_definitions['mymodule_bundle_field'])
|
Chris@18
|
1902 ->setLabel(t('Bundle Field'));
|
Chris@0
|
1903 return $fields;
|
Chris@0
|
1904 }
|
Chris@18
|
1905
|
Chris@0
|
1906 }
|
Chris@0
|
1907
|
Chris@0
|
1908 /**
|
Chris@0
|
1909 * Alter bundle field definitions.
|
Chris@0
|
1910 *
|
Chris@0
|
1911 * @param \Drupal\Core\Field\FieldDefinitionInterface[] $fields
|
Chris@0
|
1912 * The array of bundle field definitions.
|
Chris@0
|
1913 * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
Chris@0
|
1914 * The entity type definition.
|
Chris@0
|
1915 * @param string $bundle
|
Chris@0
|
1916 * The bundle.
|
Chris@0
|
1917 *
|
Chris@0
|
1918 * @see hook_entity_base_field_info()
|
Chris@0
|
1919 * @see hook_entity_base_field_info_alter()
|
Chris@0
|
1920 * @see hook_entity_bundle_field_info()
|
Chris@0
|
1921 *
|
Chris@0
|
1922 * @todo WARNING: This hook will be changed in
|
Chris@0
|
1923 * https://www.drupal.org/node/2346347.
|
Chris@0
|
1924 */
|
Chris@0
|
1925 function hook_entity_bundle_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle) {
|
Chris@0
|
1926 if ($entity_type->id() == 'node' && $bundle == 'article' && !empty($fields['mymodule_text'])) {
|
Chris@0
|
1927 // Alter the mymodule_text field to use a custom class.
|
Chris@0
|
1928 $fields['mymodule_text']->setClass('\Drupal\anothermodule\EntityComputedText');
|
Chris@0
|
1929 }
|
Chris@0
|
1930 }
|
Chris@0
|
1931
|
Chris@0
|
1932 /**
|
Chris@0
|
1933 * Provides field storage definitions for a content entity type.
|
Chris@0
|
1934 *
|
Chris@0
|
1935 * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
Chris@0
|
1936 * The entity type definition.
|
Chris@0
|
1937 *
|
Chris@0
|
1938 * @return \Drupal\Core\Field\FieldStorageDefinitionInterface[]
|
Chris@0
|
1939 * An array of field storage definitions, keyed by field name.
|
Chris@0
|
1940 *
|
Chris@0
|
1941 * @see hook_entity_field_storage_info_alter()
|
Chris@0
|
1942 * @see \Drupal\Core\Field\FieldStorageDefinitionInterface
|
Chris@0
|
1943 * @see \Drupal\Core\Entity\EntityManagerInterface::getFieldStorageDefinitions()
|
Chris@0
|
1944 */
|
Chris@0
|
1945 function hook_entity_field_storage_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type) {
|
Chris@0
|
1946 if (\Drupal::entityManager()->getStorage($entity_type->id()) instanceof DynamicallyFieldableEntityStorageInterface) {
|
Chris@0
|
1947 // Query by filtering on the ID as this is more efficient than filtering
|
Chris@0
|
1948 // on the entity_type property directly.
|
Chris@0
|
1949 $ids = \Drupal::entityQuery('field_storage_config')
|
Chris@0
|
1950 ->condition('id', $entity_type->id() . '.', 'STARTS_WITH')
|
Chris@0
|
1951 ->execute();
|
Chris@0
|
1952 // Fetch all fields and key them by field name.
|
Chris@0
|
1953 $field_storages = FieldStorageConfig::loadMultiple($ids);
|
Chris@0
|
1954 $result = [];
|
Chris@0
|
1955 foreach ($field_storages as $field_storage) {
|
Chris@0
|
1956 $result[$field_storage->getName()] = $field_storage;
|
Chris@0
|
1957 }
|
Chris@0
|
1958
|
Chris@0
|
1959 return $result;
|
Chris@0
|
1960 }
|
Chris@0
|
1961 }
|
Chris@0
|
1962
|
Chris@0
|
1963 /**
|
Chris@0
|
1964 * Alter field storage definitions for a content entity type.
|
Chris@0
|
1965 *
|
Chris@0
|
1966 * @param \Drupal\Core\Field\FieldStorageDefinitionInterface[] $fields
|
Chris@0
|
1967 * The array of field storage definitions for the entity type.
|
Chris@0
|
1968 * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
Chris@0
|
1969 * The entity type definition.
|
Chris@0
|
1970 *
|
Chris@0
|
1971 * @see hook_entity_field_storage_info()
|
Chris@0
|
1972 */
|
Chris@0
|
1973 function hook_entity_field_storage_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type) {
|
Chris@0
|
1974 // Alter the max_length setting.
|
Chris@0
|
1975 if ($entity_type->id() == 'node' && !empty($fields['mymodule_text'])) {
|
Chris@0
|
1976 $fields['mymodule_text']->setSetting('max_length', 128);
|
Chris@0
|
1977 }
|
Chris@0
|
1978 }
|
Chris@0
|
1979
|
Chris@0
|
1980 /**
|
Chris@0
|
1981 * Declares entity operations.
|
Chris@0
|
1982 *
|
Chris@0
|
1983 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
1984 * The entity on which the linked operations will be performed.
|
Chris@0
|
1985 *
|
Chris@0
|
1986 * @return array
|
Chris@0
|
1987 * An operations array as returned by
|
Chris@0
|
1988 * EntityListBuilderInterface::getOperations().
|
Chris@0
|
1989 *
|
Chris@0
|
1990 * @see \Drupal\Core\Entity\EntityListBuilderInterface::getOperations()
|
Chris@0
|
1991 */
|
Chris@0
|
1992 function hook_entity_operation(\Drupal\Core\Entity\EntityInterface $entity) {
|
Chris@0
|
1993 $operations = [];
|
Chris@0
|
1994 $operations['translate'] = [
|
Chris@0
|
1995 'title' => t('Translate'),
|
Chris@0
|
1996 'url' => \Drupal\Core\Url::fromRoute('foo_module.entity.translate'),
|
Chris@0
|
1997 'weight' => 50,
|
Chris@0
|
1998 ];
|
Chris@0
|
1999
|
Chris@0
|
2000 return $operations;
|
Chris@0
|
2001 }
|
Chris@0
|
2002
|
Chris@0
|
2003 /**
|
Chris@0
|
2004 * Alter entity operations.
|
Chris@0
|
2005 *
|
Chris@0
|
2006 * @param array $operations
|
Chris@0
|
2007 * Operations array as returned by
|
Chris@0
|
2008 * \Drupal\Core\Entity\EntityListBuilderInterface::getOperations().
|
Chris@0
|
2009 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
2010 * The entity on which the linked operations will be performed.
|
Chris@0
|
2011 */
|
Chris@0
|
2012 function hook_entity_operation_alter(array &$operations, \Drupal\Core\Entity\EntityInterface $entity) {
|
Chris@0
|
2013 // Alter the title and weight.
|
Chris@0
|
2014 $operations['translate']['title'] = t('Translate @entity_type', [
|
Chris@0
|
2015 '@entity_type' => $entity->getEntityTypeId(),
|
Chris@0
|
2016 ]);
|
Chris@0
|
2017 $operations['translate']['weight'] = 99;
|
Chris@0
|
2018 }
|
Chris@0
|
2019
|
Chris@0
|
2020 /**
|
Chris@0
|
2021 * Control access to fields.
|
Chris@0
|
2022 *
|
Chris@0
|
2023 * This hook is invoked from
|
Chris@0
|
2024 * \Drupal\Core\Entity\EntityAccessControlHandler::fieldAccess() to let modules
|
Chris@0
|
2025 * grant or deny operations on fields.
|
Chris@0
|
2026 *
|
Chris@0
|
2027 * @param string $operation
|
Chris@0
|
2028 * The operation to be performed. See
|
Chris@0
|
2029 * \Drupal\Core\Entity\EntityAccessControlHandlerInterface::fieldAccess()
|
Chris@0
|
2030 * for possible values.
|
Chris@0
|
2031 * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
|
Chris@0
|
2032 * The field definition.
|
Chris@0
|
2033 * @param \Drupal\Core\Session\AccountInterface $account
|
Chris@0
|
2034 * The user account to check.
|
Chris@0
|
2035 * @param \Drupal\Core\Field\FieldItemListInterface $items
|
Chris@16
|
2036 * (optional) The entity field object for which to check access, or NULL if
|
Chris@16
|
2037 * access is checked for the field definition, without any specific value
|
Chris@16
|
2038 * available. Defaults to NULL.
|
Chris@0
|
2039 *
|
Chris@0
|
2040 * @return \Drupal\Core\Access\AccessResultInterface
|
Chris@0
|
2041 * The access result.
|
Chris@0
|
2042 *
|
Chris@0
|
2043 * @see \Drupal\Core\Entity\EntityAccessControlHandlerInterface::fieldAccess()
|
Chris@0
|
2044 */
|
Chris@0
|
2045 function hook_entity_field_access($operation, \Drupal\Core\Field\FieldDefinitionInterface $field_definition, \Drupal\Core\Session\AccountInterface $account, \Drupal\Core\Field\FieldItemListInterface $items = NULL) {
|
Chris@0
|
2046 if ($field_definition->getName() == 'field_of_interest' && $operation == 'edit') {
|
Chris@0
|
2047 return AccessResult::allowedIfHasPermission($account, 'update field of interest');
|
Chris@0
|
2048 }
|
Chris@0
|
2049 return AccessResult::neutral();
|
Chris@0
|
2050 }
|
Chris@0
|
2051
|
Chris@0
|
2052 /**
|
Chris@0
|
2053 * Alter the default access behavior for a given field.
|
Chris@0
|
2054 *
|
Chris@0
|
2055 * Use this hook to override access grants from another module. Note that the
|
Chris@0
|
2056 * original default access flag is masked under the ':default' key.
|
Chris@0
|
2057 *
|
Chris@0
|
2058 * @param \Drupal\Core\Access\AccessResultInterface[] $grants
|
Chris@0
|
2059 * An array of grants gathered by hook_entity_field_access(). The array is
|
Chris@0
|
2060 * keyed by the module that defines the field's access control; the values are
|
Chris@0
|
2061 * grant responses for each module (\Drupal\Core\Access\AccessResult).
|
Chris@0
|
2062 * @param array $context
|
Chris@0
|
2063 * Context array on the performed operation with the following keys:
|
Chris@0
|
2064 * - operation: The operation to be performed (string).
|
Chris@0
|
2065 * - field_definition: The field definition object
|
Chris@0
|
2066 * (\Drupal\Core\Field\FieldDefinitionInterface)
|
Chris@0
|
2067 * - account: The user account to check access for
|
Chris@0
|
2068 * (Drupal\user\Entity\User).
|
Chris@0
|
2069 * - items: (optional) The entity field items
|
Chris@0
|
2070 * (\Drupal\Core\Field\FieldItemListInterface).
|
Chris@0
|
2071 */
|
Chris@0
|
2072 function hook_entity_field_access_alter(array &$grants, array $context) {
|
Chris@0
|
2073 /** @var \Drupal\Core\Field\FieldDefinitionInterface $field_definition */
|
Chris@0
|
2074 $field_definition = $context['field_definition'];
|
Chris@0
|
2075 if ($field_definition->getName() == 'field_of_interest' && $grants['node']->isForbidden()) {
|
Chris@0
|
2076 // Override node module's restriction to no opinion (neither allowed nor
|
Chris@0
|
2077 // forbidden). We don't want to provide our own access hook, we only want to
|
Chris@0
|
2078 // take out node module's part in the access handling of this field. We also
|
Chris@0
|
2079 // don't want to switch node module's grant to
|
Chris@0
|
2080 // AccessResultInterface::isAllowed() , because the grants of other modules
|
Chris@0
|
2081 // should still decide on their own if this field is accessible or not
|
Chris@0
|
2082 $grants['node'] = AccessResult::neutral()->inheritCacheability($grants['node']);
|
Chris@0
|
2083 }
|
Chris@0
|
2084 }
|
Chris@0
|
2085
|
Chris@0
|
2086 /**
|
Chris@0
|
2087 * Acts when initializing a fieldable entity object.
|
Chris@0
|
2088 *
|
Chris@0
|
2089 * This hook runs after a new entity object or a new entity translation object
|
Chris@0
|
2090 * has just been instantiated. It can be used to set initial values, e.g. to
|
Chris@0
|
2091 * provide defaults.
|
Chris@0
|
2092 *
|
Chris@0
|
2093 * @param \Drupal\Core\Entity\FieldableEntityInterface $entity
|
Chris@0
|
2094 * The entity object.
|
Chris@0
|
2095 *
|
Chris@0
|
2096 * @ingroup entity_crud
|
Chris@0
|
2097 * @see hook_ENTITY_TYPE_field_values_init()
|
Chris@0
|
2098 */
|
Chris@0
|
2099 function hook_entity_field_values_init(\Drupal\Core\Entity\FieldableEntityInterface $entity) {
|
Chris@0
|
2100 if ($entity instanceof \Drupal\Core\Entity\ContentEntityInterface && !$entity->foo->value) {
|
Chris@0
|
2101 $entity->foo->value = 'some_initial_value';
|
Chris@0
|
2102 }
|
Chris@0
|
2103 }
|
Chris@0
|
2104
|
Chris@0
|
2105 /**
|
Chris@0
|
2106 * Acts when initializing a fieldable entity object.
|
Chris@0
|
2107 *
|
Chris@0
|
2108 * This hook runs after a new entity object or a new entity translation object
|
Chris@0
|
2109 * has just been instantiated. It can be used to set initial values, e.g. to
|
Chris@0
|
2110 * provide defaults.
|
Chris@0
|
2111 *
|
Chris@0
|
2112 * @param \Drupal\Core\Entity\FieldableEntityInterface $entity
|
Chris@0
|
2113 * The entity object.
|
Chris@0
|
2114 *
|
Chris@0
|
2115 * @ingroup entity_crud
|
Chris@0
|
2116 * @see hook_entity_field_values_init()
|
Chris@0
|
2117 */
|
Chris@0
|
2118 function hook_ENTITY_TYPE_field_values_init(\Drupal\Core\Entity\FieldableEntityInterface $entity) {
|
Chris@0
|
2119 if (!$entity->foo->value) {
|
Chris@0
|
2120 $entity->foo->value = 'some_initial_value';
|
Chris@0
|
2121 }
|
Chris@0
|
2122 }
|
Chris@0
|
2123
|
Chris@0
|
2124 /**
|
Chris@0
|
2125 * Exposes "pseudo-field" components on content entities.
|
Chris@0
|
2126 *
|
Chris@0
|
2127 * Field UI's "Manage fields" and "Manage display" pages let users re-order
|
Chris@0
|
2128 * fields, but also non-field components. For nodes, these include elements
|
Chris@0
|
2129 * exposed by modules through hook_form_alter(), for instance.
|
Chris@0
|
2130 *
|
Chris@0
|
2131 * Content entities or modules that want to have their components supported
|
Chris@0
|
2132 * should expose them using this hook. The user-defined settings (weight,
|
Chris@0
|
2133 * visible) are automatically applied when entities or entity forms are
|
Chris@0
|
2134 * rendered.
|
Chris@0
|
2135 *
|
Chris@0
|
2136 * @see hook_entity_extra_field_info_alter()
|
Chris@0
|
2137 *
|
Chris@0
|
2138 * @return array
|
Chris@0
|
2139 * The array structure is identical to that of the return value of
|
Chris@0
|
2140 * \Drupal\Core\Entity\EntityFieldManagerInterface::getExtraFields().
|
Chris@0
|
2141 */
|
Chris@0
|
2142 function hook_entity_extra_field_info() {
|
Chris@0
|
2143 $extra = [];
|
Chris@0
|
2144 $module_language_enabled = \Drupal::moduleHandler()->moduleExists('language');
|
Chris@0
|
2145 $description = t('Node module element');
|
Chris@0
|
2146
|
Chris@0
|
2147 foreach (NodeType::loadMultiple() as $bundle) {
|
Chris@0
|
2148
|
Chris@0
|
2149 // Add also the 'language' select if Language module is enabled and the
|
Chris@0
|
2150 // bundle has multilingual support.
|
Chris@0
|
2151 // Visibility of the ordering of the language selector is the same as on the
|
Chris@0
|
2152 // node/add form.
|
Chris@0
|
2153 if ($module_language_enabled) {
|
Chris@0
|
2154 $configuration = ContentLanguageSettings::loadByEntityTypeBundle('node', $bundle->id());
|
Chris@0
|
2155 if ($configuration->isLanguageAlterable()) {
|
Chris@0
|
2156 $extra['node'][$bundle->id()]['form']['language'] = [
|
Chris@0
|
2157 'label' => t('Language'),
|
Chris@0
|
2158 'description' => $description,
|
Chris@0
|
2159 'weight' => 0,
|
Chris@0
|
2160 ];
|
Chris@0
|
2161 }
|
Chris@0
|
2162 }
|
Chris@0
|
2163 $extra['node'][$bundle->id()]['display']['language'] = [
|
Chris@0
|
2164 'label' => t('Language'),
|
Chris@0
|
2165 'description' => $description,
|
Chris@0
|
2166 'weight' => 0,
|
Chris@0
|
2167 'visible' => FALSE,
|
Chris@0
|
2168 ];
|
Chris@0
|
2169 }
|
Chris@0
|
2170
|
Chris@0
|
2171 return $extra;
|
Chris@0
|
2172 }
|
Chris@0
|
2173
|
Chris@0
|
2174 /**
|
Chris@0
|
2175 * Alter "pseudo-field" components on content entities.
|
Chris@0
|
2176 *
|
Chris@0
|
2177 * @param array $info
|
Chris@0
|
2178 * The array structure is identical to that of the return value of
|
Chris@0
|
2179 * \Drupal\Core\Entity\EntityManagerInterface::getExtraFields().
|
Chris@0
|
2180 *
|
Chris@0
|
2181 * @see hook_entity_extra_field_info()
|
Chris@0
|
2182 */
|
Chris@0
|
2183 function hook_entity_extra_field_info_alter(&$info) {
|
Chris@0
|
2184 // Force node title to always be at the top of the list by default.
|
Chris@0
|
2185 foreach (NodeType::loadMultiple() as $bundle) {
|
Chris@0
|
2186 if (isset($info['node'][$bundle->id()]['form']['title'])) {
|
Chris@0
|
2187 $info['node'][$bundle->id()]['form']['title']['weight'] = -20;
|
Chris@0
|
2188 }
|
Chris@0
|
2189 }
|
Chris@0
|
2190 }
|
Chris@0
|
2191
|
Chris@0
|
2192 /**
|
Chris@0
|
2193 * @} End of "addtogroup hooks".
|
Chris@0
|
2194 */
|