TYPO3 CMS  TYPO3_7-6
NewContentElementController.php
Go to the documentation of this file.
1 <?php
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 
30 
35 {
41  public $id;
42 
48  public $sys_language = 0;
49 
55  public $R_URI = '';
56 
62  public $colPos;
63 
67  public $uid_pid;
68 
74  public $modTSconfig = [];
75 
81  public $doc;
82 
88  public $content;
89 
95  public $access;
96 
102  public $config;
103 
107  protected $pageInfo;
108 
112  protected $elementWrapper;
113 
117  protected $onClickEvent;
118 
122  protected $MCONF;
123 
127  public function __construct()
128  {
129  parent::__construct();
130  $GLOBALS['SOBE'] = $this;
131  $this->init();
132  }
133 
139  public function init()
140  {
141  $lang = $this->getLanguageService();
142  $lang->includeLLFile('EXT:lang/locallang_misc.xlf');
143  $LOCAL_LANG_orig = $GLOBALS['LOCAL_LANG'];
144  $lang->includeLLFile('EXT:backend/Resources/Private/Language/locallang_db_new_content_el.xlf');
145  ArrayUtility::mergeRecursiveWithOverrule($LOCAL_LANG_orig, $GLOBALS['LOCAL_LANG']);
146  $GLOBALS['LOCAL_LANG'] = $LOCAL_LANG_orig;
147 
148  // Setting internal vars:
149  $this->id = (int)GeneralUtility::_GP('id');
150  $this->sys_language = (int)GeneralUtility::_GP('sys_language_uid');
151  $this->R_URI = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'));
152  $this->colPos = GeneralUtility::_GP('colPos') === null ? null : (int)GeneralUtility::_GP('colPos');
153  $this->uid_pid = (int)GeneralUtility::_GP('uid_pid');
154  $this->MCONF['name'] = 'xMOD_db_new_content_el';
155  $this->modTSconfig = BackendUtility::getModTSconfig($this->id, 'mod.wizards.newContentElement');
157  $this->config = $config['mod.']['wizards.']['newContentElement.'];
158  // Starting the document template object:
159  // We keep this here in case somebody relies on it in a hook or alike
160  $this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
161  // Setting up the context sensitive menu:
162  $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ClickMenu');
163  // Getting the current page and receiving access information (used in main())
164  $perms_clause = $this->getBackendUser()->getPagePermsClause(1);
165  $this->pageInfo = BackendUtility::readPageAccess($this->id, $perms_clause);
166  $this->access = is_array($this->pageInfo) ? 1 : 0;
167  }
168 
177  public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
178  {
179  $this->main();
180  $this->moduleTemplate->setContent($this->content);
181  $response->getBody()->write($this->moduleTemplate->renderContent());
182  return $response;
183  }
184 
191  public function main()
192  {
193  $lang = $this->getLanguageService();
194  $this->content .= '<form action="" name="editForm" id="NewContentElementController"><input type="hidden" name="defValues" value="" />';
195  if ($this->id && $this->access) {
196  // Init position map object:
197  $posMap = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\View\ContentCreationPagePositionMap::class);
198  $posMap->cur_sys_language = $this->sys_language;
199  // If a column is pre-set:
200  if (isset($this->colPos)) {
201  if ($this->uid_pid < 0) {
202  $row = [];
203  $row['uid'] = abs($this->uid_pid);
204  } else {
205  $row = '';
206  }
207  $this->onClickEvent = $posMap->onClickInsertRecord(
208  $row,
209  $this->colPos,
210  '',
211  $this->uid_pid,
212  $this->sys_language
213  );
214  } else {
215  $this->onClickEvent = '';
216  }
217  // ***************************
218  // Creating content
219  // ***************************
220  $this->content .= '<h1>' . $lang->getLL('newContentElement') . '</h1>';
221  // Wizard
222  $wizardItems = $this->wizardArray();
223  // Wrapper for wizards
224  $this->elementWrapper['section'] = ['', ''];
225  // Hook for manipulating wizardItems, wrapper, onClickEvent etc.
226  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms']['db_new_content_el']['wizardItemsHook'])) {
227  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms']['db_new_content_el']['wizardItemsHook'] as $classData) {
228  $hookObject = GeneralUtility::getUserObj($classData);
229  if (!$hookObject instanceof NewContentElementWizardHookInterface) {
230  throw new \UnexpectedValueException(
231  $classData . ' must implement interface ' . NewContentElementWizardHookInterface::class,
232  1227834741
233  );
234  }
235  $hookObject->manipulateWizardItems($wizardItems, $this);
236  }
237  }
238  // Add document inline javascript
239  $this->moduleTemplate->addJavaScriptCode(
240  'NewContentElementWizardInlineJavascript',
241  '
242  function goToalt_doc() {
243  ' . $this->onClickEvent . '
244  }'
245  );
246 
247  $iconRegistry = GeneralUtility::makeInstance(IconRegistry::class);
248 
249  // Traverse items for the wizard.
250  // An item is either a header or an item rendered with a radio button and title/description and icon:
251  $cc = ($key = 0);
252  $menuItems = [];
253  foreach ($wizardItems as $k => $wInfo) {
254  if ($wInfo['header']) {
255  $menuItems[] = [
256  'label' => htmlspecialchars($wInfo['header']),
257  'content' => $this->elementWrapper['section'][0]
258  ];
259  $key = count($menuItems) - 1;
260  } else {
261  $content = '';
262 
263  if (!$this->onClickEvent) {
264  // Radio button:
265  $oC = 'document.editForm.defValues.value=unescape(' . GeneralUtility::quoteJSvalue(rawurlencode($wInfo['params'])) . ');goToalt_doc();' . (!$this->onClickEvent ? 'window.location.hash=\'#sel2\';' : '');
266  $content .= '<div class="media-left"><input type="radio" name="tempB" value="' . htmlspecialchars($k) . '" onclick="' . htmlspecialchars($oC) . '" /></div>';
267  // Onclick action for icon/title:
268  $aOnClick = 'document.getElementsByName(\'tempB\')[' . $cc . '].checked=1;' . $oC . 'return false;';
269  } else {
270  $aOnClick = "document.editForm.defValues.value=unescape('" . rawurlencode($wInfo['params']) . "');goToalt_doc();" . (!$this->onClickEvent?"window.location.hash='#sel2';":'');
271  }
272 
273  if (isset($wInfo['icon'])) {
274  GeneralUtility::deprecationLog('The PageTS-Config: mod.wizards.newContentElement.wizardItems.*.elements.*.icon'
275  . ' is deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8.'
276  . ' Register your icon in IconRegistry::registerIcon and use the new setting:'
277  . ' mod.wizards.newContentElement.wizardItems.*.elements.*.iconIdentifier');
278  $wInfo['iconIdentifier'] = 'content-' . $k;
279  $icon = $wInfo['icon'];
280  if (StringUtility::beginsWith($icon, '../typo3conf/ext/')) {
281  $icon = str_replace('../typo3conf/ext/', 'EXT:', $icon);
282  }
283  if (!StringUtility::beginsWith($icon, 'EXT:') && strpos($icon, '/') !== false) {
284  $icon = TYPO3_mainDir . GeneralUtility::resolveBackPath($wInfo['icon']);
285  }
286  $iconRegistry->registerIcon($wInfo['iconIdentifier'], BitmapIconProvider::class, [
287  'source' => $icon
288  ]);
289  }
290  $icon = $this->moduleTemplate->getIconFactory()->getIcon($wInfo['iconIdentifier'])->render();
291  $menuItems[$key]['content'] .= '
292  <div class="media">
293  <a href="#" onclick="' . htmlspecialchars($aOnClick) . '">
294  ' . $content . '
295  <div class="media-left">
296  ' . $icon . '
297  </div>
298  <div class="media-body">
299  <strong>' . htmlspecialchars($wInfo['title']) . '</strong>' .
300  '<br />' .
301  nl2br(htmlspecialchars(trim($wInfo['description']))) .
302  '</div>
303  </a>
304  </div>';
305  $cc++;
306  }
307  }
308  // Add closing section-tag
309  foreach ($menuItems as $key => $val) {
310  $menuItems[$key]['content'] .= $this->elementWrapper['section'][1];
311  }
312  // Add the wizard table to the content, wrapped in tabs
313  $code = '<p>' . $lang->getLL('sel1', 1) . '</p>' . $this->moduleTemplate->getDynamicTabMenu(
314  $menuItems,
315  'new-content-element-wizard'
316  );
317 
318  $this->content .= !$this->onClickEvent ? '<h2>' . $lang->getLL('1_selectType', true) . '</h2>' : '';
319  $this->content .= '<div>' . $code . '</div>';
320 
321  // If the user must also select a column:
322  if (!$this->onClickEvent) {
323  // Add anchor "sel2"
324  $this->content .= '<div><a name="sel2"></a></div>';
325  // Select position
326  $code = '<p>' . $lang->getLL('sel2', 1) . '</p>';
327 
328  // Load SHARED page-TSconfig settings and retrieve column list from there, if applicable:
329  $colPosArray = GeneralUtility::callUserFunction(
330  BackendLayoutView::class . '->getColPosListItemsParsed',
331  $this->id,
332  $this
333  );
334  $colPosIds = array_column($colPosArray, 1);
335  // Removing duplicates, if any
336  $colPosList = implode(',', array_unique(array_map('intval', $colPosIds)));
337  // Finally, add the content of the column selector to the content:
338  $code .= $posMap->printContentElementColumns($this->id, 0, $colPosList, 1, $this->R_URI);
339  $this->content .= '<h2>' . $lang->getLL('2_selectPosition', true) . '</h2><div>' . $code . '</div>';
340  }
341  } else {
342  // In case of no access:
343  $this->content = '';
344  $this->content .= '<h1>' . $lang->getLL('newContentElement') . '</h1>';
345  }
346  $this->content .= '</form>';
347  // Setting up the buttons and markers for docheader
348  $this->getButtons();
349  }
350 
354  protected function getButtons()
355  {
356  $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
357  if ($this->R_URI) {
358  $backButton = $buttonBar->makeLinkButton()
359  ->setHref($this->R_URI)
360  ->setTitle($this->getLanguageService()->getLL('goBack'))
361  ->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
362  'actions-view-go-back',
364  ));
365  $buttonBar->addButton($backButton);
366  }
367  $cshButton = $buttonBar->makeHelpButton()->setModuleName('xMOD_csh_corebe')->setFieldName('new_ce');
368  $buttonBar->addButton($cshButton);
369  }
370 
371  /***************************
372  *
373  * OTHER FUNCTIONS:
374  *
375  ***************************/
382  public function getWizardItems()
383  {
385  return $this->wizardArray();
386  }
387 
394  public function wizardArray()
395  {
396  $wizardItems = [];
397  if (is_array($this->config)) {
398  $wizards = $this->config['wizardItems.'];
399  $appendWizards = $this->wizard_appendWizards($wizards['elements.']);
400  if (is_array($wizards)) {
401  foreach ($wizards as $groupKey => $wizardGroup) {
402  $groupKey = rtrim($groupKey, '.');
403  $showItems = GeneralUtility::trimExplode(',', $wizardGroup['show'], true);
404  $showAll = in_array('*', $showItems, true);
405  $groupItems = [];
406  if (is_array($appendWizards[$groupKey . '.']['elements.'])) {
407  $wizardElements = array_merge((array)$wizardGroup['elements.'], $appendWizards[$groupKey . '.']['elements.']);
408  } else {
409  $wizardElements = $wizardGroup['elements.'];
410  }
411  if (is_array($wizardElements)) {
412  foreach ($wizardElements as $itemKey => $itemConf) {
413  $itemKey = rtrim($itemKey, '.');
414  if ($showAll || in_array($itemKey, $showItems)) {
415  $tmpItem = $this->wizard_getItem($groupKey, $itemKey, $itemConf);
416  if ($tmpItem) {
417  $groupItems[$groupKey . '_' . $itemKey] = $tmpItem;
418  }
419  }
420  }
421  }
422  if (!empty($groupItems)) {
423  $wizardItems[$groupKey] = $this->wizard_getGroupHeader($groupKey, $wizardGroup);
424  $wizardItems = array_merge($wizardItems, $groupItems);
425  }
426  }
427  }
428  }
429  // Remove elements where preset values are not allowed:
430  $this->removeInvalidElements($wizardItems);
431  return $wizardItems;
432  }
433 
438  public function wizard_appendWizards($wizardElements)
439  {
440  if (!is_array($wizardElements)) {
441  $wizardElements = [];
442  }
443  if (is_array($GLOBALS['TBE_MODULES_EXT']['xMOD_db_new_content_el']['addElClasses'])) {
444  foreach ($GLOBALS['TBE_MODULES_EXT']['xMOD_db_new_content_el']['addElClasses'] as $class => $path) {
445  require_once $path;
446  $modObj = GeneralUtility::makeInstance($class);
447  $wizardElements = $modObj->proc($wizardElements);
448  }
449  }
450  $returnElements = [];
451  foreach ($wizardElements as $key => $wizardItem) {
452  preg_match('/^[a-zA-Z0-9]+_/', $key, $group);
453  $wizardGroup = $group[0] ? substr($group[0], 0, -1) . '.' : $key;
454  $returnElements[$wizardGroup]['elements.'][substr($key, strlen($wizardGroup)) . '.'] = $wizardItem;
455  }
456  return $returnElements;
457  }
458 
465  public function wizard_getItem($groupKey, $itemKey, $itemConf)
466  {
467  $itemConf['title'] = $this->getLanguageService()->sL($itemConf['title']);
468  $itemConf['description'] = $this->getLanguageService()->sL($itemConf['description']);
469  $itemConf['tt_content_defValues'] = $itemConf['tt_content_defValues.'];
470  unset($itemConf['tt_content_defValues.']);
471  return $itemConf;
472  }
473 
479  public function wizard_getGroupHeader($groupKey, $wizardGroup)
480  {
481  return [
482  'header' => $this->getLanguageService()->sL($wizardGroup['header'])
483  ];
484  }
485 
495  public function removeInvalidElements(&$wizardItems)
496  {
497  // Get TCEFORM from TSconfig of current page
498  $row = ['pid' => $this->id];
499  $TCEFORM_TSconfig = BackendUtility::getTCEFORM_TSconfig('tt_content', $row);
500  $headersUsed = [];
501  // Traverse wizard items:
502  foreach ($wizardItems as $key => $cfg) {
503  // Exploding parameter string, if any (old style)
504  if ($wizardItems[$key]['params']) {
505  // Explode GET vars recursively
506  $tempGetVars = GeneralUtility::explodeUrl2Array($wizardItems[$key]['params'], true);
507  // If tt_content values are set, merge them into the tt_content_defValues array,
508  // unset them from $tempGetVars and re-implode $tempGetVars into the param string
509  // (in case remaining parameters are around).
510  if (is_array($tempGetVars['defVals']['tt_content'])) {
511  $wizardItems[$key]['tt_content_defValues'] = array_merge(
512  is_array($wizardItems[$key]['tt_content_defValues']) ? $wizardItems[$key]['tt_content_defValues'] : [],
513  $tempGetVars['defVals']['tt_content']
514  );
515  unset($tempGetVars['defVals']['tt_content']);
516  $wizardItems[$key]['params'] = GeneralUtility::implodeArrayForUrl('', $tempGetVars);
517  }
518  }
519  // If tt_content_defValues are defined...:
520  if (is_array($wizardItems[$key]['tt_content_defValues'])) {
521  $backendUser = $this->getBackendUser();
522  // Traverse field values:
523  foreach ($wizardItems[$key]['tt_content_defValues'] as $fN => $fV) {
524  if (is_array($GLOBALS['TCA']['tt_content']['columns'][$fN])) {
525  // Get information about if the field value is OK:
526  $config = &$GLOBALS['TCA']['tt_content']['columns'][$fN]['config'];
527  $authModeDeny = $config['type'] == 'select' && $config['authMode']
528  && !$backendUser->checkAuthMode('tt_content', $fN, $fV, $config['authMode']);
529  // explode TSconfig keys only as needed
530  if (!isset($removeItems[$fN])) {
531  $removeItems[$fN] = GeneralUtility::trimExplode(
532  ',',
533  $TCEFORM_TSconfig[$fN]['removeItems'],
534  true
535  );
536  }
537  if (!isset($keepItems[$fN])) {
538  $keepItems[$fN] = GeneralUtility::trimExplode(
539  ',',
540  $TCEFORM_TSconfig[$fN]['keepItems'],
541  true
542  );
543  }
544  $isNotInKeepItems = !empty($keepItems[$fN]) && !in_array($fV, $keepItems[$fN]);
545  if ($authModeDeny || $fN === 'CType' && (in_array($fV, $removeItems[$fN]) || $isNotInKeepItems)) {
546  // Remove element all together:
547  unset($wizardItems[$key]);
548  break;
549  } else {
550  // Add the parameter:
551  $wizardItems[$key]['params'] .= '&defVals[tt_content][' . $fN . ']=' . rawurlencode($this->getLanguageService()->sL($fV));
552  $tmp = explode('_', $key);
553  $headersUsed[$tmp[0]] = $tmp[0];
554  }
555  }
556  }
557  }
558  }
559  // remove headers without elements
560  foreach ($wizardItems as $key => $cfg) {
561  $tmp = explode('_', $key);
562  if ($tmp[0] && !$tmp[1] && !in_array($tmp[0], $headersUsed)) {
563  unset($wizardItems[$key]);
564  }
565  }
566  }
567 
573  protected function getLanguageService()
574  {
575  return $GLOBALS['LANG'];
576  }
577 
583  protected function getBackendUser()
584  {
585  return $GLOBALS['BE_USER'];
586  }
587 }
static getPagesTSconfig($id, $rootLine=null, $returnPartArray=false)
static readPageAccess($id, $perms_clause)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
static callUserFunction($funcName, &$params, &$ref, $checkPrefix='', $errorMode=0)
static implodeArrayForUrl($name, array $theArray, $str='', $skipBlank=false, $rawurlencodeParamName=false)
static explodeUrl2Array($string, $multidim=false)
static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
static beginsWith($haystack, $needle)
mainAction(ServerRequestInterface $request, ResponseInterface $response)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']