Skip to content

Commit

Permalink
[BUGFIX] Defer Icon resolving after assets paths have been built
Browse files Browse the repository at this point in the history
Fixes: #175
  • Loading branch information
nhovratov committed Apr 1, 2024
1 parent 6f8751e commit aad4704
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 12 deletions.
15 changes: 8 additions & 7 deletions Classes/Loader/ContentBlockLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
use TYPO3\CMS\ContentBlocks\Definition\ContentType\ContentTypeIcon;
use TYPO3\CMS\ContentBlocks\Definition\Factory\UniqueIdentifierCreator;
use TYPO3\CMS\ContentBlocks\Registry\ContentBlockRegistry;
use TYPO3\CMS\ContentBlocks\Service\ContentTypeIconResolver;
use TYPO3\CMS\ContentBlocks\Utility\ContentBlockPathUtility;
use TYPO3\CMS\ContentBlocks\Validation\ContentBlockNameValidator;
use TYPO3\CMS\ContentBlocks\Validation\PageTypeNameValidator;
Expand Down Expand Up @@ -62,10 +61,6 @@
* package part separated by a slash. The name parts must be lowercase and can
* be separated by dashes.
*
* @todo Asset publishing of the `Assets` folder happens during the runtime, as
* @todo opposed to the publishing of the extensions' Resources/Public folder in
* @todo the composer installation phase. This is not optimal.
*
* @internal Not part of TYPO3's public API.
*/
class ContentBlockLoader
Expand All @@ -76,6 +71,7 @@ public function __construct(
protected readonly LazyObjectInterface|PhpFrontend $cache,
protected readonly BasicsService $basicsService,
protected readonly PackageManager $packageManager,
protected readonly IconProcessor $iconProcessor,
) {}

public function load(): ContentBlockRegistry
Expand Down Expand Up @@ -117,6 +113,7 @@ public function loadUncached(): ContentBlockRegistry
$contentBlockRegistry = $this->fillContentBlockRegistry($loadedContentBlocks);

$this->publishAssets($loadedContentBlocks);
$this->iconProcessor->process();

return $contentBlockRegistry;
}
Expand Down Expand Up @@ -230,7 +227,9 @@ protected function loadSingleContentBlock(
$table = $yaml['table'];
$yaml = $this->basicsService->applyBasics($yaml);
$iconIdentifier = ContentBlockPathUtility::getIconNameWithoutFileExtension();
$contentBlockIcon = ContentTypeIconResolver::resolve(
$contentBlockIcon = new ContentTypeIcon();
$this->iconProcessor->addInstruction(
$contentBlockIcon,
$name,
$absolutePath,
$extPath,
Expand All @@ -242,13 +241,15 @@ protected function loadSingleContentBlock(
$pageIconHideInMenu = new ContentTypeIcon();
if ($contentType === ContentType::PAGE_TYPE) {
$iconIdentifierHideInMenu = ContentBlockPathUtility::getIconHideInMenuNameWithoutFileExtension();
$pageIconHideInMenu = ContentTypeIconResolver::resolve(
$this->iconProcessor->addInstruction(
$pageIconHideInMenu,
$name,
$absolutePath,
$extPath,
$iconIdentifierHideInMenu,
$contentType,
$table,
$typeName,
'-hide-in-menu'
);
}
Expand Down
77 changes: 77 additions & 0 deletions Classes/Loader/IconProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?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\ContentBlocks\Loader;

use TYPO3\CMS\ContentBlocks\Definition\ContentType\ContentType;
use TYPO3\CMS\ContentBlocks\Definition\ContentType\ContentTypeIcon;
use TYPO3\CMS\ContentBlocks\Service\ContentTypeIconResolver;

/**
* @internal Not part of TYPO3's public API.
*/
class IconProcessor
{
/** @var callable[] */
protected array $instructions = [];

public function process(): void
{
while ($instruction = array_shift($this->instructions)) {
$instruction();
}
}

public function addInstruction(
ContentTypeIcon $contentTypeIcon,
string $name,
string $absolutePath,
string $extPath,
string $identifier,
ContentType $contentType,
string $table,
int|string $typeName,
string $suffix = '',
): void {
$instruction = function () use (
$contentTypeIcon,
$name,
$absolutePath,
$extPath,
$identifier,
$contentType,
$table,
$typeName,
$suffix,
) {
$resultIcon = ContentTypeIconResolver::resolve(
$name,
$absolutePath,
$extPath,
$identifier,
$contentType,
$table,
$typeName,
$suffix,
);
$contentTypeIcon->iconIdentifier = $resultIcon->iconIdentifier;
$contentTypeIcon->iconPath = $resultIcon->iconPath;
$contentTypeIcon->iconProvider = $resultIcon->iconProvider;
};
$this->instructions[] = $instruction;
}
}
27 changes: 22 additions & 5 deletions Classes/Service/ContentTypeIconResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,23 @@ public static function resolve(
$iconProviderClass = $fileExtension === 'svg' ? SvgIconProvider::class : BitmapIconProvider::class;
$contentTypeIcon->iconPath = $icon;
$contentTypeIcon->iconProvider = $iconProviderClass;
$contentTypeIcon->iconIdentifier = self::buildTypeIconIdentifier($table, $typeName, $contentTypeIcon->iconPath, $suffix);
$contentTypeIcon->iconIdentifier = self::buildTypeIconIdentifier(
$table,
$typeName,
$contentTypeIcon->iconPath,
$suffix
);
return $contentTypeIcon;
}
$contentTypeIcon = new ContentTypeIcon();
$contentTypeIcon->iconPath = self::getDefaultContentTypeIcon($contentType);
$contentTypeIcon->iconProvider = SvgIconProvider::class;
$contentTypeIcon->iconIdentifier = self::buildTypeIconIdentifier($table, $typeName, $contentTypeIcon->iconPath, $suffix);
$contentTypeIcon->iconIdentifier = self::buildTypeIconIdentifier(
$table,
$typeName,
$contentTypeIcon->iconPath,
$suffix
);
return $contentTypeIcon;
}

Expand All @@ -81,14 +91,21 @@ public static function getDefaultContentTypeIcon(ContentType $contentType): stri
* We add a part of the md5 hash here in order to mitigate browser caching issues when changing the Content Block
* Icon. Otherwise, the icon identifier would always be the same and stored in the local storage.
*/
protected static function buildTypeIconIdentifier(string $table, int|string $typeName, string $iconPath, string $suffix = ''): string
{
protected static function buildTypeIconIdentifier(
string $table,
int|string $typeName,
string $iconPath,
string $suffix = ''
): string {
$typeIconIdentifier = $table . '-' . $typeName . $suffix;
$absolutePath = GeneralUtility::getFileAbsFileName($iconPath);
if ($absolutePath !== '') {
$contents = @file_get_contents($absolutePath);
if ($contents === false) {
return '';
throw new \RuntimeException(
'Icon in path ' . $iconPath . ' is not available.',
1711970286
);
}
$hash = md5($contents);
$hasSubString = substr($hash, 0, 7);
Expand Down

0 comments on commit aad4704

Please sign in to comment.