Skip to content

Commit

Permalink
[TASK] Add LanguageAspect to Contexts
Browse files Browse the repository at this point in the history
This change adds a new Aspect called "Language" which bundles
most existing TypoScript options on frontend language fetching.
A factory allows to migrate the logic from TSFE.

Major / Important Changes:
- RootlineUtility is decoupled from PageRepository
- TSFE->sys_language_mode is not necessary anymore
- TSFE->sys_language_contentOL can be substituted by "overlayType" of Aspect
- A new PageRepository->getLanguageOverlay() bundles all other methods
- A lot of common public properties in TSFE are now deprecated

Next steps:
- Isolate calls from RootlineUtility/PageRepository more from each other and from TSFE
- Migrate PageRepository "-1" parameters to "null"
- Migrate usages PageRepository->getRootline() to RootlineUtility::__construct()
- Then deprecate PageRepository->getRootLine()
- Migrate Extbase QuerySettings to Contexts

Resolves: #85543
Releases: master
Change-Id: I8d177222a244a8d1fd66a884e9fc50b107f27e20
Reviewed-on: https://review.typo3.org/57424
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Andreas Fernandez <a.fernandez@scripting-base.de>
Tested-by: Andreas Fernandez <a.fernandez@scripting-base.de>
  • Loading branch information
bmack authored and andreaskienast committed Jul 13, 2018
1 parent 7a17c8d commit 4003c5f
Show file tree
Hide file tree
Showing 27 changed files with 844 additions and 277 deletions.
27 changes: 22 additions & 5 deletions typo3/sysext/adminpanel/Classes/Service/EditToolbarService.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,24 @@

namespace TYPO3\CMS\Adminpanel\Service;

/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/

use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
use TYPO3\CMS\Backend\Routing\UriBuilder;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Context\LanguageAspect;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer;
use TYPO3\CMS\Core\Imaging\Icon;
Expand All @@ -30,13 +45,15 @@ class EditToolbarService
*/
public function createToolbar(): string
{
/** @var LanguageAspect $languageAspect */
$languageAspect = GeneralUtility::makeInstance(Context::class)->getAspect('language');
$iconFactory = GeneralUtility::makeInstance(IconFactory::class);
$tsfe = $this->getTypoScriptFrontendController();
// If mod.newContentElementWizard.override is set, use that extension's create new content wizard instead:
$moduleName = BackendUtility::getPagesTSconfig($tsfe->page['uid'])['mod.']['newContentElementWizard.']['override'] ?? 'new_content_element';
$uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
$perms = $this->getBackendUser()->calcPerms($tsfe->page);
$langAllowed = $this->getBackendUser()->checkLanguageAccess($tsfe->sys_language_uid);
$langAllowed = $this->getBackendUser()->checkLanguageAccess($languageAspect->getId());
$id = $tsfe->id;
$returnUrl = GeneralUtility::getIndpEnv('REQUEST_URI');
$classes = 'typo3-adminPanel-btn typo3-adminPanel-btn-default';
Expand Down Expand Up @@ -69,8 +86,8 @@ public function createToolbar(): string
'id' => $id,
'returnUrl' => $returnUrl,
];
if (!empty($tsfe->sys_language_uid)) {
$linkParameters['sys_language_uid'] = $tsfe->sys_language_uid;
if (!empty($languageAspect->getId())) {
$linkParameters['sys_language_uid'] = $languageAspect->getId();
}
$link = (string)$uriBuilder->buildUriFromRoute($moduleName, $linkParameters);
$icon = $iconFactory->getIcon('actions-add', Icon::SIZE_SMALL)->render();
Expand Down Expand Up @@ -156,7 +173,7 @@ public function createToolbar(): string
}

// Edit Page Overlay
if ($perms & Permission::PAGE_EDIT && $tsfe->sys_language_uid && $langAllowed) {
if ($perms & Permission::PAGE_EDIT && $languageAspect->getId() > 0 && $langAllowed) {
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable('pages');
$queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
Expand All @@ -170,7 +187,7 @@ public function createToolbar(): string
),
$queryBuilder->expr()->eq(
$GLOBALS['TCA']['pages']['ctrl']['languageField'],
$queryBuilder->createNamedParameter($tsfe->sys_language_uid, \PDO::PARAM_INT)
$queryBuilder->createNamedParameter($languageAspect->getId(), \PDO::PARAM_INT)
)
)
->setMaxResults(1)
Expand Down
4 changes: 4 additions & 0 deletions typo3/sysext/core/Classes/Context/Context.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
* - visibility
* - frontend.user
* - backend.user
* - language
*/
class Context implements SingletonInterface
{
Expand Down Expand Up @@ -79,6 +80,9 @@ public function __construct(array $defaultAspects = [])
if (!$this->hasAspect('workspace')) {
$this->setAspect('workspace', new WorkspaceAspect());
}
if (!$this->hasAspect('language')) {
$this->setAspect('language', new LanguageAspect());
}
}

