-
Notifications
You must be signed in to change notification settings - Fork 3
/
localgov_publications.module
363 lines (317 loc) · 12.6 KB
/
localgov_publications.module
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
<?php
/**
* @file
* Module file for the LocalGov Publications module.
*/
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Config\Entity\ConfigDependencyManager;
use Drupal\Core\Config\FileStorage;
use Drupal\Core\Config\InstallStorage;
use Drupal\Core\Config\StorageInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\block\Entity\Block;
use Drupal\localgov_roles\RolesHelper;
use Drupal\node\Entity\Node;
use Drupal\node\NodeInterface;
/**
* Implements hook_theme().
*/
function localgov_publications_theme($existing, $type, $theme, $path): array {
return [
'book_navigation__publication' => [
'template' => 'book-navigation--publication',
'base hook' => 'book_navigation__publication',
],
'localgov_publication_page_header_block' => [
'variables' => [
'title' => '',
'node_title' => '',
'published_date' => NULL,
'last_updated_date' => NULL,
],
],
'paragraph__localgov_publications_banner' => [
'template' => 'paragraph--localgov-publications-banner',
'base hook' => 'paragraph',
],
'media__document__publication' => [
'template' => 'media--document--publication',
'base hook' => 'media',
],
'field__localgov_publication' => [
'template' => 'publication-html-reference',
'base hook' => 'field',
],
];
}
/**
* Implements hook_localgov_role_default().
*/
function localgov_publications_localgov_roles_default(): array {
return [
RolesHelper::EDITOR_ROLE => [
'add content to books',
'administer book outlines',
'create new books',
'create localgov_publication_page content',
'create localgov_publication_cover_page content',
'delete any localgov_publication_page content',
'delete any localgov_publication_cover_page content',
'delete localgov_publication_page revisions',
'delete localgov_publication_cover_page revisions',
'delete own localgov_publication_page content',
'delete own localgov_publication_cover_page content',
'edit any localgov_publication_page content',
'edit any localgov_publication_cover_page content',
'edit own localgov_publication_page content',
'edit own localgov_publication_cover_page content',
'revert localgov_publication_page revisions',
'revert localgov_publication_cover_page revisions',
'view localgov_publication_page revisions',
'view localgov_publication_cover_page revisions',
],
];
}
/**
* Is the given type one of the publication node types?
*/
function localgov_publications_is_publication_type(string $type): bool {
return $type === 'localgov_publication_page' || $type === 'localgov_publication_cover_page';
}
/**
* Implements hook_theme_suggestions_HOOK().
*/
function localgov_publications_theme_suggestions_book_navigation(array $variables): array {
$suggestions = [];
// Only add suggestion on publication pages and publication cover pages.
$node = \Drupal::routeMatch()->getParameter('node');
if (localgov_publications_is_publication_type($node->getType())) {
$suggestions[] = $variables['theme_hook_original'] . '__' . 'publication';
}
return $suggestions;
}
/**
* Implements hook_block_access().
*/
function localgov_publications_block_access(Block $block, $operation, AccountInterface $account) {
if ($block->getPluginId() == 'localgov_page_header_block' && $operation == 'view') {
$node = \Drupal::routeMatch()->getParameter('node');
if ($node instanceof NodeInterface && localgov_publications_is_publication_type($node->getType())) {
return AccessResult::forbiddenIf(TRUE)->addCacheableDependency($block);
}
}
}
/**
* Implements hook_form_FORM_ID_alter() for book_admin_edit.
*/
function localgov_publications_form_book_admin_edit_alter(&$form, FormStateInterface $form_state, $form_id): void {
// If we're on the route this module uses for this form, change some wording.
$route_name = \Drupal::routeMatch()->getRouteName();
if ($route_name === 'publication.admin_edit') {
$form['save']['#value'] = t('Save publication pages');
}
}
/**
* Implements hook_form_alter().
*/
function localgov_publications_form_alter(&$form, FormStateInterface $form_state, $form_id): void {
$forms_to_alter = [
'node_localgov_publication_cover_page_form',
'node_localgov_publication_cover_page_edit_form',
'node_localgov_publication_page_form',
'node_localgov_publication_page_edit_form',
];
if (!in_array($form_id, $forms_to_alter, TRUE)) {
return;
}
/**
* Get the node from the form object.
* @var \Drupal\Core\Entity\EntityFormInterface $formObject
*/
$formObject = $form_state->getFormObject();
$node = $formObject->getEntity();
// Attach JS.
if ($form['book']['#attached']['library'][0] == 'book/drupal.book') {
unset($form['book']['#attached']['library']);
$form['book']['#attached']['library'][0] = 'localgov_publications/localgov-publications';
}
// Get form state values.
$book_values = $form_state->getValue('book');
// Alter the book outline form title.
$form['book']['#title'] = t('Publication outline');
// Alter the select element.
$form['book']['bid']['#title'] = t('Publication');
// Change "Create new book" to "Create a new publication".
if (isset($form['book']['bid']['#options']['new'])) {
$form['book']['bid']['#options']['new'] = t('- Create a new publication -');
}
$form['book']['bid']['#description'] = t('Your page will be part of the selected publication');
// Alter "No book selected".
if (is_array($book_values)) {
switch ($book_values['bid']) {
case '0':
$form['book']['pid']['#prefix'] = '<div id="edit-book-plid-wrapper"><em>No publication selected.</em>';
break;
case 'new':
case $node->id():
$form['book']['pid']['#prefix'] = '<div id="edit-book-plid-wrapper"><em>This will be the top-level page in this publication.</em>';
break;
default:
$form['book']['pid']['#description'] = t(
'The parent page in the publication. The maximum depth for a publication and all child pages is @maxdepth. Some pages in the selected publication may not be available as parents if selecting them would exceed this limit.',
['@maxdepth' => $form['book']['parent_depth_limit']['#value']],
);
break;
}
}
else {
$form['book']['pid']['#prefix'] = '<div id="edit-book-plid-wrapper"><em>No publication selected.</em>';
}
if ($form_id == 'node_localgov_publication_page_form' || $form_id == 'node_localgov_publication_page_edit_form') {
$form['#validate'][] = 'localgov_publications_validate_node_form';
}
}
/**
* Form validation function.
*
* Ensures that either 'Create a new publication', or an existing publication
* has been chosen from the book field.
*/
function localgov_publications_validate_node_form(&$form, FormStateInterface $form_state): void {
if ($form_state->hasValue('book')) {
$book = $form_state->getValue('book');
if ($book['bid'] === '0') {
$form_state->setErrorByName('book', t("Please choose either 'Create a new publication', or one of your existing publications for this page to be part of."));
}
}
}
/**
* Implements hook_node_links_alter().
*
* If book module has added the "Add child page" link, and we're on a
* publication type page, alter the link, so it creates a
* localgov_publication_page, instead of the default book type.
*/
function localgov_publications_node_links_alter(array &$links, NodeInterface $node, array &$context): void {
if (localgov_publications_is_publication_type($node->getType()) && isset($links['book']['#links']['book_add_child'])) {
$links['book']['#links']['book_add_child']['url'] = Url::fromRoute('node.add', ['node_type' => 'localgov_publication_page'], ['query' => ['parent' => $node->id()]]);
}
}
/**
* Implements hook_preprocess_node().
*/
function localgov_publications_preprocess_node(&$variables): void {
$view_mode = $variables['elements']['#view_mode'];
/** @var \Drupal\node\NodeInterface $node */
$node = $variables['elements']['#node'];
if ($view_mode === 'full' && localgov_publications_is_publication_type($node->getType())) {
$variables['content']['#attached']['library'][] = 'localgov_publications/localgov-publications';
}
}
/**
* Implements hook_modules_installed().
*/
function localgov_publications_modules_installed($modules, $is_syncing) {
if (!$is_syncing && in_array('book', $modules, TRUE)) {
// If book module is being installed, prevent the 'book' node type and its
// dependencies from being installed from its config (or rather, delete it
// -- there's no way to intercept it within the config API).
$extension_path = \Drupal::service('extension.path.resolver')->getPath('module', 'book');
$optional_install_path = $extension_path . '/' . InstallStorage::CONFIG_OPTIONAL_DIRECTORY;
// Get all of book module's optional config.
$storage = new FileStorage($optional_install_path, StorageInterface::DEFAULT_COLLECTION);
$list = $storage->listAll();
$config_to_create = $storage->readMultiple($list);
// Filter this to those config entities that depend on the 'book' node type.
$dependency_manager = new ConfigDependencyManager();
$dependency_manager->setData($config_to_create);
$dependencies = $dependency_manager->getDependentEntities('config', 'node.type.book');
foreach (array_keys($dependencies) as $config_name) {
\Drupal::configFactory()->getEditable($config_name)->delete();
}
\Drupal::configFactory()->getEditable('node.type.book')->delete();
// The mapping of fields to bundles is stored in the key-value store. As we
// removed the content type and its fields on a config level, we also need
// to clear out the book data from here, as it won't be done for us like it
// is when you delete a content type via the UI.
$kvStore = \Drupal::keyValue('entity.definitions.bundle_field_map');
$fieldMap = $kvStore->get('node');
unset($fieldMap['body']['bundles']['book']);
$kvStore->set('node', $fieldMap);
// Clear all caches to ensure there are no references to the Book node left.
drupal_flush_all_caches();
}
}
/**
* Implements hook_module_implements_alter().
*
* Moves our implementations of hook_entity_insert and hook_entity_update to the
* end of the list, so they run after pathauto. If they run before pathauto, we
* don't pick up changes to the URL of cover pages when generating URL aliases
* for the rest of the publication.
*/
function localgov_publications_module_implements_alter(&$implementations, $hook): void {
switch ($hook) {
case 'entity_insert':
case 'entity_update':
$group = $implementations['localgov_publications'];
unset($implementations['localgov_publications']);
$implementations['localgov_publications'] = $group;
break;
}
}
/**
* Implements hook_entity_insert().
*
* NB that we don't implement hook_node_insert to ensure we run after pathauto.
*/
function localgov_publications_entity_insert(EntityInterface $entity): void {
if ($entity instanceof NodeInterface) {
localgov_publications_update_path_aliases($entity);
}
}
/**
* Implements hook_entity_update().
*
* NB that we don't implement hook_node_update to ensure we run after pathauto.
*/
function localgov_publications_entity_update(EntityInterface $entity): void {
if ($entity instanceof NodeInterface) {
localgov_publications_update_path_aliases($entity);
}
}
/**
* Updates the path alias of every page in a publication.
*
* @param \Drupal\node\NodeInterface $node
* Cover page node.
*/
function localgov_publications_update_path_aliases(NodeInterface $node): void {
// Only do anything if we're saving a cover page.
if ($node->getType() !== 'localgov_publication_cover_page') {
return;
}
/** @var \Drupal\book\BookManager $bookManager */
$bookManager = \Drupal::service('book.manager');
/** @var \Drupal\node\NodeInterface[] $publications */
$publications = $node->get('localgov_publication')->referencedEntities();
$publicationPages = [];
foreach ($publications as $publication) {
if (isset($publication->book)) {
// Find the ID of every node in the publication.
$bookPages = $bookManager->bookTreeGetFlat($publication->book);
$publicationPages = array_merge($publicationPages, array_keys($bookPages));
}
}
if (count($publicationPages) === 0) {
return;
}
$pageNodes = Node::loadMultiple($publicationPages);
$pathAutoGenerator = \Drupal::service('pathauto.generator');
foreach ($pageNodes as $pageNode) {
$pathAutoGenerator->updateEntityAlias($pageNode, 'update');
}
}