Passed
Pull Request — master (#1318)
by
unknown
32:46
created

InfoModuleController::initializeView()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 1
1
<?php
2
namespace ApacheSolrForTypo3\Solr\Controller\Backend\Search;
3
4
/***************************************************************
5
 *  Copyright notice
6
 *
7
 *  (c) 2010-2017 dkd Internet Service GmbH <[email protected]>
8
 *  All rights reserved
9
 *
10
 *  This script is part of the TYPO3 project. The TYPO3 project is
11
 *  free software; you can redistribute it and/or modify
12
 *  it under the terms of the GNU General Public License as published by
13
 *  the Free Software Foundation; either version 2 of the License, or
14
 *  (at your option) any later version.
15
 *
16
 *  The GNU General Public License can be found at
17
 *  http://www.gnu.org/copyleft/gpl.html.
18
 *
19
 *  This script is distributed in the hope that it will be useful,
20
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 *  GNU General Public License for more details.
23
 *
24
 *  This copyright notice MUST APPEAR in all copies of the script!
25
 ***************************************************************/
26
27
use ApacheSolrForTypo3\Solr\Api;
28
use ApacheSolrForTypo3\Solr\Domain\Search\Statistics\StatisticsRepository;
29
use ApacheSolrForTypo3\Solr\System\Validator\Path;
30
use TYPO3\CMS\Backend\Template\ModuleTemplate;
31
use TYPO3\CMS\Core\Messaging\FlashMessage;
32
use TYPO3\CMS\Core\Registry;
33
use TYPO3\CMS\Core\Utility\GeneralUtility;
34
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
35
36
/**
37
 * Info Module
38
 */
39
class InfoModuleController extends AbstractModuleController
40
{
41
    /**
42
     * @var \ApacheSolrForTypo3\Solr\ConnectionManager
43
     * @inject
44
     */
45
    protected $solrConnectionManager;
46
47
    /**
48
     * Set up the doc header properly here
49
     *
50
     * @param ViewInterface $view
51
     * @return void
52
     */
53
    protected function initializeView(ViewInterface $view)
54
    {
55
        parent::initializeView($view);
56
57
        /* @var ModuleTemplate $module */ // holds the state of chosen tab
58
        $module = GeneralUtility::makeInstance(ModuleTemplate::class);
59
        $coreOptimizationTabs = $module->getDynamicTabMenu([], 'coreOptimization');
60
        $this->view->assign('tabs', $coreOptimizationTabs);
61
    }
62
63
    /**
64
     * Index action, shows an overview of the state of the Solr index
65
     *
66
     * @return void
67
     */
68
    public function indexAction()
69
    {
70
        if ($this->selectedSite === null) {
71
            $this->view->assign('can_not_proceed', true);
72
            return;
73
        }
74
75
        $this->collectConnectionInfos();
76
        $this->collectStatistics();
77
        $this->collectIndexFieldsInfo();
78
    }
79
80
    /**
81
     * Checks whether the configured Solr server can be reached and provides a
82
     * flash message according to the result of the check.
83
     *
84
     * @return void
85
     */
86
    protected function collectConnectionInfos()
87
    {
88
        $connectedHosts = [];
89
        $missingHosts = [];
90
        $invalidPaths = [];
91
92
        /* @var Path $path */
93
        $path = GeneralUtility::makeInstance(Path::class);
94
        $connections = $this->solrConnectionManager->getConnectionsBySite($this->selectedSite);
95
96
        if (empty($connections)) {
97
            $this->view->assign('can_not_proceed', true);
98
            return;
99
        }
100
101
        foreach ($connections as $connection) {
102
            $coreUrl = $connection->getScheme() . '://' . $connection->getHost() . ':' . $connection->getPort() . $connection->getPath();
103
104
            if ($connection->ping()) {
105
                $connectedHosts[] = $coreUrl;
106
            } else {
107
                $missingHosts[] = $coreUrl;
108
            }
109
110
            if (!$path->isValidSolrPath($connection->getPath())) {
111
                $invalidPaths[] = $connection->getPath();
112
            }
113
        }
114
115
        $this->view->assignMultiple([
116
            'site' => $this->selectedSite,
117
            'apiKey' => Api::getApiKey(),
118
            'connectedHosts' => $connectedHosts,
119
            'missingHosts' => $missingHosts,
120
            'invalidPaths' => $invalidPaths
121
        ]);
122
    }
123
124
    /**
125
     * Index action, shows an overview of the state of the Solr index
126
     *
127
     * @return void
128
     */
129
    protected function collectStatistics()
130
    {
131
        // TODO make time frame user adjustable, for now it's last 30 days
132
133
        $siteRootPageId = $this->selectedSite->getRootPageId();
134
        /* @var StatisticsRepository $statisticsRepository */
135
        $statisticsRepository = GeneralUtility::makeInstance(StatisticsRepository::class);
136
137
        // @TODO: Do we want Typoscript constants to restrict the results?
138
        $this->view->assign(
139
            'top_search_phrases',
140
            $statisticsRepository->getTopKeyWordsWithHits($siteRootPageId, 30, 5)
141
        );
142
        $this->view->assign(
143
            'top_search_phrases_without_hits',
144
            $statisticsRepository->getTopKeyWordsWithoutHits($siteRootPageId, 30, 5)
145
        );
146
        $this->view->assign(
147
            'search_phrases_statistics',
148
            $statisticsRepository->getSearchStatistics($siteRootPageId, 30, 100)
149
        );
150
151
        $labels = [];
152
        $data = [];
153
        $chartData = $statisticsRepository->getQueriesOverTime($siteRootPageId, 30, 86400);
154
        foreach ($chartData as $bucket) {
155
            $labels[] = strftime('%x', $bucket['timestamp']);
156
            $data[] = (int)$bucket['numQueries'];
157
        }
158
159
        $this->view->assign('queriesChartLabels', json_encode($labels));
160
        $this->view->assign('queriesChartData', json_encode($data));
161
    }
162
163
    /**
164
     * Gets Luke meta data for the currently selected core and provides a list
165
     * of that data.
166
     *
167
     * @return void
168
     */
169
    protected function collectIndexFieldsInfo()
170
    {
171
        $indexFieldsInfoByCorePaths = [];
172
173
        $solrCoreConnections = $this->solrConnectionManager->getConnectionsBySite($this->selectedSite);
174
        foreach ($solrCoreConnections as $solrCoreConnection) {
175
            $indexFieldsInfo = [
176
                'corePath' => $solrCoreConnection->getPath()
177
            ];
178
            if ($solrCoreConnection->ping()) {
179
                $lukeData = $solrCoreConnection->getLukeMetaData();
180
181
                /* @var Registry $registry */
182
                $registry = GeneralUtility::makeInstance(Registry::class);
183
                $limit = $registry->get('tx_solr', 'luke.limit', 20000);
184
                $limitNote = '';
185
186
                if (isset($lukeData->index->numDocs) && $lukeData->index->numDocs > $limit) {
187
                    $limitNote = '<em>Too many terms</em>';
188
                } elseif (isset($lukeData->index->numDocs)) {
189
                    $limitNote = 'Nothing indexed';
190
                    // below limit, so we can get more data
191
                    // Note: we use 2 since 1 fails on Ubuntu Hardy.
192
                    $lukeData = $solrCoreConnection->getLukeMetaData(2);
193
                }
194
195
                $fields = $this->getFields($lukeData, $limitNote);
196
                $coreMetrics = $this->getCoreMetrics($lukeData, $fields);
197
198
                $indexFieldsInfo['noError'] = 'OK';
199
                $indexFieldsInfo['fields'] = $fields;
200
                $indexFieldsInfo['coreMetrics'] = $coreMetrics;
201
            } else {
202
                $indexFieldsInfo['noError'] = null;
203
204
                $this->addFlashMessage(
205
                    '',
206
                    'Unable to contact Apache Solr server: ' . $this->selectedSite->getLabel() . ' ' . $solrCoreConnection->getPath(),
207
                    FlashMessage::ERROR
208
                );
209
            }
210
            $indexFieldsInfoByCorePaths[$solrCoreConnection->getPath()] = $indexFieldsInfo;
211
        }
212
        $this->view->assign('indexFieldsInfoByCorePaths', $indexFieldsInfoByCorePaths);
213
    }
214
215
    /**
216
     * Gets field metrics.
217
     *
218
     * @param \Apache_Solr_Response $lukeData Luke index data
219
     * @param string $limitNote Note to display if there are too many documents in the index to show number of terms for a field
220
     *
221
     * @return array An array of field metrics
222
     */
223
    protected function getFields(\Apache_Solr_Response $lukeData, $limitNote)
224
    {
225
        $rows = [];
226
227
        $fields = (array)$lukeData->fields;
228
        foreach ($fields as $name => $field) {
229
            $rows[$name] = [
230
                'name' => $name,
231
                'type' => $field->type,
232
                'docs' => isset($field->docs) ? $field->docs : 0,
233
                'terms' => isset($field->distinct) ? $field->distinct : $limitNote
234
            ];
235
        }
236
        ksort($rows);
237
238
        return $rows;
239
    }
240
241
    /**
242
     * Gets general core metrics.
243
     *
244
     * @param \Apache_Solr_Response $lukeData Luke index data
245
     * @param array $fields Fields metrics
246
     *
247
     * @return array An array of core metrics
248
     */
249
    protected function getCoreMetrics(\Apache_Solr_Response $lukeData, array $fields)
250
    {
251
        $coreMetrics = [
252
            'numberOfDocuments' => $lukeData->index->numDocs,
253
            'numberOfDeletedDocuments' => $lukeData->index->deletedDocs,
254
            'numberOfTerms' => $lukeData->index->numTerms,
255
            'numberOfFields' => count($fields)
256
        ];
257
258
        return $coreMetrics;
259
    }
260
}
261