-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathCpController.php
197 lines (167 loc) · 6.39 KB
/
CpController.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
194
195
196
197
<?php
/**
* Elasticsearch plugin for Craft CMS.
*
* @link https://www.lahautesociete.com
* @copyright Copyright (c) 2018 La Haute Société
*/
namespace lhs\elasticsearch\controllers;
use Craft;
use craft\helpers\UrlHelper;
use craft\records\Site;
use craft\web\Controller;
use craft\web\Request;
use lhs\elasticsearch\Elasticsearch;
use lhs\elasticsearch\Elasticsearch as ElasticsearchPlugin;
use lhs\elasticsearch\models\IndexableElementModel;
use yii\helpers\VarDumper;
use yii\web\Response;
/**
* Control Panel controller
*/
class CpController extends Controller
{
/** @var ElasticsearchPlugin */
public $plugin;
protected array|bool|int $allowAnonymous = ['testConnection', 'reindexPerformAction'];
public function init(): void
{
parent::init();
$this->plugin = ElasticsearchPlugin::getInstance();
}
/**
* Test the elasticsearch connection
*
* @return Response
* @throws \yii\web\ForbiddenHttpException If the user doesn't have the utility:refresh-elasticsearch-index permission
*/
public function actionTestConnection(): Response
{
$this->requirePermission('utility:refresh-elasticsearch-index');
$elasticsearchPlugin = Elasticsearch::getInstance();
assert($elasticsearchPlugin !== null, "Elasticsearch::getInstance() should always return the plugin instance when called from the plugin's code.");
$settings = $elasticsearchPlugin->getSettings();
if ($elasticsearchPlugin->service->testConnection() === true) {
Craft::$app->session->setNotice(
Craft::t(
Elasticsearch::PLUGIN_HANDLE,
'Successfully connected to {elasticsearchEndpoint}',
['elasticsearchEndpoint' => $settings->elasticsearchEndpoint]
)
);
} else {
Craft::$app->session->setError(
Craft::t(
Elasticsearch::PLUGIN_HANDLE,
'Could not establish connection with {elasticsearchEndpoint}',
['elasticsearchEndpoint' => $settings->elasticsearchEndpoint]
)
);
}
return $this->redirect(UrlHelper::cpUrl('utilities/elasticsearch-utilities'));
}
/**
* Reindex Craft entries into Elasticsearch (called from utility panel)
*
* @return Response
* @throws \Exception If reindexing an entry fails
* @throws \yii\web\BadRequestHttpException if the request body is missing a `params` property
* @throws \yii\web\ForbiddenHttpException if the user doesn't have access to the Elasticsearch utility
*/
public function actionReindexPerformAction(): Response
{
$this->requirePermission('utility:refresh-elasticsearch-index');
$request = Craft::$app->getRequest();
$params = $request->getRequiredBodyParam('params');
// Return the ids of entries to process
if (!empty($params['start'])) {
try {
$siteIds = $this->getSiteIds($request);
// Don't match exactly. On false we receive an empty string, on true we
// receive a string '1'. We only recreate the indexes when requested.
if ($params['recreate'] == true) {
Elasticsearch::getInstance()->indexManagementService->recreateSiteIndex(...$siteIds);
}
} catch (\Exception $e) {
return $this->asErrorJson($e->getMessage());
}
return $this->getReindexQueue($siteIds);
}
// Process the given element
$reason = $this->reindexElement();
if ($reason !== null) {
return $this->asJson(
[
'success' => true,
'skipped' => true,
'reason' => $reason,
]
);
}
return $this->asJson(['success' => true]);
}
/**
* @param int[] $siteIds The numeric ids of sites to be re-indexed
*
* @return Response
*/
protected function getReindexQueue(array $siteIds): Response
{
/** @var Elasticsearch $plugin */
$plugin = Elasticsearch::getInstance();
$indexableElementModels = $plugin->service->getIndexableElementModels($siteIds);
// Re-format $indexableElementModels to keep the JS part as close as possible to Craft SearchIndexUtility's
array_walk(
$indexableElementModels,
static function (&$element) {
$element = ['params' => $element->toArray()];
}
);
return $this->asJson(
[
'entries' => [$indexableElementModels],
]
);
}
/**
* When using Garnish's CheckboxSelect component, the field value is "*" when the all checkbox is selected.
* This value gets passed to the controller.
*
* This methods converts the "*" value into an array containing the id of all sites.
*
* @param Request $request
*
* @return int[]
*/
protected function getSiteIds(Request $request): array
{
$siteIds = $request->getParam('params.sites', '*');
if ($siteIds === '*') {
$siteIds = Site::find()->select('id')->column();
}
return $siteIds;
}
/**
* @return string|null A string explaining why the entry wasn't reindexed or `null` if it was reindexed
* @throws \Exception If reindexing the entry fails for some reason.
* @throws \yii\web\BadRequestHttpException if the request body is missing a `params` property
*/
protected function reindexElement(): ?string
{
$request = Craft::$app->getRequest();
$model = new IndexableElementModel();
$model->elementId = $request->getRequiredBodyParam('params.elementId');
$model->siteId = $request->getRequiredBodyParam('params.siteId');
$model->type = $request->getRequiredBodyParam('params.type');
$element = $model->getElement();
try {
return $element
? Elasticsearch::getInstance()->elementIndexerService->indexElement($element)
: null;
} catch (\Exception $e) {
Craft::error("Error while re-indexing element {$element->url}: {$e->getMessage()}", __METHOD__);
Craft::error(VarDumper::dumpAsString($e), __METHOD__);
throw $e;
}
}
}