572d66da9053a6ad7200134c3be7fdab69ed789b
[Packages/TYPO3.CMS.git] / typo3 / sysext / belog / Classes / Controller / AbstractController.php
1 <?php
2 namespace TYPO3\CMS\Belog\Controller;
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 TYPO3\CMS\Core\Page\PageRenderer;
18 use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
19 use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
20 use TYPO3\CMS\Backend\View\BackendTemplateView;
21
22 /**
23 * Abstract class to show log entries from sys_log
24 */
25 abstract class AbstractController extends ActionController {
26
27 /**
28 * @var int
29 */
30 const TIMEFRAME_THISWEEK = 0;
31
32 /**
33 * @var int
34 */
35 const TIMEFRAME_LASTWEEK = 1;
36
37 /**
38 * @var int
39 */
40 const TIMEFRAME_LASTSEVENDAYS = 2;
41
42 /**
43 * @var int
44 */
45 const TIMEFRAME_THISMONTH = 10;
46
47 /**
48 * @var int
49 */
50 const TIMEFRAME_LASTMONTH = 11;
51
52 /**
53 * @var int
54 */
55 const TIMEFRAME_LAST31DAYS = 12;
56
57 /**
58 * @var int
59 */
60 const TIMEFRAME_CUSTOM = 30;
61
62 /**
63 * Whether plugin is running in page context (sub module of Web > Info)
64 *
65 * @var bool
66 */
67 protected $isInPageContext = FALSE;
68
69 /**
70 * Page ID in page context
71 *
72 * @var int
73 */
74 protected $pageId = 0;
75
76 /**
77 * @var \TYPO3\CMS\Belog\Domain\Repository\LogEntryRepository
78 */
79 protected $logEntryRepository = NULL;
80
81 /**
82 * @var BackendTemplateView
83 */
84 protected $view;
85
86 /**
87 * BackendTemplateView Container
88 *
89 * @var BackendTemplateView
90 */
91 protected $defaultViewObjectName = BackendTemplateView::class;
92
93 /**
94 * @param \TYPO3\CMS\Belog\Domain\Repository\LogEntryRepository $logEntryRepository
95 */
96 public function injectLogEntryRepository(\TYPO3\CMS\Belog\Domain\Repository\LogEntryRepository $logEntryRepository) {
97 $this->logEntryRepository = $logEntryRepository;
98 }
99
100 /**
101 * Initialize the view
102 *
103 * @param ViewInterface $view The view
104 * @return void
105 */
106 protected function initializeView(ViewInterface $view) {
107 /** @var BackendTemplateView $view */
108 parent::initializeView($view);
109 $view->getModuleTemplate()->getPageRenderer()->loadExtJS();
110 $view->getModuleTemplate()->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/DateTimePicker');
111 }
112
113 /**
114 * init all actions
115 * @return void
116 */
117 public function initializeAction() {
118 }
119
120 /**
121 * Initialize index action
122 *
123 * @return void
124 * @throws \RuntimeException
125 */
126 public function initializeIndexAction() {
127 // @TODO: Extbase backend modules rely on frontend TypoScript for view, persistence
128 // and settings. Thus, we need a TypoScript root template, that then loads the
129 // ext_typoscript_setup.txt file of this module. This is nasty, but can not be
130 // circumvented until there is a better solution in extbase.
131 // For now we throw an exception if no settings are detected.
132 if (empty($this->settings)) {
133 throw new \RuntimeException(
134 'No settings detected. This usually happens if there is no frontend TypoScript template with root flag set. Please create one.',
135 1333650506
136 );
137 }
138 if (!isset($this->settings['dateFormat'])) {
139 $this->settings['dateFormat'] = $GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ? 'm-d-Y' : 'd-m-Y';
140 }
141 if (!isset($this->settings['timeFormat'])) {
142 $this->settings['timeFormat'] = $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'];
143 }
144 }
145
146 /**
147 * Show general information and the installed modules
148 *
149 * @param \TYPO3\CMS\Belog\Domain\Model\Constraint $constraint
150 * @return void
151 */
152 public function indexAction(\TYPO3\CMS\Belog\Domain\Model\Constraint $constraint = NULL) {
153 // Constraint object handling:
154 // If there is none from GET, try to get it from BE user data, else create new
155 if ($constraint === NULL) {
156 $constraint = $this->getConstraintFromBeUserData();
157 if ($constraint === NULL) {
158 $constraint = $this->objectManager->get(\TYPO3\CMS\Belog\Domain\Model\Constraint::class);
159 }
160 } else {
161 $this->persistConstraintInBeUserData($constraint);
162 }
163 $constraint->setIsInPageContext($this->isInPageContext);
164 $constraint->setPageId($this->pageId);
165 $this->setStartAndEndTimeFromTimeSelector($constraint);
166 $this->forceWorkspaceSelectionIfInWorkspace($constraint);
167 $logEntries = $this->logEntryRepository->findByConstraint($constraint);
168 $groupedLogEntries = $this->groupLogEntriesByPageAndDay($logEntries, $constraint->getGroupByPage());
169 $this->view->assign('groupedLogEntries', $groupedLogEntries)->assign('constraint', $constraint)->assign('userGroups', $this->createUserAndGroupListForSelectOptions())->assign('workspaces', $this->createWorkspaceListForSelectOptions())->assign('pageDepths', $this->createPageDepthOptions());
170 }
171
172 /**
173 * Get module states (the constraint object) from user data
174 *
175 * @return \TYPO3\CMS\Belog\Domain\Model\Constraint|NULL
176 */
177 protected function getConstraintFromBeUserData() {
178 $serializedConstraint = $GLOBALS['BE_USER']->getModuleData(get_class($this));
179 if (!is_string($serializedConstraint) || empty($serializedConstraint)) {
180 return NULL;
181 }
182 return @unserialize($serializedConstraint);
183 }
184
185 /**
186 * Save current constraint object in be user settings (uC)
187 *
188 * @param \TYPO3\CMS\Belog\Domain\Model\Constraint $constraint
189 * @return void
190 */
191 protected function persistConstraintInBeUserData(\TYPO3\CMS\Belog\Domain\Model\Constraint $constraint) {
192 $GLOBALS['BE_USER']->pushModuleData(get_class($this), serialize($constraint));
193 }
194
195 /**
196 * Create a sorted array for day and page view from
197 * the query result of the sys log repository.
198 *
199 * If group by page is FALSE, pid is always -1 (will render a flat list),
200 * otherwise the output is splitted by pages.
201 * '12345' is a sub array to split entries by day, number is first second of day
202 *
203 * [pid][dayTimestamp][items]
204 *
205 * @param \TYPO3\CMS\Extbase\Persistence\QueryResultInterface<\TYPO3\CMS\Belog\Domain\Model\LogEntry> $logEntries
206 * @param bool $groupByPage Whether or not log entries should be grouped by page
207 * @return array
208 */
209 protected function groupLogEntriesByPageAndDay(\TYPO3\CMS\Extbase\Persistence\QueryResultInterface $logEntries, $groupByPage = FALSE) {
210 $targetStructure = array();
211 /** @var $entry \TYPO3\CMS\Belog\Domain\Model\LogEntry */
212 foreach ($logEntries as $entry) {
213 // Create page split list or flat list
214 if ($groupByPage) {
215 $pid = $entry->getEventPid();
216 } else {
217 $pid = -1;
218 }
219 // Create array if it is not defined yet
220 if (!is_array($targetStructure[$pid])) {
221 $targetStructure[$pid] = array();
222 }
223 // Get day timestamp of log entry and create sub array if needed
224 $timestampDay = strtotime(strftime('%d.%m.%Y', $entry->getTstamp()));
225 if (!is_array($targetStructure[$pid][$timestampDay])) {
226 $targetStructure[$pid][$timestampDay] = array();
227 }
228 // Add row
229 $targetStructure[$pid][$timestampDay][] = $entry;
230 }
231 ksort($targetStructure);
232 return $targetStructure;
233 }
234
235 /**
236 * Create options for the user / group drop down.
237 * This is not moved to a repository by intention to not mix up this 'meta' data
238 * with real repository work
239 *
240 * @return array Key is the option name, value its label
241 */
242 protected function createUserAndGroupListForSelectOptions() {
243 $userGroupArray = array();
244 // Two meta entries: 'all' and 'self'
245 $userGroupArray[0] = \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('allUsers', 'Belog');
246 $userGroupArray[-1] = \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('self', 'Belog');
247 // List of groups, key is gr-'uid'
248 $groups = \TYPO3\CMS\Backend\Utility\BackendUtility::getGroupNames();
249 foreach ($groups as $group) {
250 $userGroupArray['gr-' . $group['uid']] = \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('group', 'Belog') . ' ' . $group['title'];
251 }
252 // List of users, key is us-'uid'
253 $users = \TYPO3\CMS\Backend\Utility\BackendUtility::getUserNames();
254 foreach ($users as $user) {
255 $userGroupArray['us-' . $user['uid']] = \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('user', 'Belog') . ' ' . $user['username'];
256 }
257 return $userGroupArray;
258 }
259
260 /**
261 * Create options for the workspace selector
262 *
263 * @return array Key is uid of workspace, value its label
264 */
265 protected function createWorkspaceListForSelectOptions() {
266 if (!\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('workspaces')) {
267 return array();
268 }
269 $workspaceArray = array();
270 // Two meta entries: 'all' and 'live'
271 $workspaceArray[-99] = \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('any', 'Belog');
272 $workspaceArray[0] = \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('live', 'Belog');
273 $workspaces = $this->objectManager->get(\TYPO3\CMS\Belog\Domain\Repository\WorkspaceRepository::class)->findAll();
274 /** @var $workspace \TYPO3\CMS\Belog\Domain\Model\Workspace */
275 foreach ($workspaces as $workspace) {
276 $workspaceArray[$workspace->getUid()] = $workspace->getUid() . ': ' . $workspace->getTitle();
277 }
278 return $workspaceArray;
279 }
280
281 /**
282 * If the user is in a workspace different than LIVE,
283 * we force to show only log entries from the selected workspace,
284 * and the workspace selector is not shown.
285 *
286 * @param \TYPO3\CMS\Belog\Domain\Model\Constraint $constraint
287 * @return void
288 */
289 protected function forceWorkspaceSelectionIfInWorkspace(\TYPO3\CMS\Belog\Domain\Model\Constraint $constraint) {
290 if ($GLOBALS['BE_USER']->workspace !== 0) {
291 $constraint->setWorkspaceUid($GLOBALS['BE_USER']->workspace);
292 $this->view->assign('showWorkspaceSelector', FALSE);
293 } else {
294 $this->view->assign('showWorkspaceSelector', TRUE);
295 }
296 }
297
298 /**
299 * Create options for the 'depth of page levels' selector.
300 * This is shown if the module is displayed in page -> info
301 *
302 * @return array Key is depth identifier (1 = One level), value the localized select option label
303 */
304 protected function createPageDepthOptions() {
305 $options = array(
306 0 => \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('LLL:EXT:lang/locallang_core.xlf:labels.depth_0', 'lang'),
307 1 => \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('LLL:EXT:lang/locallang_core.xlf:labels.depth_1', 'lang'),
308 2 => \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('LLL:EXT:lang/locallang_core.xlf:labels.depth_2', 'lang'),
309 3 => \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('LLL:EXT:lang/locallang_core.xlf:labels.depth_3', 'lang'),
310 4 => \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('LLL:EXT:lang/locallang_core.xlf:labels.depth_4', 'lang'),
311 999 => \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('LLL:EXT:lang/locallang_core.xlf:labels.depth_infi', 'lang')
312 );
313 return $options;
314 }
315
316 /**
317 * Calculate the start- and end timestamp from the different time selector options
318 *
319 * @param \TYPO3\CMS\Belog\Domain\Model\Constraint $constraint
320 * @return void
321 */
322 protected function setStartAndEndTimeFromTimeSelector(\TYPO3\CMS\Belog\Domain\Model\Constraint $constraint) {
323 $startTime = 0;
324 $endTime = $GLOBALS['EXEC_TIME'];
325 // @TODO: Refactor this construct
326 switch ($constraint->getTimeFrame()) {
327 case self::TIMEFRAME_THISWEEK:
328 // This week
329 $week = (date('w') ?: 7) - 1;
330 $startTime = mktime(0, 0, 0) - $week * 3600 * 24;
331 break;
332 case self::TIMEFRAME_LASTWEEK:
333 // Last week
334 $week = (date('w') ?: 7) - 1;
335 $startTime = mktime(0, 0, 0) - ($week + 7) * 3600 * 24;
336 $endTime = mktime(0, 0, 0) - $week * 3600 * 24;
337 break;
338 case self::TIMEFRAME_LASTSEVENDAYS:
339 // Last 7 days
340 $startTime = mktime(0, 0, 0) - 7 * 3600 * 24;
341 break;
342 case self::TIMEFRAME_THISMONTH:
343 // This month
344 $startTime = mktime(0, 0, 0, date('m'), 1);
345 break;
346 case self::TIMEFRAME_LASTMONTH:
347 // Last month
348 $startTime = mktime(0, 0, 0, date('m') - 1, 1);
349 $endTime = mktime(0, 0, 0, date('m'), 1);
350 break;
351 case self::TIMEFRAME_LAST31DAYS:
352 // Last 31 days
353 $startTime = mktime(0, 0, 0) - 31 * 3600 * 24;
354 break;
355 case self::TIMEFRAME_CUSTOM:
356 $startTime = $constraint->getStartTimestamp();
357 if ($constraint->getEndTimestamp() > $constraint->getStartTimestamp()) {
358 $endTime = $constraint->getEndTimestamp();
359 } else {
360 $endTime = $GLOBALS['EXEC_TIME'];
361 }
362 break;
363 default:
364 }
365 $constraint->setStartTimestamp($startTime);
366 $constraint->setEndTimestamp($endTime);
367 }
368 }