Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Classes/Command/CheckContentEscapingCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ViewHelperNode;
use TYPO3Fluid\Fluid\Core\Parser\TemplateParser;
use TYPO3Fluid\Fluid\ViewHelpers\Format\RawViewHelper;
use function array_keys;

class CheckContentEscapingCommand extends Command
{
Expand Down Expand Up @@ -69,14 +70,14 @@ protected function configure(): void

protected function execute(InputInterface $input, OutputInterface $output): int
{
$componentNamespaces = $this->componentLoader->getNamespaces();
$componentNamespaces = array_keys($this->componentLoader->getNamespaces());
$templateFiles = $this->discoverTemplateFiles();

$progress = new ProgressBar($output, count($componentNamespaces) + count($templateFiles));
$progress->start();

// Determine which components use {content -> f:format.raw()} or similar
foreach ($componentNamespaces as $namespace => $path) {
foreach ($componentNamespaces as $namespace) {
foreach ($this->componentLoader->findComponentsInNamespace($namespace) as $className => $file) {
try {
$template = $this->parseTemplate($file);
Expand Down
5 changes: 3 additions & 2 deletions Classes/Service/XsdGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use SMS\FluidComponents\Utility\ComponentLoader;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3Fluid\Fluid\Core\ViewHelper\ArgumentDefinition;
use function array_keys;

class XsdGenerator
{
Expand Down Expand Up @@ -127,8 +128,8 @@ protected function getDefaultPrefixForNamespace(string $namespace): int|string
public function generateXsd(string $path, ?string $namespace = null): array
{
$generatedNameSpaces = [];
$namespaces = $this->componentLoader->getNamespaces();
foreach ($namespaces as $registeredNamespace => $registeredNamepacePath) {
$namespaces = array_keys($this->componentLoader->getNamespaces());
foreach ($namespaces as $registeredNamespace) {
if ($namespace === null || $registeredNamespace === $namespace) {
$components = $this->componentLoader->findComponentsInNamespace($registeredNamespace);
$filePath = rtrim((string) $path, DIRECTORY_SEPARATOR) .
Expand Down
47 changes: 29 additions & 18 deletions Classes/Utility/ComponentLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class ComponentLoader implements \TYPO3\CMS\Core\SingletonInterface
{
/**
* Registered component namespaces.
* @var array<string, list<string>>
*/
protected array $namespaces = [];

Expand All @@ -23,14 +24,15 @@ public function __construct()

/**
* Adds a new component namespace.
* @param string|list<string> $path
*/
public function addNamespace(string $namespace, string $path): self
public function addNamespace(string $namespace, string|array $path): self
{
// Sanitize namespace data
$namespace = $this->sanitizeNamespace($namespace);
$path = $this->sanitizePath($path);
$paths = array_values(array_map($this->sanitizePath(...), (array)$path));

$this->namespaces[$namespace] = $path;
$this->namespaces[$namespace] = $paths;
return $this;
}

Expand Down Expand Up @@ -81,21 +83,24 @@ public function findComponent(string $class, string $ext = '.html'): string|null

// Walk through available namespaces, ordered from specific to unspecific
$class = ltrim($class, '\\');
foreach ($this->namespaces as $namespace => $path) {
foreach ($this->namespaces as $namespace => $paths) {
// No match, skip to next
if (!str_starts_with($class, $namespace . '\\')) {
continue;
}

$componentParts = explode('\\', trim(substr($class, strlen($namespace)), '\\'));

$componentPath = $path . DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, $componentParts);
$componentFile = $componentPath . DIRECTORY_SEPARATOR . end($componentParts) . $ext;
foreach (array_reverse($paths) as $path) {
$componentPath = $path . DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, $componentParts);
$componentFile = $componentPath . DIRECTORY_SEPARATOR . end($componentParts) . $ext;

// Check if component file exists
if (file_exists($componentFile)) {
$this->componentsCache[$cacheIdentifier] = $componentFile;
return $componentFile;
// Check if component file exists
if (file_exists($componentFile)) {
$this->componentsCache[$cacheIdentifier] = $componentFile;
// first path found is the most specific one, so we can return it immediately
return $componentFile;
}
}
}

Expand All @@ -110,17 +115,23 @@ public function findComponent(string $class, string $ext = '.html'): string|null
*/
public function findComponentsInNamespace(string $namespace, string $ext = '.html'): array
{
if (!isset($this->namespaces[$namespace]) || !is_dir($this->namespaces[$namespace])) {
$paths = $this->namespaces[$namespace] ?? null;
if (!$paths) {
return [];
}

$scannedPaths = [];
return $this->scanForComponents(
$this->namespaces[$namespace],
$ext,
$namespace,
$scannedPaths
);
$components = [];
foreach ($paths as $path) {
if (!is_dir($path)) {
continue;
}

$scannedPaths = [];
// overwrite previous locations with newer locations
$components = [...$components, ...$this->scanForComponents($path, $ext, $namespace, $scannedPaths)];
}

return $components;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ or [via composer](https://packagist.org/packages/sitegeist/fluid-components):
2. Define the component namespace in your *ext_localconf.php*:

```php
$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['fluid_components']['namespaces']['VENDOR\\MyExtension\\Components'] =
$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['fluid_components']['namespaces']['VENDOR\\MyExtension\\Components'][] =
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('my_extension', 'Resources/Private/Components');
```

Expand Down
2 changes: 1 addition & 1 deletion Tests/Functional/ComponentRendererTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public function setUp(): void
// Register test components
$this->componentNamespaces = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['fluid_components']['namespaces'] ?? null;
$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['fluid_components']['namespaces'] = [
$this->testNamespace => realpath(__DIR__ . '/../Fixtures/Functional/Components/'),
$this->testNamespace => [realpath(__DIR__ . '/../Fixtures/Functional/Components/')],
];

// Register and then disable fluid cache
Expand Down
2 changes: 1 addition & 1 deletion Tests/Unit/Domain/Model/LabelsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ protected function setUp(): void
parent::setUp();

$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['fluid_components']['namespaces'] = [
'SMS\FluidComponents\Tests' => realpath(__DIR__ . '/../../../Fixtures/Unit/ComponentLoader'),
'SMS\FluidComponents\Tests' => [realpath(__DIR__ . '/../../../Fixtures/Unit/ComponentLoader')],
];
}

Expand Down
47 changes: 30 additions & 17 deletions Tests/Unit/Utility/ComponentLoaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,35 @@ public static function addNamespaceProvider()
'\\Vendor\\Extension\\Category\\',
'/path/to/components',
[
'Vendor\\Extension\\Category' => '/path/to/components',
'Vendor\\Extension\\Category' => ['/path/to/components'],
],
],
'pathWithTrailingSlash' => [
'Vendor\\Extension\\Category\\',
'/path/to/components/',
[
'Vendor\\Extension\\Category' => '/path/to/components',
'Vendor\\Extension\\Category' => ['/path/to/components'],
],
],
'pathsWithTrailingSlash' => [
'Vendor\\Extension\\Category\\',
[
'/path/to/components',
'/path/to/components_overwrites',
],
[
'Vendor\\Extension\\Category' => [
'/path/to/components',
'/path/to/components_overwrites',
],
],
],
];
}

#[Test]
#[DataProvider('addNamespaceProvider')]
public function addNamespace(string $namespace, string $path, array $namespaces): void
public function addNamespace(string $namespace, string|array $path, array $namespaces): void
{
$this->loader->addNamespace($namespace, $path);
$this->assertEquals(
Expand Down Expand Up @@ -74,22 +87,22 @@ public static function setNamespacesProvider()
return [
'case1' => [
[
'Sitegeist\\Fixtures\\ComponentLoader' => '/case1/path1',
'Sitegeist\\Fixtures\\Component\\Loader' => '/case1/path2',
'Sitegeist\\Fixtures\\ComponentLoader\\Test' => '/case1/path3',
'Vendor\\Test\\Namespace' => '/case1/path4',
'\\Sitegeist\\Fixtures\\ComponentLoader' => '/case1/path5',
'\\Sitegeist\\Fixtures\\ComponentLoader\\' => '/case1/path6',
'\\Sitegeist\\Fixtures\\AnotherTest\\' => '/case1/path7',
'\\Sitegeist\\Fixtures\\Test\\' => '/case1/path8',
'Sitegeist\\Fixtures\\ComponentLoader' => ['/case1/path1'],
'Sitegeist\\Fixtures\\Component\\Loader' => ['/case1/path2'],
'Sitegeist\\Fixtures\\ComponentLoader\\Test' => ['/case1/path3'],
'Vendor\\Test\\Namespace' => ['/case1/path4'],
'\\Sitegeist\\Fixtures\\ComponentLoader' => ['/case1/path5'],
'\\Sitegeist\\Fixtures\\ComponentLoader\\' => ['/case1/path6'],
'\\Sitegeist\\Fixtures\\AnotherTest\\' => ['/case1/path7'],
'\\Sitegeist\\Fixtures\\Test\\' => ['/case1/path8'],
],
[
'Vendor\\Test\\Namespace' => '/case1/path4',
'Sitegeist\\Fixtures\\Test' => '/case1/path8',
'Sitegeist\\Fixtures\\AnotherTest' => '/case1/path7',
'Sitegeist\\Fixtures\\ComponentLoader\\Test' => '/case1/path3',
'Sitegeist\\Fixtures\\ComponentLoader' => '/case1/path6',
'Sitegeist\\Fixtures\\Component\\Loader' => '/case1/path2',
'Vendor\\Test\\Namespace' => ['/case1/path4'],
'Sitegeist\\Fixtures\\Test' => ['/case1/path8'],
'Sitegeist\\Fixtures\\AnotherTest' => ['/case1/path7'],
'Sitegeist\\Fixtures\\ComponentLoader\\Test' => ['/case1/path3'],
'Sitegeist\\Fixtures\\ComponentLoader' => ['/case1/path6'],
'Sitegeist\\Fixtures\\Component\\Loader' => ['/case1/path2'],
],
],
];
Expand Down