Skip to content
Snippets Groups Projects
Commit 7f68e0a6 authored by Simon Praetorius's avatar Simon Praetorius Committed by Christian Kuhn
Browse files

[FEATURE] Command to generate Fluid schema files

The XSD schema generator, added with Fluid Standalone 2.12,
is applied to TYPO3's Fluid integration. This provides
autocompletion for supporting IDEs (like PhpStorm) by executing
the CLI command added with this patch.

Resolves: #104114
Releases: main
Change-Id: Id9f996820483e5af21506cdde2221b2be65a38d8
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/84720


Tested-by: default avatarStefan Bürk <stefan@buerk.tech>
Reviewed-by: default avatarBenni Mack <benni@typo3.org>
Tested-by: default avatarChristian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: default avatarChristian Kuhn <lolli@schwarzbu.ch>
Tested-by: default avatarBenni Mack <benni@typo3.org>
Tested-by: default avatarcore-ci <typo3@b13.com>
Reviewed-by: default avatarStefan Bürk <stefan@buerk.tech>
parent f9dd9cb4
Branches
Tags
No related merge requests found
.. include:: /Includes.rst.txt
.. _feature-104114-1719419341:
=========================================================
Feature: #104114 - Command to generate Fluid schema files
=========================================================
See :issue:`104114`
Description
===========
With Fluid Standalone 2.12, a new implementation of the XSD schema generator has
been introduced, which was previously a separate composer package. These XSD files
allow IDEs to provide autocompletion for ViewHelper arguments in Fluid templates,
provided that they are included in the template by using the xmlns syntax:
.. code-block:: html
<html
xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
xmlns:my="http://typo3.org/ns/Vendor/MyPackage/ViewHelpers"
data-namespace-typo3-fluid="true"
>
A new CLI command has been defined to apply Fluid's new schema generator to TYPO3's
Fluid integration. New Fluid APIs are used to find all ViewHelpers that exist in
the current project (based on the composer autoloader). Then, TYPO3's configuration
is checked for any merged Fluid namespaces (like `f:`, which consists of both
Fluid Standalone and EXT:fluid ViewHelpers which in some cases override each other).
After that consolidation, `*.xsd` files are created in `var/transient/` using another
API from Fluid Standalone. These files which will automatically get picked up by
supporting IDEs (like PhpStorm) to provide autocompletion in template files.
Impact
======
To get autocompletion for all available ViewHelpers in supporting IDEs, the following
CLI command can be executed in local development environments:
::
vendor/bin/typo3 fluid:schema:generate
.. index:: CLI, Fluid, ext:fluid
<?php
/*
* 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\Fluid\Command;
use Composer\Autoload\ClassLoader;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use TYPO3\CMS\Core\Core\Environment;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3Fluid\Fluid\Schema\SchemaGenerator;
use TYPO3Fluid\Fluid\Schema\ViewHelperFinder;
/**
* Generate schema files from fluid view helpers
*
* @internal: Specific command implementation, not API itself.
*/
#[AsCommand('fluid:schema:generate', 'Generate XSD schema files for all available ViewHelpers in var/transient/')]
final class SchemaCommand extends Command
{
public function __construct(private readonly ClassLoader $classLoader)
{
parent::__construct();
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$allViewHelpers = (new ViewHelperFinder())->findViewHelpersInComposerProject($this->classLoader);
// Group ViewHelpers by xml namespace to split them into xsd files later
$xsdFiles = $groupedByNamespace = [];
foreach ($allViewHelpers as $viewHelper) {
$xsdFiles[$viewHelper->xmlNamespace] ??= [];
$xsdFiles[$viewHelper->xmlNamespace][] = $viewHelper;
$groupedByNamespace[$viewHelper->namespace] ??= [];
$groupedByNamespace[$viewHelper->namespace][] = $viewHelper;
}
// Special handling of TYPO3's global ViewHelper namespaces which allows
// merging of several PHP namespaces into one Fluid namespace. If a configured
// global Fluid namespace has more than one PHP namespace, ViewHelpers can be
// overridden by subsequent namespaces if they are defined with the same name.
// For example, both Fluid Standalone and EXT:fluid define <f:render>,
// but EXT:fluid is the higher item in the namespace array, so it will be part
// of the xsd file, while the <f:render> from Fluid Standalone will be omitted.
foreach ($GLOBALS['TYPO3_CONF_VARS']['SYS']['fluid']['namespaces'] ?? [] as $mergedNamespace) {
// If a global namespace has only one item, it is already covered by the
// default handling above
if (count($mergedNamespace) < 2) {
continue;
}
// Last PHP namespace defines the xml namespace
$targetNamespace = end($mergedNamespace);
if (!isset($groupedByNamespace[$targetNamespace])) {
continue;
}
$xmlNamespace = $groupedByNamespace[$targetNamespace][0]->xmlNamespace;
// Combine PHP namespaces into one XML namespace
// Subsequent ViewHelpers with the same name can override
$xsdFiles[$xmlNamespace] = [];
foreach ($mergedNamespace as $namespace) {
foreach ($groupedByNamespace[$namespace] ?? [] as $viewHelper) {
$xsdFiles[$xmlNamespace][$viewHelper->name] = $viewHelper;
}
}
$xsdFiles[$xmlNamespace] = array_values($xsdFiles[$xmlNamespace]);
}
// Create transient folder if necessary
$temporaryPath = Environment::getVarPath() . '/transient/';
if (!is_dir($temporaryPath)) {
GeneralUtility::mkdir_deep($temporaryPath);
}
// Remove existing schema files in transient folder
$existingSchemaFiles = GeneralUtility::getFilesInDir($temporaryPath, 'xsd');
foreach ($existingSchemaFiles as $file) {
if (str_starts_with($file, 'schema_')) {
unlink($temporaryPath . $file);
}
}
// Write schema files to transient folder
foreach ($xsdFiles as $xmlNamespace => $viewHelpers) {
$schema = (new SchemaGenerator())->generate($xmlNamespace, $viewHelpers);
$fileName = str_replace('http://typo3.org/ns/', '', $xmlNamespace);
$fileName = str_replace('/', '_', $fileName);
$fileName = preg_replace('#[^0-9a-zA-Z_]#', '', $fileName);
GeneralUtility::writeFile($temporaryPath . 'schema_' . $fileName . '.xsd', $schema->asXml());
}
return Command::SUCCESS;
}
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment