-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRandomPageController.php
193 lines (168 loc) · 6.74 KB
/
RandomPageController.php
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
<?php
declare(strict_types=1);
namespace Drupal\omnipedia_menu\Controller;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Access\AccessResultInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\omnipedia_core\Service\WikiNodeAccessInterface;
use Drupal\omnipedia_core\Service\WikiNodeResolverInterface;
use Drupal\omnipedia_core\Service\WikiNodeTrackerInterface;
use Drupal\omnipedia_core\Service\WikiNodeViewedInterface;
use Drupal\omnipedia_date\Service\TimelineInterface;
use Drupal\omnipedia_main_page\Service\MainPageResolverInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
/**
* Controller for the 'omnipedia_menu.random_page' route.
*/
class RandomPageController implements ContainerInjectionInterface {
/**
* Controller constructor; saves dependencies.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
* The Drupal entity type manager.
*
* @param \Drupal\omnipedia_main_page\Service\MainPageResolverInterface $mainPageResolver
* The Omnipedia main page resolver service.
*
* @param \Drupal\omnipedia_date\Service\TimelineInterface $timeline
* The Omnipedia timeline service.
*
* @param \Drupal\omnipedia_core\Service\WikiNodeAccessInterface $wikiNodeAccess
* The Omnipedia wiki node access service.
*
* @param \Drupal\omnipedia_core\Service\WikiNodeResolverInterface $wikiNodeResolver
* The Omnipedia wiki node resolver service.
*
* @param \Drupal\omnipedia_core\Service\WikiNodeTrackerInterface $wikiNodeTracker
* The Omnipedia wiki node tracker service.
*
* @param \Drupal\omnipedia_core\Service\WikiNodeViewedInterface $wikiNodeViewed
* The Omnipedia wiki node viewed service.
*/
public function __construct(
protected readonly EntityTypeManagerInterface $entityTypeManager,
protected readonly MainPageResolverInterface $mainPageResolver,
protected readonly TimelineInterface $timeline,
protected readonly WikiNodeAccessInterface $wikiNodeAccess,
protected readonly WikiNodeResolverInterface $wikiNodeResolver,
protected readonly WikiNodeTrackerInterface $wikiNodeTracker,
protected readonly WikiNodeViewedInterface $wikiNodeViewed,
) {}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity_type.manager'),
$container->get('omnipedia_main_page.resolver'),
$container->get('omnipedia.timeline'),
$container->get('omnipedia.wiki_node_access'),
$container->get('omnipedia.wiki_node_resolver'),
$container->get('omnipedia.wiki_node_tracker'),
$container->get('omnipedia.wiki_node_viewed'),
);
}
/**
* Checks access for the route.
*
* @param \Drupal\Core\Session\AccountInterface $account
* Run access checks for this account.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result. Access is granted if $account can access at least one
* wiki node.
*
* @todo Can/should we vary this per wiki date?
*/
public function access(AccountInterface $account): AccessResultInterface {
return AccessResult::allowedIf(
$this->wikiNodeAccess->canUserAccessAnyWikiNode($account),
);
}
/**
* Redirect to a random wiki node with the current date.
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse
* A redirect response object.
*
* @see https://www.php.net/manual/en/function.shuffle.php
* Can we use the built-in PHP \shuffle() function to create a playlist of
* wiki nodes ahead of time rather than the current method of randomization
* at time of invoking this controller?
*/
public function view(): RedirectResponse {
/** @var string */
$currentDate = $this->timeline->getDateFormatted('current', 'storage');
/** @var array */
$nodeData = $this->wikiNodeTracker->getTrackedWikiNodeData();
/** @var \Drupal\node\NodeInterface */
$currentDateMainPage = $this->mainPageResolver->get($currentDate);
/** @var string */
$currentDateMainPageNid = $currentDateMainPage->nid->getString();
// Array of all node IDs (nids) for the current date that the current user
// has access to, including the main page and recently viewed nodes; the
// node entity query applies access checks by default for us. Note that
// \array_values() is needed to ensure the keys are integers and not
// strings.
/** @var array */
$currentDateNids = \array_values(($this->entityTypeManager->getStorage(
'node'
)->getQuery())
->condition('nid', $nodeData['dates'][$currentDate], 'IN')
->accessCheck(true)
->execute()
);
// If there at least 3 nodes for the current date, remove the main page so
// that it can't be picked. If there are two nodes, alternating between the
// main page and the single wiki node is preferable so that a user sees a
// change when choosing random.
if (\count($currentDateNids) > 2) {
\array_splice(
$currentDateNids,
\array_search($currentDateMainPageNid, $currentDateNids),
1
);
}
// Recent wiki nodes for the current date. Note that \array_values() is
// needed to ensure the keys are integers and not strings.
/** @var array */
$currentDateRecentNids = \array_values(\array_filter(
$this->wikiNodeViewed->getNodes(),
function($nid) use ($currentDateNids) {
// This filters out any nodes that aren't of the current date.
return \in_array($nid, $currentDateNids);
},
));
// Reduce the recent nodes array to one less than the available nodes.
$currentDateRecentNids = \array_reverse(\array_slice(
\array_reverse($currentDateRecentNids),
0,
\count($currentDateNids) - 1,
));
/** @var array */
$nids = \array_filter(
$currentDateNids,
function($nid) use ($currentDateRecentNids) {
// This filters out recently viewed wiki nodes.
return !\in_array($nid, $currentDateRecentNids);
},
);
// If no nids are left at this point, fall back to the main page.
if (empty($nids)) {
$nids = [$currentDateMainPageNid];
}
// We have to make a copy of the array as \shuffle() modifies the array you
// pass it rather than returning a shuffled copy.
$shuffled = $nids;
\shuffle($shuffled);
return new RedirectResponse(Url::fromRoute('entity.node.canonical', [
// Return the first element from the shuffled list of available node IDs
// (nids).
'node' => $shuffled[0],
])->toString(), 302);
}
}