/**
Expand Down
208 changes: 208 additions & 0 deletions typo3/sysext/core/Classes/Context/LanguageAspect.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
<?php
declare(strict_types = 1);
namespace TYPO3\CMS\Core\Context;

/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/

use TYPO3\CMS\Core\Context\Exception\AspectPropertyNotFoundException;

/**
* The Aspect is usually available as "language" property, and
* can be used to find out the "overlay"/data retrieval strategy.
*
*
* "id" (languageId, int)
* - formally known as $TSFE->sys_language_uid
* - the requested language of the current page (frontend)
* - used in menus and links to generate "links in language with this ID"
*
* "contentId" (int)
* - formally known as $TSFE->sys_language_content
* - the language of records to be fetched
* - if empty, "languageId" is used.
*
* "fallbackChain"
* - when "fallback" go with
* - depends what "contentId" value should be set
* - defined in config.sys_language_mode (strict/content_fallback:4,5,stop/ignore?)
* - previously known as $TSFE->sys_language_mode
* - defines "contentId" based on "if the current page is available in this language"
* - "strict"
* - "fallback" if current page is not available, check the fallbackChain"
* - "fallbackAndIgnore"
*
* "overlays"
* - defines which way the records should be fetched from ($TSFE->sys_language_contentOL and config.sys_language_overlay)
* - usually you fetch language 0 and -1, then take the "contentId" and "overlay" them
* - here you have two choices
* 1. "on" if there is no overlay, do not render the default language records ("hideNonTranslated")
* 2. "mixed" - if there no overlay, just keep the default language, possibility to have mixed languages - config.sys_language_overlay = 1
* 3. "off" - do not do overlay, only fetch records available in the current "contentId" (see above), and do not care about overlays or fallbacks - fallbacks could be an option here, actually that is placed on top
* 4. "includeFloating" - on + includeRecordsWithoutDefaultTranslation
*/
class LanguageAspect implements AspectInterface
{
/**
* @var int
*/
protected $id = 0;

/**
* @var int
*/
protected $contentId = 0;

/**
* @var array
*/
protected $fallbackChain = [];

/**
* @var string
*/
protected $overlayType;

public const OVERLAYS_OFF = 'off'; // config.sys_language_overlay = 0
public const OVERLAYS_MIXED = 'mixed'; // config.sys_language_overlay = 1 (keep the ones that are only available in default language)
public const OVERLAYS_ON = 'on'; // "hideNonTranslated"
public const OVERLAYS_ON_WITH_FLOATING = 'includeFloating'; // "hideNonTranslated" + records that are only available in polish

/**
* Create the default language
*
* @param int $id
* @param int|null $contentId
* @param string $overlayType
* @param array $fallbackChain
*/
public function __construct(int $id = 0, int $contentId = null, string $overlayType = self::OVERLAYS_ON_WITH_FLOATING, array $fallbackChain = [])
{
$this->overlayType = $overlayType;
$this->id = $id;
$this->contentId = $contentId === null ? $this->id : $contentId;
$this->fallbackChain = $fallbackChain;
}

/**
* Used language overlay
*
* @return string
*/
public function getOverlayType(): string
{
return $this->overlayType;
}

/**
* Returns the language ID the current page was requested,
* this is relevant when building menus or links to other pages.
*
* @return int
*/
public function getId(): int
{
return $this->id;
}

/**
* Contains the language UID of the content records that should be overlaid to would be fetched.
* This is especially useful when a page requested with language=4 should fall back to showing
* content of language=2 (see fallbackChain)
*
* @return int
*/
public function getContentId(): int
{
return $this->contentId;
}

public function getFallbackChain(): array
{
return $this->fallbackChain;
}

/**
* Whether overlays should be done
*
* @return bool
*/
public function doOverlays(): bool
{
return $this->contentId > 0 && $this->overlayType !== self::OVERLAYS_OFF;
}

/**
* Previously known as TSFE->sys_language_mode, here for compatibility reasons
*
* @return string
*/
public function getLegacyLanguageMode(): string
{
if ($this->fallbackChain === ['off']) {
return '';
}
if (empty($this->fallbackChain)) {
return 'strict';
}
if ($this->fallbackChain === [-1]) {
return 'ignore';
}
return 'content_fallback';
}

/**
* Previously known as TSFE->sys_language_contentOL, here for compatibility reasons
*
* @return string
*/
public function getLegacyOverlayType(): string
{
switch ($this->overlayType) {
case self::OVERLAYS_ON_WITH_FLOATING:
case self::OVERLAYS_ON:
return 'hideNonTranslated';
case self::OVERLAYS_MIXED:
return '1';
case self::OVERLAYS_OFF:
default:
return '0';
}
}

/**
* Fetch a property.
*
* @param string $name
* @return int|string|array
* @throws AspectPropertyNotFoundException
*/
public function get(string $name)
{
switch ($name) {
case 'id':
return $this->id;
case 'contentId':
return $this->contentId;
case 'fallbackChain':
return $this->fallbackChain;
case 'overlayType':
return $this->overlayType;
case 'legacyLanguageMode':
return $this->getLegacyLanguageMode();
case 'legacyOverlayType':
return $this->getLegacyOverlayType();
}
throw new AspectPropertyNotFoundException('Property "' . $name . '" not found in Aspect "' . __CLASS__ . '".', 1530448504);
}
}
Loading

0 comments on commit 4003c5f

Please sign in to comment.