e64e57d846b7f861622108453d67245fafb2f4ee
[Packages/TYPO3.CMS.git] / typo3 / sysext / reports / Classes / Report / Status / Status.php
1 <?php
2 namespace TYPO3\CMS\Reports\Report\Status;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use Psr\Http\Message\ServerRequestInterface;
18 use TYPO3\CMS\Core\Localization\LanguageService;
19 use TYPO3\CMS\Core\Registry;
20 use TYPO3\CMS\Core\Utility\GeneralUtility;
21 use TYPO3\CMS\Reports\ExtendedStatusProviderInterface;
22 use TYPO3\CMS\Reports\RequestAwareReportInterface;
23 use TYPO3\CMS\Reports\RequestAwareStatusProviderInterface;
24 use TYPO3\CMS\Reports\Status as ReportStatus;
25 use TYPO3\CMS\Reports\StatusProviderInterface;
26
27 /**
28 * The status report
29 */
30 class Status implements RequestAwareReportInterface
31 {
32 /**
33 * @var StatusProviderInterface[][]
34 */
35 protected $statusProviders = [];
36
37 /**
38 * Constructor for class tx_reports_report_Status
39 */
40 public function __construct()
41 {
42 $this->getLanguageService()->includeLLFile('EXT:reports/Resources/Private/Language/locallang_reports.xlf');
43 $this->getStatusProviders();
44 }
45
46 /**
47 * Takes care of creating / rendering the status report
48 *
49 * @param ServerRequestInterface|null $request the currently handled request
50 * @return string The status report as HTML
51 */
52 public function getReport(ServerRequestInterface $request = null)
53 {
54 $content = '';
55 $status = $this->getSystemStatus($request);
56 $highestSeverity = $this->getHighestSeverity($status);
57 // Updating the registry
58 $registry = GeneralUtility::makeInstance(Registry::class);
59 $registry->set('tx_reports', 'status.highestSeverity', $highestSeverity);
60 $content .= '<p class="lead">' . $this->getLanguageService()->getLL('status_report_explanation') . '</p>';
61 return $content . $this->renderStatus($status);
62 }
63
64 /**
65 * Gets all registered status providers and creates instances of them.
66 */
67 protected function getStatusProviders()
68 {
69 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['reports']['tx_reports']['status']['providers'] as $key => $statusProvidersList) {
70 $this->statusProviders[$key] = [];
71 foreach ($statusProvidersList as $statusProvider) {
72 $statusProviderInstance = GeneralUtility::makeInstance($statusProvider);
73 if ($statusProviderInstance instanceof StatusProviderInterface) {
74 $this->statusProviders[$key][] = $statusProviderInstance;
75 }
76 }
77 }
78 }
79
80 /**
81 * Runs through all status providers and returns all statuses collected.
82 *
83 * @param ServerRequestInterface $request
84 * @return \TYPO3\CMS\Reports\Status[]
85 */
86 public function getSystemStatus(ServerRequestInterface $request = null)
87 {
88 $status = [];
89 foreach ($this->statusProviders as $statusProviderId => $statusProviderList) {
90 $status[$statusProviderId] = [[]];
91 foreach ($statusProviderList as $statusProvider) {
92 if ($statusProvider instanceof RequestAwareStatusProviderInterface) {
93 $statuses = $statusProvider->getStatus($request);
94 } else {
95 $statuses = $statusProvider->getStatus();
96 }
97 $status[$statusProviderId][] = $statuses;
98 }
99 $status[$statusProviderId] = array_merge(...$status[$statusProviderId]);
100 }
101 return $status;
102 }
103
104 /**
105 * Runs through all status providers and returns all statuses collected, which are detailed.
106 *
107 * @return \TYPO3\CMS\Reports\Status[]
108 */
109 public function getDetailedSystemStatus()
110 {
111 $status = [];
112 foreach ($this->statusProviders as $statusProviderId => $statusProviderList) {
113 $status[$statusProviderId] = [];
114 foreach ($statusProviderList as $statusProvider) {
115 if ($statusProvider instanceof ExtendedStatusProviderInterface) {
116 $statuses = $statusProvider->getDetailedStatus();
117 $status[$statusProviderId][] = $statuses;
118 }
119 }
120 $status[$statusProviderId] = array_merge(...$status[$statusProviderId]);
121 }
122 return $status;
123 }
124
125 /**
126 * Determines the highest severity from the given statuses.
127 *
128 * @param array $statusCollection An array of \TYPO3\CMS\Reports\Status objects.
129 * @return int The highest severity found from the statuses.
130 */
131 public function getHighestSeverity(array $statusCollection)
132 {
133 $highestSeverity = ReportStatus::NOTICE;
134 foreach ($statusCollection as $statusProvider => $providerStatuses) {
135 /** @var ReportStatus $status */
136 foreach ($providerStatuses as $status) {
137 if ($status->getSeverity() > $highestSeverity) {
138 $highestSeverity = $status->getSeverity();
139 }
140 // Reached the highest severity level, no need to go on
141 if ($highestSeverity == ReportStatus::ERROR) {
142 break;
143 }
144 }
145 }
146 return $highestSeverity;
147 }
148
149 /**
150 * Renders the system's status
151 *
152 * @param array $statusCollection An array of statuses as returned by the available status providers
153 * @return string The system status as an HTML table
154 */
155 protected function renderStatus(array $statusCollection)
156 {
157 $content = '';
158 $template = '
159 <tr>
160 <td class="###CLASS### col-xs-6">###HEADER###</td>
161 <td class="###CLASS### col-xs-6">###STATUS###<br>###CONTENT###</td>
162 </tr>
163 ';
164 $statuses = $this->sortStatusProviders($statusCollection);
165 $id = 0;
166 foreach ($statuses as $provider => $providerStatus) {
167 $providerState = $this->sortStatuses($providerStatus);
168 $id++;
169 $classes = [
170 ReportStatus::NOTICE => 'notice',
171 ReportStatus::INFO => 'info',
172 ReportStatus::OK => 'success',
173 ReportStatus::WARNING => 'warning',
174 ReportStatus::ERROR => 'danger'
175 ];
176 $messages = '';
177 /** @var ReportStatus $status */
178 foreach ($providerState as $status) {
179 $severity = $status->getSeverity();
180 $messages .= strtr($template, [
181 '###CLASS###' => $classes[$severity],
182 '###HEADER###' => $status->getTitle(),
183 '###STATUS###' => $status->getValue(),
184 '###CONTENT###' => $status->getMessage()
185 ]);
186 }
187 $header = '<h2>' . $provider . '</h2>';
188 $table = '<table class="table table-striped table-hover">';
189 $table .= '<tbody>' . $messages . '</tbody>';
190 $table .= '</table>';
191
192 $content .= $header . $table;
193 }
194 return $content;
195 }
196
197 /**
198 * Sorts the status providers (alphabetically and puts primary status providers at the beginning)
199 *
200 * @param array $statusCollection A collection of statuses (with providers)
201 * @return array The collection of statuses sorted by provider (beginning with provider "_install")
202 */
203 protected function sortStatusProviders(array $statusCollection)
204 {
205 // Extract the primary status collections, i.e. the status groups
206 // that must appear on top of the status report
207 // Change their keys to localized collection titles
208 $primaryStatuses = [
209 $this->getLanguageService()->getLL('status_typo3') => $statusCollection['typo3'],
210 $this->getLanguageService()->getLL('status_system') => $statusCollection['system'],
211 $this->getLanguageService()->getLL('status_security') => $statusCollection['security'],
212 $this->getLanguageService()->getLL('status_configuration') => $statusCollection['configuration']
213 ];
214 unset($statusCollection['typo3'], $statusCollection['system'], $statusCollection['security'], $statusCollection['configuration']);
215 // Assemble list of secondary status collections with left-over collections
216 // Change their keys using localized labels if available
217 // @todo extract into getLabel() method
218 $secondaryStatuses = [];
219 foreach ($statusCollection as $statusProviderId => $collection) {
220 if (strpos($statusProviderId, 'LLL:') === 0) {
221 // Label provided by extension
222 $label = $this->getLanguageService()->sL($statusProviderId);
223 } else {
224 // Generic label
225 $label = $this->getLanguageService()->getLL('status_' . $statusProviderId);
226 }
227 $providerLabel = empty($label) ? $statusProviderId : $label;
228 $secondaryStatuses[$providerLabel] = $collection;
229 }
230 // Sort the secondary status collections alphabetically
231 ksort($secondaryStatuses);
232 $orderedStatusCollection = array_merge($primaryStatuses, $secondaryStatuses);
233 return $orderedStatusCollection;
234 }
235
236 /**
237 * Sorts the statuses by severity
238 *
239 * @param array $statusCollection A collection of statuses per provider
240 * @return array The collection of statuses sorted by severity
241 */
242 protected function sortStatuses(array $statusCollection)
243 {
244 $statuses = [];
245 $sortTitle = [];
246 $header = null;
247 /** @var ReportStatus $status */
248 foreach ($statusCollection as $status) {
249 if ($status->getTitle() === 'TYPO3') {
250 $header = $status;
251 continue;
252 }
253 $statuses[] = $status;
254 $sortTitle[] = $status->getSeverity();
255 }
256 array_multisort($sortTitle, SORT_DESC, $statuses);
257 // Making sure that the core version information is always on the top
258 if (is_object($header)) {
259 array_unshift($statuses, $header);
260 }
261 return $statuses;
262 }
263
264 /**
265 * @return LanguageService
266 */
267 protected function getLanguageService()
268 {
269 return $GLOBALS['LANG'];
270 }
271 }