TYPO3 v15 dev-main snapshot ()

This commit is contained in:
2026-08-10 22:31:00 +02:00
commit f9941541b7
1178 changed files with 135377 additions and 0 deletions
@@ -0,0 +1,259 @@
<?php
declare(strict_types=1);
/*
* 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!
*/
namespace TYPO3\CMS\Backend\View\BackendLayout\Grid;
use TYPO3\CMS\Backend\Routing\UriBuilder;
use TYPO3\CMS\Backend\View\PageLayoutContext;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Localization\LanguageService;
use TYPO3\CMS\Core\Page\ContentSlideMode;
use TYPO3\CMS\Core\Schema\Capability\TcaSchemaCapability;
use TYPO3\CMS\Core\Schema\TcaSchemaFactory;
use TYPO3\CMS\Core\Type\Bitmask\Permission;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Grid Column
*
* Object representation (model/proxy) for a single column from a grid defined
* in a BackendLayout. Stores GridColumnItem representations of content records
* and provides getter methods which return various properties associated with
* a single column, e.g. the "edit all elements in content" URL and the "add
* new content element" URL of the button that is placed in the top of columns
* in the page layout.
*
* Accessed from Fluid templates.
*
* @internal
*/
class GridColumn
{
/**
* @var GridColumnItem[]
*/
protected array $items = [];
protected readonly ?int $columnNumber;
protected readonly string $columnName;
protected readonly string $icon;
protected readonly int $colSpan;
protected readonly int $rowSpan;
protected readonly ?string $identifier;
protected readonly ContentSlideMode $slideMode;
/**
* @param array<string, mixed> $definition
*/
public function __construct(
protected readonly PageLayoutContext $context,
protected readonly array $definition,
protected readonly string $table = 'tt_content'
) {
$this->columnNumber = isset($definition['colPos']) ? (int)$definition['colPos'] : null;
$this->columnName = (string)($definition['name'] ?? 'default');
$this->icon = (string)($definition['icon'] ?? '');
$this->colSpan = (int)($definition['colspan'] ?? 1);
$this->rowSpan = (int)($definition['rowspan'] ?? 1);
$this->identifier = isset($definition['identifier']) ? (string)$definition['identifier'] : null;
$this->slideMode = ContentSlideMode::tryFrom($definition['slideMode'] ?? null);
}
public function getContext(): PageLayoutContext
{
return $this->context;
}
/**
* @return array<string, mixed>
*/
public function getDefinition(): array
{
return $this->definition;
}
public function isActive(): bool
{
return $this->columnNumber !== null && in_array($this->columnNumber, $this->context->getDrawingConfiguration()->getActiveColumns());
}
public function addItem(GridColumnItem $item): void
{
$this->items[] = $item;
}
/**
* @return GridColumnItem[]
*/
public function getItems(): iterable
{
return $this->items;
}
public function getColumnNumber(): ?int
{
return $this->columnNumber;
}
public function getColumnName(): string
{
return $this->columnName;
}
public function getIcon(): string
{
return $this->icon;
}
public function getColSpan(): int
{
if ($this->context->getDrawingConfiguration()->isLanguageComparisonMode()) {
return 1;
}
return $this->colSpan;
}
public function getRowSpan(): int
{
if ($this->context->getDrawingConfiguration()->isLanguageComparisonMode()) {
return 1;
}
return $this->rowSpan;
}
public function getIdentifier(): ?string
{
return $this->identifier;
}
public function getIdentifierCleaned(): string
{
return strtolower((string)preg_replace('/[^a-zA-Z0-9_-]/', '', (string)$this->identifier));
}
public function getSlideMode(): ContentSlideMode
{
return $this->slideMode;
}
/**
* @return int[]
*/
public function getAllContainedItemUids(): array
{
$uids = [];
foreach ($this->items as $columnItem) {
$uids[] = $columnItem->getRecord()->getUid();
}
return $uids;
}
public function getEditUrl(): ?string
{
if (empty($this->items)) {
return null;
}
$pageRecord = $this->context->getPageRecord();
if (!$this->getBackendUser()->doesUserHaveAccess($pageRecord, Permission::CONTENT_EDIT)
|| !$this->getBackendUser()->checkLanguageAccess($this->context->getSiteLanguage())) {
return null;
}
$uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
return (string)$uriBuilder->buildUriFromRoute('record_edit', [
'edit' => [
$this->table => [
implode(',', $this->getAllContainedItemUids()) => 'edit',
],
],
'module' => 'web_layout',
'returnUrl' => $this->context->getReturnUrl(),
]);
}
public function getNewContentUrl(): string
{
$uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
$pageId = $this->context->getPageId();
return (string)$uriBuilder->buildUriFromRoute('new_content_element_wizard', [
'id' => $pageId,
'sys_language_uid' => $this->context->getSiteLanguage()->getLanguageId(),
'colPos' => $this->getColumnNumber(),
'uid_pid' => $pageId,
'returnUrl' => $this->context->getReturnUrl(),
]);
}
public function getTitle(): string
{
$columnNumber = $this->getColumnNumber();
$colTitle = '';
foreach ($this->context->getBackendLayout()->getUsedColumns() as $colPos => $title) {
if ($colPos === $columnNumber) {
$colTitle = $this->getLanguageService()->sL($title);
}
}
return $colTitle;
}
public function getTitleInaccessible(): string
{
return $this->getLanguageService()->sL($this->columnName) . ' (' . $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:noAccess') . ')';
}
public function getTitleUnassigned(): string
{
return $this->getLanguageService()->sL($this->columnName) . ' (' . $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:notAssigned') . ')';
}
public function isUnassigned(): bool
{
return $this->columnName !== 'unused' && $this->columnNumber === null;
}
public function isUnused(): bool
{
return $this->columnName === 'unused' && $this->columnNumber === null;
}
public function isContentEditable(): bool
{
if ($this->columnName === 'unused' || $this->columnNumber === null) {
return false;
}
if ($this->getBackendUser()->isAdmin()) {
return true;
}
$pageRecord = $this->context->getPageRecord();
return $this->getBackendUser()->doesUserHaveAccess($pageRecord, Permission::CONTENT_EDIT)
&& $this->getBackendUser()->checkLanguageAccess($this->context->getSiteLanguage())
&& (
!($pagesSchema = GeneralUtility::makeInstance(TcaSchemaFactory::class)->get('pages'))->hasCapability(TcaSchemaCapability::EditLock)
|| !($pageRecord[$pagesSchema->getCapability(TcaSchemaCapability::EditLock)->getFieldName()] ?? false)
);
}
protected function getLanguageService(): LanguageService
{
return $GLOBALS['LANG'];
}
protected function getBackendUser(): BackendUserAuthentication
{
return $GLOBALS['BE_USER'];
}
}