*/}
+
+ )
+}
diff --git a/Build/Sources/helper/api/listAvailableExtensions.js b/Build/Sources/helper/api/listAvailableExtensions.js
new file mode 100644
index 000000000..c503da860
--- /dev/null
+++ b/Build/Sources/helper/api/listAvailableExtensions.js
@@ -0,0 +1,42 @@
+import axios from "axios";
+
+export async function listAvailableExtensions() {
+ const payload = {
+ id: 1,
+ method: "listWirings",
+ params: {
+ language: "extbaseModeling",
+ },
+ version: "json-rpc-2.0"
+ };
+
+ try {
+ const response = await axios.post(TYPO3.settings.ajaxUrls.eb_dispatchRpcAction, JSON.stringify(payload), {
+ headers: {
+ 'Content-Type': 'application/json',
+ "X-Requested-With": "XMLHttpRequest"
+ }
+ });
+
+ const success = response && response.data && response.data.success;
+ const error = response && response.data && response.data.error;
+
+ if(!success || error || !response) {
+ return createErrorMessage("Something went wrong on server side. Success: " + (error ? JSON.stringify(error) : ''));
+ }
+
+ return response.data;
+
+ } catch (error) {
+ console.error(error.message); //for error logging in production, it's better to use console.error instead of console.log
+ return createErrorMessage(error.message);
+ }
+}
+
+function createErrorMessage(msg) {
+ return {
+ success: false,
+ error: true,
+ message: msg
+ };
+}
diff --git a/Build/Sources/helper/converter/convertModulesToNodes.js b/Build/Sources/helper/converter/convertModulesToNodes.js
new file mode 100644
index 000000000..bc995baad
--- /dev/null
+++ b/Build/Sources/helper/converter/convertModulesToNodes.js
@@ -0,0 +1,74 @@
+function convertModulesToNodes(modules) {
+ for (let i = 0; i < modules.length; i++) {
+ // console.log(`Element ${i}:`, modules[i]);
+ // Hier kannst du auf einzelne Eigenschaften des aktuellen Objekts zugreifen, z.B.:
+ // console.log(`Name: ${modules[i].name}`);
+ // Und weitere Verarbeitungen für jedes Objekt im Array durchführen...
+ }
+
+ // console.log('convertModuleToNodes');
+ // console.log(modules);
+
+ let result = modules.map((item, index) => ({
+ id: `dndnode_${index}`,
+ uid: item.value.objectsettings.uid,
+ type: "customModel",
+ position: {
+ x: item.config.position[0],
+ y: item.config.position[1]
+ },
+ data: {
+ label: getModelName(item),
+ objectType: "foobar",
+ isAggregateRoot: item.value.objectsettings.aggregateRoot,
+ enableSorting: item.value.objectsettings.sorting,
+ addDeletedField: item.value.objectsettings.addDeletedField,
+ addHiddenField: item.value.objectsettings.addHiddenField,
+ addStarttimeEndtimeFields: item.value.objectsettings.addStarttimeEndtimeFields,
+ enableCategorization: item.value.objectsettings.categorizable,
+ description: item.value.objectsettings.description,
+ mapToExistingTable: item.value.objectsettings.mapToTable,
+ extendExistingModelClass: item.value.objectsettings.parentClass,
+ actions: {
+ actionIndex: item.value.actionGroup._default0_index,
+ actionList: item.value.actionGroup._default1_list,
+ actionShow: item.value.actionGroup._default2_show,
+ actionNewCreate: item.value.actionGroup._default3_new_create,
+ actionEditUpdate: item.value.actionGroup._default4_edit_update,
+ actionDelete: item.value.actionGroup._default5_delete
+ },
+ customActions: item.value.actionGroup.customActions,
+ properties: item.value.propertyGroup.properties,
+ relations: item.value.relationGroup.relations
+ },
+ dragHandle: ".drag-handle",
+ draggable: true,
+ width: 300,
+ height: 257,
+ selected: false,
+ positionAbsolute: {
+ x: item.config.position[0],
+ y: item.config.position[1]
+ },
+ dragging: false
+ }));
+
+ // console.log('result');
+ // console.log(result);
+
+ return result;
+}
+
+/**
+ * Workaround for older versions. In version 11 the name was stored inside value.name, not it is stored in name.
+ */
+function getModelName(item) {
+ console.log("item");
+ console.log(item);
+ if(item.name == 'New Model Object') {
+ return item.value.name;
+ }
+ return item.name;
+}
+
+export default convertModulesToNodes;
diff --git a/Build/Sources/helper/converter/convertRelationsToReactFlowRelations.js b/Build/Sources/helper/converter/convertRelationsToReactFlowRelations.js
new file mode 100644
index 000000000..c40cfb59a
--- /dev/null
+++ b/Build/Sources/helper/converter/convertRelationsToReactFlowRelations.js
@@ -0,0 +1,78 @@
+// from
+// "wires": [
+// {
+// "src": {
+// "moduleId": 0, ➡️ array Index von Modul innerhalb von modules
+// "terminal": "relationWire_0", ➡️ irrelevant
+// "uid": "reactflow__edge-dndnode_0rel-dndnode_0-364bc27b-ad04-42e3-a548-792a8e54efcf-dndnode_1cmn-dndnode_1" => edges.id
+// },
+// "tgt": {
+// "moduleId": 1, ➡️ array Index von Modul innerhalb von modules
+// "terminal": "SOURCES", ➡️ irrelevant
+// "uid": "dndnode_0"
+// }
+// }
+// ]
+
+// to
+// "edges": [
+// {
+// "source": "dndnode_0",
+// "sourceHandle": "rel-dndnode_0-364bc27b-ad04-42e3-a548-792a8e54efcf",
+// "target": "dndnode_1",
+// "targetHandle": "cmn-dndnode_1",
+// "id": "reactflow__edge-dndnode_0rel-dndnode_0-364bc27b-ad04-42e3-a548-792a8e54efcf-dndnode_1cmn-dndnode_1"
+// }
+function convertRelationsToReactFlowRelations(wires, modules) {
+ console.log("relations wires: ", wires);
+
+ const edges = wires.map(wire => {
+ console.log("wire", wire);
+
+ if (!wire.src || !wire.tgt) {
+ console.error('Fehler: Einige Wire-Objekte haben keine vollständigen src oder tgt Daten.', wire);
+ return null;
+ }
+
+ // Finden der entsprechenden Module anhand der moduleId
+ const sourceModule = modules[wire.src.moduleId];
+ const targetModule = modules[wire.tgt.moduleId];
+
+ if (!sourceModule || !targetModule) {
+ console.error('Fehler: Modul nicht gefunden für moduleId', wire.src.moduleId, wire.tgt.moduleId);
+ return null;
+ }
+
+ // Generierung der Source und Target IDs
+ const source = `dndnode_${wire.src.moduleId}`;
+ const target = `dndnode_${wire.tgt.moduleId}`;
+
+ // Extraktion der Handle-Informationen
+ const srcUidParts = wire.src.uid?.split("-");
+ const sourceHandle = srcUidParts.slice(1, 3).join('-');
+ const targetHandle = wire.tgt.terminal?.toLowerCase();
+
+ // Generierung der Edge-Id aus der Quell-UID
+ const edgeId = wire.src.uid;
+
+ // Überprüfen, ob alle benötigten Daten vorhanden sind
+ if (!source || !target || !sourceHandle || !targetHandle || !edgeId) {
+ console.error('Fehler: Nicht alle erforderlichen Daten konnten aus dem Wire-Objekt extrahiert werden.', wire);
+ return null;
+ }
+
+ // Erstellen des Edge-Objekts
+ return {
+ id: edgeId,
+ source: source,
+ sourceHandle: sourceHandle,
+ target: target,
+ targetHandle: targetHandle
+ };
+ });
+
+ console.log("edges from method: ", edges);
+ return edges.filter(edge => edge !== null);
+}
+
+export default convertRelationsToReactFlowRelations;
diff --git a/Build/Sources/helper/helper.js b/Build/Sources/helper/helper.js
new file mode 100644
index 000000000..6c42c39b3
--- /dev/null
+++ b/Build/Sources/helper/helper.js
@@ -0,0 +1,7 @@
+export function resizeSettingsSidebar(isRightColumnFullWidth) {
+ if (isRightColumnFullWidth) {
+ document.getElementById('settings-column').style.opacity = '0';
+ } else {
+ document.getElementById('settings-column').style.opacity = '1';
+ }
+}
diff --git a/Build/Sources/helper/index.js b/Build/Sources/helper/index.js
new file mode 100644
index 000000000..a86bd3bb4
--- /dev/null
+++ b/Build/Sources/helper/index.js
@@ -0,0 +1,5 @@
+import {resizeSettingsSidebar} from "./helper";
+import {getExtensionKeyIsValid} from "./validation/getExtensionKeyIsValid";
+
+export {resizeSettingsSidebar}
+export {getExtensionKeyIsValid}
diff --git a/Build/Sources/helper/validation/getExtensionKeyIsValid.js b/Build/Sources/helper/validation/getExtensionKeyIsValid.js
new file mode 100644
index 000000000..3f6ffdf3d
--- /dev/null
+++ b/Build/Sources/helper/validation/getExtensionKeyIsValid.js
@@ -0,0 +1,32 @@
+export function getExtensionKeyIsValid(extensionKey) {
+ // Überprüft die Länge des Schlüssels (ohne Unterstriche)
+ var keyLength = extensionKey.replace(/_/g, '').length;
+ if (keyLength < 3 || keyLength > 30) {
+ return false;
+ }
+
+ // Überprüft, ob der Schlüssel mit einem unerlaubten Präfix beginnt
+ var forbiddenPrefixes = ['tx', 'user_', 'pages', 'tt_', 'sys_', 'ts_language', 'csh_'];
+ var hasForbiddenPrefix = forbiddenPrefixes.some(prefix => extensionKey.startsWith(prefix));
+ if (hasForbiddenPrefix) {
+ return false;
+ }
+
+ // Überprüft, ob der Schlüssel mit einer Ziffer oder einem Unterstrich beginnt oder endet
+ if (/^[0-9_]|_$/.test(extensionKey)) {
+ return false;
+ }
+
+ // Überprüft, ob der Schlüssel nur die erlaubten Zeichen enthält (a-z, 0-9 und Unterstrich)
+ if (!/^[a-z0-9_]*$/.test(extensionKey)) {
+ return false;
+ }
+
+ // Überprüft, ob der Schlüssel Großbuchstaben enthält
+ if (/[A-Z]/.test(extensionKey)) {
+ return false;
+ }
+
+ // Wenn alle Überprüfungen bestanden sind, ist der Schlüssel gültig
+ return true;
+}
diff --git a/Build/Sources/helper/validation/getExtensionKeyIsValid.test.js b/Build/Sources/helper/validation/getExtensionKeyIsValid.test.js
new file mode 100644
index 000000000..bad6cebe1
--- /dev/null
+++ b/Build/Sources/helper/validation/getExtensionKeyIsValid.test.js
@@ -0,0 +1,43 @@
+import { getExtensionKeyIsValid } from './getExtensionKeyIsValid'; // replace with actual file name
+
+describe('getExtensionKeyIsValid', () => {
+ it('returns false for key length less than 3 (without underscores)', () => {
+ expect(getExtensionKeyIsValid('a_')).toBe(false);
+ });
+
+ it('returns false for key length more than 30 (without underscores)', () => {
+ expect(getExtensionKeyIsValid('a'.repeat(31) + '_')).toBe(false);
+ });
+
+ it('returns false for keys beginning with forbidden prefixes', () => {
+ const forbiddenPrefixes = ['tx', 'user_', 'pages', 'tt_', 'sys_', 'ts_language', 'csh_'];
+ forbiddenPrefixes.forEach(prefix => {
+ expect(getExtensionKeyIsValid(prefix + 'validKey')).toBe(false);
+ });
+ });
+
+ it('returns false for keys beginning or ending with a digit or underscore', () => {
+ expect(getExtensionKeyIsValid('_invalidKey')).toBe(false);
+ expect(getExtensionKeyIsValid('invalidKey_')).toBe(false);
+ expect(getExtensionKeyIsValid('1invalidKey')).toBe(false);
+ });
+
+ it('returns false for keys containing characters other than lowercase letters, digits, and underscore', () => {
+ expect(getExtensionKeyIsValid('invalidKey$')).toBe(false);
+ expect(getExtensionKeyIsValid('InvalidKey')).toBe(false);
+ });
+
+ it('returns true for valid keys', () => {
+ expect(getExtensionKeyIsValid('valid_key')).toBe(true);
+ expect(getExtensionKeyIsValid('validkey')).toBe(true);
+ expect(getExtensionKeyIsValid('valid_key123')).toBe(true);
+ expect(getExtensionKeyIsValid('a'.repeat(29) + '_a')).toBe(true);
+ });
+
+ it('returns false for keys containing uppercase letters', () => {
+ expect(getExtensionKeyIsValid('InvalidKey')).toBe(false);
+ expect(getExtensionKeyIsValid('inValid')).toBe(false);
+ expect(getExtensionKeyIsValid('INVALid_key')).toBe(false);
+ expect(getExtensionKeyIsValid('valid_key')).toBe(true);
+ });
+});
diff --git a/Build/Sources/index.css b/Build/Sources/index.css
new file mode 100644
index 000000000..1db379606
--- /dev/null
+++ b/Build/Sources/index.css
@@ -0,0 +1,20 @@
+font-face {
+ font-family: 'Share';
+ font-style: normal;
+ font-weight: 400;
+ src: url(https://example.com/MaterialIcons-Regular.eot);
+}
+
+body {
+ margin: 0;
+ font-family: 'Share', 'Helvetica Neue', sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+code {
+ font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
+ monospace;
+}
+
+
diff --git a/Build/Sources/index.js b/Build/Sources/index.js
new file mode 100644
index 000000000..18efbb532
--- /dev/null
+++ b/Build/Sources/index.js
@@ -0,0 +1,25 @@
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import './index.css';
+import App from './App';
+import reportWebVitals from './reportWebVitals';
+
+import { library } from '@fortawesome/fontawesome-svg-core'
+import { fab } from '@fortawesome/free-brands-svg-icons'
+import { fas } from '@fortawesome/free-solid-svg-icons'
+
+/* Entry point for the React app */
+const root = ReactDOM.createRoot(document.getElementById('root'));
+root.render(
+
+
+
+);
+
+// If you want to start measuring performance in your app, pass a function
+// to log results (for example: reportWebVitals(console.log))
+// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
+// reportWebVitals(console.log);
+
+library.add(fab, fas)
+
diff --git a/Build/Sources/initialValues/author.js b/Build/Sources/initialValues/author.js
new file mode 100644
index 000000000..f4b63f94c
--- /dev/null
+++ b/Build/Sources/initialValues/author.js
@@ -0,0 +1,21 @@
+const defaultAuthor = {
+ company: '',
+ email: '',
+ name: '',
+ role: '',
+}
+
+export const roles = [
+ "Developer",
+ "testing master",
+ "Product Manager",
+ "Designer",
+ "Tester",
+ "Documentation Writer",
+ "Reviewer",
+ "Support",
+ "Translator",
+ "Security",
+];
+
+export default defaultAuthor;
diff --git a/Build/Sources/initialValues/modelProperty.js b/Build/Sources/initialValues/modelProperty.js
new file mode 100644
index 000000000..ccd0b99a6
--- /dev/null
+++ b/Build/Sources/initialValues/modelProperty.js
@@ -0,0 +1,48 @@
+const modelProperty = {
+ propertyName: '',
+ propertyType: '',
+ propertyDescription: '',
+ propertyIsRequired: false,
+ propertyIsNullable: false,
+ propertyIsExcludeField: false,
+ propertyIsL10nModeExclude: false,
+ typeSelect: {
+ selectboxValues: "",
+ renderType: "selectSingle",
+ foreignTable: "",
+ whereClause: "",
+ },
+ typeText: {
+ enableRichtext: false,
+ },
+ typeNumber: {
+ enableSlider: false,
+ steps: 1,
+ setRange: false,
+ upperRange: 255,
+ lowerRange: 0,
+ },
+ typeColor: {
+ setValuesColorPicker: false,
+ colorPickerValues: '',
+ },
+ typeBoolean: {
+ renderType: "default",
+ booleanValues: "",
+ },
+ typePassword: {
+ renderPasswordGenerator: false,
+ },
+ typeDateTime: {
+ dbTypeDateTime: "",
+ formatDateTime: "",
+ },
+ typeFile: {
+ allowedFileTypes: "",
+ },
+ size: "",
+ minItems: "",
+ maxItems: "",
+}
+
+export default modelProperty;
diff --git a/Build/Sources/initialValues/module.js b/Build/Sources/initialValues/module.js
new file mode 100644
index 000000000..3188c8f8c
--- /dev/null
+++ b/Build/Sources/initialValues/module.js
@@ -0,0 +1,22 @@
+const defaultModule = {
+ actions : {
+ controllerActionCombinations: ""
+ },
+ description: '',
+ key: '',
+ mainModule: '',
+ name: '',
+ tabLabel: '',
+}
+
+export const mainModules = [
+ "web",
+ "file",
+ "site",
+ "system",
+ "tools",
+ "user",
+ "help"
+];
+
+export default defaultModule;
diff --git a/Build/Sources/initialValues/nodeData.js b/Build/Sources/initialValues/nodeData.js
new file mode 100644
index 000000000..51e7f953a
--- /dev/null
+++ b/Build/Sources/initialValues/nodeData.js
@@ -0,0 +1,27 @@
+const nodeData = {
+ label: "",
+ objectType: "",
+ isAggregateRoot: false,
+ controllerScope: "Frontend",
+ enableSorting: false,
+ addDeletedField: true,
+ addHiddenField: true,
+ addStarttimeEndtimeFields: true,
+ enableCategorization: false,
+ description: "",
+ mapToExistingTable: "",
+ extendExistingModelClass: "",
+ actions: {
+ actionIndex: false,
+ actionList: false,
+ actionShow: false,
+ actionNewCreate: false,
+ actionEditUpdate: false,
+ actionDelete: false,
+ },
+ customActions: [],
+ properties: [],
+ relations: [],
+}
+
+export default nodeData;
diff --git a/Build/Sources/initialValues/plugin.js b/Build/Sources/initialValues/plugin.js
new file mode 100644
index 000000000..7d53c35ea
--- /dev/null
+++ b/Build/Sources/initialValues/plugin.js
@@ -0,0 +1,11 @@
+const defaultPlugin = {
+ actions: {
+ controllerActionCombinations: "",
+ noncacheableActions: ""
+ },
+ description: '',
+ key: '',
+ name: '',
+}
+
+export default defaultPlugin;
diff --git a/Build/Sources/initialValues/properties.js b/Build/Sources/initialValues/properties.js
new file mode 100644
index 000000000..0270df760
--- /dev/null
+++ b/Build/Sources/initialValues/properties.js
@@ -0,0 +1,27 @@
+const initialProperties = {
+ backendModules: [],
+ description: "",
+ emConf: {
+ "category": "",
+ "custom_category": "",
+ "dependsOn": "typo3 => 12.4.0-12.4.99",
+ "disableLocalization": false,
+ "disableVersioning": false,
+ "generateDocumentationTemplate": false,
+ "generateEditorConfig": true,
+ "generateEmptyGitRepository": false,
+ "sourceLanguage": "en",
+ "state": "alpha",
+ "targetVersion": "12.4",
+ "version": "0.0.1"
+ },
+ extensionKey: "",
+ name: "",
+ originalExtensionKey: "",
+ originalVendorName: "",
+ persons: [],
+ plugins: [],
+ vendorName: ""
+};
+
+export default initialProperties;
diff --git a/Build/Sources/reportWebVitals.js b/Build/Sources/reportWebVitals.js
new file mode 100644
index 000000000..5253d3ad9
--- /dev/null
+++ b/Build/Sources/reportWebVitals.js
@@ -0,0 +1,13 @@
+const reportWebVitals = onPerfEntry => {
+ if (onPerfEntry && onPerfEntry instanceof Function) {
+ import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
+ getCLS(onPerfEntry);
+ getFID(onPerfEntry);
+ getFCP(onPerfEntry);
+ getLCP(onPerfEntry);
+ getTTFB(onPerfEntry);
+ });
+ }
+};
+
+export default reportWebVitals;
diff --git a/Build/Sources/setupTests.js b/Build/Sources/setupTests.js
new file mode 100644
index 000000000..8f2609b7b
--- /dev/null
+++ b/Build/Sources/setupTests.js
@@ -0,0 +1,5 @@
+// jest-dom adds custom jest matchers for asserting on DOM nodes.
+// allows you to do things like:
+// expect(element).toHaveTextContent(/react/i)
+// learn more: https://github.com/testing-library/jest-dom
+import '@testing-library/jest-dom';
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 6f4e07332..909481461 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -4,6 +4,8 @@ Feel free to create new pull-requests on GitHub.
#### Devbox
+*Note: The devbox is not properly working at the moment.*
+
If you don't have a setup already, where you can do development, bugfixing etc. for the extension_builder, don't worry.
We have included a [ddev](https://www.ddev.com) devbox to help the development.
diff --git a/Classes/Command/MigrateExtensionCommand.php b/Classes/Command/MigrateExtensionCommand.php
new file mode 100644
index 000000000..7bc7621a2
--- /dev/null
+++ b/Classes/Command/MigrateExtensionCommand.php
@@ -0,0 +1,61 @@
+addOption(
+ 'extension',
+ 'e',
+ InputOption::VALUE_OPTIONAL,
+ 'Extension which should be migrated'
+ );
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ // get all given parameters
+ $extension = $input->getOption('extension');
+
+ // first check, if all given parameters are valid
+ if ($extension === null || $extension === '') {
+ $output->writeln('No extension key is give. You must provide an extension key for migration.');
+ return Command::INVALID;
+ }
+ // Get a list of all available extensions
+
+ // compare the list, if the given extension is available
+
+ // if yes, then migrate the extension
+
+ // if succeeded, then show a success message
+ return Command::SUCCESS;
+ }
+}
diff --git a/Classes/Configuration/ExtensionBuilderConfigurationManager.php b/Classes/Configuration/ExtensionBuilderConfigurationManager.php
index 728ed664f..e82fde66f 100644
--- a/Classes/Configuration/ExtensionBuilderConfigurationManager.php
+++ b/Classes/Configuration/ExtensionBuilderConfigurationManager.php
@@ -18,9 +18,9 @@
namespace EBT\ExtensionBuilder\Configuration;
use EBT\ExtensionBuilder\Domain\Model\Extension;
-use EBT\ExtensionBuilder\Utility\SpycYAMLParser;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
+use RectorPrefix202306\Tracy\Debugger;
use TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException;
use TYPO3\CMS\Backend\Routing\UriBuilder;
use TYPO3\CMS\Core\Configuration\Exception\ExtensionConfigurationExtensionNotConfiguredException;
@@ -34,6 +34,8 @@
use TYPO3\CMS\Core\Utility\PathUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper;
+use TYPO3\CMS\Extbase\Utility\DebuggerUtility;
+use Symfony\Component\Yaml\Yaml;
/**
* Load settings from yaml file and from TYPO3_CONF_VARS extConf
@@ -62,7 +64,9 @@ public function injectConfigurationManager(ConfigurationManagerInterface $config
}
/**
- * Wrapper for file_get_contents('php://input')
+ * Parse the request data from the input stream.
+ *
+ * @return void
*/
public function parseRequest(): void
{
@@ -116,10 +120,12 @@ public function getSettings(?array $typoscript = null): array
if ($typoscript === null) {
$typoscript = $this->configurationManager->getConfiguration($this->configurationManager::CONFIGURATION_TYPE_FULL_TYPOSCRIPT);
}
- $settings = $typoscript['module.']['extension_builder.']['settings.'];
+ $settings = $typoscript['module.']['extension_builder.']['settings.'] ?? [];
$settings['extConf'] = $this->getExtensionBuilderSettings();
if (empty($settings['publicResourcesPath'])) {
$settings['publicResourcesPath'] = ExtensionManagementUtility::extPath('extension_builder') . 'Resources/Public/';
+ $settings['codeTemplateRootPaths'][] = ExtensionManagementUtility::extPath('extension_builder') . 'Resources/Private/CodeTemplates/Extbase/';
+ $settings['codeTemplatePartialPaths'][] = ExtensionManagementUtility::extPath('extension_builder') . 'Resources/Private/CodeTemplates/Extbase/Partials/';
}
return $settings;
}
@@ -142,7 +148,7 @@ public function getExtensionSettings(string $extensionKey, string $extensionStor
if (!file_exists($settingsFile)) {
return [];
}
- return SpycYAMLParser::YAMLLoadString(file_get_contents($settingsFile));
+ return Yaml::parseFile($settingsFile);
}
/**
@@ -164,7 +170,7 @@ public function getExtensionBuilderConfiguration(string $extensionKey, ?string $
return null;
}
- public static function getExtensionBuilderJson(string $extensionKey, ?string $storagePath = null)
+ public static function getExtensionBuilderJson(string $extensionKey, ?string $storagePath = null): ?array
{
$storagePath = $storagePath ?? Environment::getPublicPath() . '/typo3conf/ext/';
$jsonFile = $storagePath . $extensionKey . '/' . self::EXTENSION_BUILDER_SETTINGS_FILE;
@@ -271,8 +277,7 @@ protected function mapAdvancedMode(array $jsonConfig, bool $prepareForModeler =
$fieldsToMap = [
'relationType',
'renderType',
- 'propertyIsExcludeField',
- 'propertyIsExcludeField',
+ 'excludeField',
'lazyLoading',
'relationDescription',
'foreignRelationClass'
@@ -284,17 +289,17 @@ protected function mapAdvancedMode(array $jsonConfig, bool $prepareForModeler =
$module['value']['relationGroup']['relations'][$i]['advancedSettings'] = [];
foreach ($fieldsToMap as $fieldToMap) {
$module['value']['relationGroup']['relations'][$i]['advancedSettings'][$fieldToMap] =
- $module['value']['relationGroup']['relations'][$i][$fieldToMap];
+ $module['value']['relationGroup']['relations'][$i][$fieldToMap] ?? '';
}
$module['value']['relationGroup']['relations'][$i]['advancedSettings']['propertyIsExcludeField'] =
- $module['value']['relationGroup']['relations'][$i]['propertyIsExcludeField'];
+ $module['value']['relationGroup']['relations'][$i]['propertyIsExcludeField'] ?? '';
$module['value']['relationGroup']['relations'][$i]['advancedSettings']['lazyLoading'] =
- $module['value']['relationGroup']['relations'][$i]['lazyLoading'];
+ $module['value']['relationGroup']['relations'][$i]['lazyLoading'] ?? '';
$module['value']['relationGroup']['relations'][$i]['advancedSettings']['relationDescription'] =
- $module['value']['relationGroup']['relations'][$i]['relationDescription'];
+ $module['value']['relationGroup']['relations'][$i]['relationDescription'] ?? '';
$module['value']['relationGroup']['relations'][$i]['advancedSettings']['foreignRelationClass'] =
- $module['value']['relationGroup']['relations'][$i]['foreignRelationClass'];
+ $module['value']['relationGroup']['relations'][$i]['foreignRelationClass'] ?? '';
}
} elseif (isset($module['value']['relationGroup']['relations'][$i]['advancedSettings'])) {
foreach ($fieldsToMap as $fieldToMap) {
@@ -368,30 +373,31 @@ protected function resetOutboundedPositions(array $jsonConfig): array
*/
protected function reArrangeRelations(array $jsonConfig): array
{
- foreach ($jsonConfig['wires'] as &$wire) {
- // format: relation_1
- $parts = explode('_', $wire['src']['terminal']);
- $supposedRelationIndex = (int)$parts[1];
-
- // Source
- $uid = $wire['src']['uid'];
- $wire['src'] = $this->findModuleIndexByRelationUid(
- $wire['src']['uid'],
- $jsonConfig['modules'],
- $wire['src']['moduleId'],
- $supposedRelationIndex
- );
- $wire['src']['uid'] = $uid;
-
- // Target
- $uid = $wire['tgt']['uid'];
- $wire['tgt'] = $this->findModuleIndexByRelationUid(
- $wire['tgt']['uid'],
- $jsonConfig['modules'],
- $wire['tgt']['moduleId']
- );
- $wire['tgt']['uid'] = $uid;
- }
+ // TODO check this code. This one removes the terminal array key inside the src array, this mustn't happen
+ // foreach ($jsonConfig['wires'] as &$wire) {
+ // // format: relation_1
+ // $parts = explode('_', $wire['src']['terminal']);
+ // $supposedRelationIndex = (int)$parts[1];
+//
+ // // Source
+ // $uid = $wire['src']['uid'];
+ // $wire['src'] = $this->findModuleIndexByRelationUid(
+ // $wire['src']['uid'],
+ // $jsonConfig['modules'],
+ // $wire['src']['moduleId'],
+ // $supposedRelationIndex
+ // );
+ // $wire['src']['uid'] = $uid;
+//
+ // // Target
+ // $uid = $wire['tgt']['uid'];
+ // $wire['tgt'] = $this->findModuleIndexByRelationUid(
+ // $wire['tgt']['uid'],
+ // $jsonConfig['modules'],
+ // $wire['tgt']['moduleId']
+ // );
+ // $wire['tgt']['uid'] = $uid;
+ // }
return $jsonConfig;
}
@@ -429,7 +435,7 @@ protected function findModuleIndexByRelationUid(
}
if (
- isset($modules[$supposedModuleIndex]['value']['relationGroup']['relations'][$supposedRelationIndex]['uid'])
+ isset($modules[$supposedModuleIndex]['value']['relationGroup']['relations'][$supposedRelationIndex]['uid'])
&& $modules[$supposedModuleIndex]['value']['relationGroup']['relations'][$supposedRelationIndex]['uid'] === $uid
) {
$result['terminal'] = 'relationWire_' . $supposedRelationIndex;
@@ -465,35 +471,4 @@ public function getParentClassForEntityObject(Extension $extension): string
return $settings['classBuilder']['Model']['AbstractEntity']['parentClass'] ??
'\\TYPO3\\CMS\\Extbase\\DomainObject\\AbstractEntity';
}
-
- /**
- * Ajax callback that reads the smd file and modiefies the target URL to include
- * the module token.
- *
- * @param ServerRequestInterface $request
- * @return JsonResponse
- * @throws RouteNotFoundException
- */
- public function getWiringEditorSmd(ServerRequestInterface $request): JsonResponse
- {
- $smdJsonString = file_get_contents(
- ExtensionManagementUtility::extPath('extension_builder') . 'Resources/Public/jsDomainModeling/phpBackend/WiringEditor.smd'
- );
- $smdJson = json_decode($smdJsonString);
- $parameters = [
- 'tx_extensionbuilder_tools_extensionbuilderextensionbuilder' => [
- 'controller' => 'BuilderModule',
- 'action' => 'dispatchRpc',
- ]
- ];
- $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
- try {
- $uri = $uriBuilder->buildUriFromRoute('tools_ExtensionBuilderExtensionbuilder', $parameters);
- } catch (RouteNotFoundException $e) {
- $uri = $uriBuilder->buildUriFromRoutePath('tools_ExtensionBuilderExtensionbuilder', $parameters);
- }
- $smdJson->target = (string)$uri;
-
- return (new JsonResponse())->setPayload((array)$smdJson);
- }
}
diff --git a/Classes/Controller/BuilderModuleController.php b/Classes/Controller/BuilderModuleController.php
index ab16d758b..b06d24fa0 100644
--- a/Classes/Controller/BuilderModuleController.php
+++ b/Classes/Controller/BuilderModuleController.php
@@ -27,7 +27,9 @@
use EBT\ExtensionBuilder\Service\RoundTrip;
use EBT\ExtensionBuilder\Template\Components\Buttons\LinkButtonWithId;
use EBT\ExtensionBuilder\Utility\ExtensionInstallationStatus;
+use JsonException;
use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Backend\Template\Components\ButtonBar;
use TYPO3\CMS\Backend\Template\ModuleTemplate;
use TYPO3\CMS\Backend\Template\ModuleTemplateFactory;
@@ -44,31 +46,47 @@
use TYPO3\CMS\Core\Utility\PathUtility;
use TYPO3\CMS\Extbase\Http\ForwardResponse;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
+use TYPO3\CMS\Extbase\Utility\DebuggerUtility;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
class BuilderModuleController extends ActionController
{
private FileGenerator $fileGenerator;
-
- private ExtensionBuilderConfigurationManager $extensionBuilderConfigurationManager;
-
+ private IconFactory $iconFactory;
+ private PageRenderer $pageRenderer;
private ExtensionInstallationStatus $extensionInstallationStatus;
-
private ExtensionSchemaBuilder $extensionSchemaBuilder;
-
private ExtensionService $extensionService;
-
+ private ModuleTemplateFactory $moduleTemplateFactory;
private ExtensionValidator $extensionValidator;
-
private ExtensionRepository $extensionRepository;
- private ModuleTemplateFactory $moduleTemplateFactory;
+ public function __construct(
+ FileGenerator $fileGenerator,
+ IconFactory $iconFactory,
+ PageRenderer $pageRenderer,
+ ExtensionInstallationStatus $extensionInstallationStatus,
+ ExtensionSchemaBuilder $extensionSchemaBuilder,
+ ExtensionService $extensionService,
+ ModuleTemplateFactory $moduleTemplateFactory,
+ ExtensionValidator $extensionValidator,
+ ExtensionRepository $extensionRepository,
+ )
+ {
+ $this->fileGenerator = $fileGenerator;
+ $this->iconFactory = $iconFactory;
+ $this->pageRenderer = $pageRenderer;
+ $this->extensionInstallationStatus = $extensionInstallationStatus;
+ $this->extensionSchemaBuilder = $extensionSchemaBuilder;
+ $this->extensionService = $extensionService;
+ $this->moduleTemplateFactory = $moduleTemplateFactory;
+ $this->extensionValidator = $extensionValidator;
+ $this->extensionRepository = $extensionRepository;
+ }
+ private ExtensionBuilderConfigurationManager $extensionBuilderConfigurationManager;
private ModuleTemplate $moduleTemplate;
- private PageRenderer $pageRenderer;
-
- private IconFactory $iconFactory;
/**
* Settings from various sources:
@@ -78,11 +96,6 @@ class BuilderModuleController extends ActionController
*/
protected array $extensionBuilderSettings = [];
- public function injectFileGenerator(FileGenerator $fileGenerator): void
- {
- $this->fileGenerator = $fileGenerator;
- }
-
public function injectExtensionBuilderConfigurationManager(
ExtensionBuilderConfigurationManager $configurationManager
): void {
@@ -90,46 +103,9 @@ public function injectExtensionBuilderConfigurationManager(
$this->extensionBuilderSettings = $this->extensionBuilderConfigurationManager->getSettings();
}
- public function injectExtensionInstallationStatus(ExtensionInstallationStatus $extensionInstallationStatus): void
- {
- $this->extensionInstallationStatus = $extensionInstallationStatus;
- }
-
- public function injectExtensionSchemaBuilder(ExtensionSchemaBuilder $extensionSchemaBuilder): void
- {
- $this->extensionSchemaBuilder = $extensionSchemaBuilder;
- }
-
- public function injectExtensionService(ExtensionService $extensionService): void
- {
- $this->extensionService = $extensionService;
- }
-
- public function injectExtensionValidator(ExtensionValidator $extensionValidator): void
- {
- $this->extensionValidator = $extensionValidator;
- }
-
- public function injectExtensionRepository(ExtensionRepository $extensionRepository): void
- {
- $this->extensionRepository = $extensionRepository;
- }
-
- public function injectModuleTemplateFactory(ModuleTemplateFactory $moduleTemplateFactory): void
- {
- $this->moduleTemplateFactory = $moduleTemplateFactory;
- }
-
- public function injectPageRenderer(PageRenderer $pageRenderer): void
- {
- $this->pageRenderer = $pageRenderer;
- }
-
- public function injectIconFactory(IconFactory $iconFactory): void
- {
- $this->iconFactory = $iconFactory;
- }
-
+ /**
+ * @return void
+ */
public function initializeAction(): void
{
$this->fileGenerator->setSettings($this->extensionBuilderSettings);
@@ -165,14 +141,50 @@ public function indexAction(): ResponseInterface
public function domainmodellingAction(): ResponseInterface
{
$this->moduleTemplate = $this->moduleTemplateFactory->create($this->request);
- $this->moduleTemplate->setBodyTag('');
$this->moduleTemplate->setTitle('Extension Builder');
+ $this->moduleTemplate->getDocHeaderComponent()->disable();
+ $storagePaths = $this->extensionService->resolveStoragePaths();
+ $storagePath = reset($storagePaths);
+
+ $this->addAssets();
+
+ $this->pageRenderer->addInlineSettingArray(
+ 'extensionBuilder',
+ ['publicResourcesUrl' => PathUtility::getPublicResourceWebPath('EXT:extension_builder/Resources/Public')]
+ );
- $this->addMainMenu('domainmodelling');
- //$this->addStoragePathMenu();
+ $this->setLocallangSettings();
- $this->addLeftButtons();
- $this->addRightButtons();
+ $initialWarnings = [];
+ if (!$this->extensionService->isStoragePathConfigured()) {
+ $initialWarnings[] = ExtensionService::COMPOSER_PATH_WARNING;
+ }
+ $this->view->assignMultiple([
+ 'initialWarnings' => $initialWarnings,
+ 'currentVersion' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getExtensionVersion($this->request->getControllerExtensionKey()),
+ 'backupDir' => $this->extensionBuilderSettings['extConf']['backupDir'],
+ 'outputDir' => $storagePath,
+ ]);
+ $this->pageRenderer->addInlineSetting(
+ 'extensionBuilder.publicResourceWebPath',
+ 'core',
+ PathUtility::getPublicResourceWebPath('EXT:core/Resources/Public/')
+ );
+ $this->getBackendUserAuthentication()->pushModuleData('extensionbuilder', ['firstTime' => 0]);
+
+ $this->moduleTemplate->setContent($this->view->render());
+
+ return $this->htmlResponse($this->moduleTemplate->renderContent());
+ }
+
+ /**
+ * @return ResponseInterface
+ * @throws \TYPO3\CMS\Core\Package\Exception
+ * @throws \TYPO3\CMS\Core\Resource\Exception\InvalidFileException
+ */
+ public function helpAction() {
+ $this->moduleTemplate = $this->moduleTemplateFactory->create($this->request);
+ $this->moduleTemplate->setTitle('Extension Builder');
$this->addAssets();
@@ -188,7 +200,8 @@ public function domainmodellingAction(): ResponseInterface
$initialWarnings[] = ExtensionService::COMPOSER_PATH_WARNING;
}
$this->view->assignMultiple([
- 'initialWarnings' => $initialWarnings
+ 'initialWarnings' => $initialWarnings,
+ 'currentVersion' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getExtensionVersion($this->request->getControllerExtensionKey())
]);
$this->pageRenderer->addInlineSetting(
'extensionBuilder.publicResourceWebPath',
@@ -202,16 +215,12 @@ public function domainmodellingAction(): ResponseInterface
return $this->htmlResponse($this->moduleTemplate->renderContent());
}
+
protected function addMainMenu(string $currentAction): void
{
$menu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
$menu->setIdentifier('ExtensionBuilderMainModuleMenu');
- $menu->addMenuItem(
- $menu->makeMenuItem()
- ->setTitle('Introduction')
- ->setHref($this->uriBuilder->uriFor('index'))
- ->setActive($currentAction === 'index')
- );
+
$menu->addMenuItem(
$menu->makeMenuItem()
->setTitle('Domain Modelling')
@@ -221,92 +230,65 @@ protected function addMainMenu(string $currentAction): void
$this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
}
- /*
- * This does not work as intended as the dropdown menu will only show a value if there are at least 2 entries
- * and additionally submit the value when changed which we don't want.
- *
- //protected function addStoragePathMenu(): void
- {
- $menu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
- $menu->setIdentifier('storagePath');
- $menu->setLabel('Storage Path:');
-
- $storagePaths = $this->extensionService->resolveStoragePaths();
- foreach ($storagePaths as $storagePath) {
- $menu->addMenuItem(
- $menu->makeMenuItem()
- ->setTitle($storagePath)
- ->setHref($storagePath)
- );
- }
- $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
- }*/
-
protected function addLeftButtons(): void
{
$buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
- $loadButton = GeneralUtility::makeInstance(LinkButtonWithId::class)
- ->setIcon($this->iconFactory->getIcon('actions-system-list-open', Icon::SIZE_SMALL))
- ->setTitle('Open extension')
- ->setId('WiringEditor-loadButton-button')
+ // Add buttons for default domainmodelling page
+ $slackButton = GeneralUtility::makeInstance(LinkButtonWithId::class)
+ ->setIcon($this->iconFactory->getIcon('actions-brand-slack', Icon::SIZE_SMALL))
+ ->setTitle('Get help on Slack')
+ ->setShowLabelText(true)
+ ->setId('slack-button')
->setHref('#');
- $buttonBar->addButton($loadButton, ButtonBar::BUTTON_POSITION_LEFT, 1);
+ $buttonBar->addButton($slackButton, ButtonBar::BUTTON_POSITION_LEFT, 1);
- $loadButton = GeneralUtility::makeInstance(LinkButtonWithId::class)
- ->setIcon($this->iconFactory->getIcon('actions-document-new', Icon::SIZE_SMALL))
- ->setTitle('New extension')
- ->setId('WiringEditor-newButton-button')
+ $bugButton = GeneralUtility::makeInstance(LinkButtonWithId::class)
+ ->setIcon($this->iconFactory->getIcon('actions-debug', Icon::SIZE_SMALL))
+ ->setTitle('Report a bug')
+ ->setShowLabelText(true)
+ ->setId('bug-button')
->setHref('#');
- $buttonBar->addButton($loadButton, ButtonBar::BUTTON_POSITION_LEFT, 2);
+ $buttonBar->addButton($bugButton, ButtonBar::BUTTON_POSITION_LEFT, 1);
- $loadButton = GeneralUtility::makeInstance(LinkButtonWithId::class)
- ->setIcon($this->iconFactory->getIcon('actions-document-save', Icon::SIZE_SMALL))
- ->setTitle('Save extension')
- ->setId('WiringEditor-saveButton-button')
+ $documentationButton = GeneralUtility::makeInstance(LinkButtonWithId::class)
+ ->setIcon($this->iconFactory->getIcon('apps-toolbar-menu-opendocs', Icon::SIZE_SMALL))
+ ->setTitle('Show documentation')
+ ->setShowLabelText(true)
+ ->setId('documentation-button')
->setHref('#');
- $buttonBar->addButton($loadButton, ButtonBar::BUTTON_POSITION_LEFT, 3);
+ $buttonBar->addButton($documentationButton, ButtonBar::BUTTON_POSITION_LEFT, 1);
+
+ $sponsorButton = GeneralUtility::makeInstance(LinkButtonWithId::class)
+ ->setIcon($this->iconFactory->getIcon('actions-link', Icon::SIZE_SMALL))
+ ->setTitle('Sponsor this project')
+ ->setShowLabelText(true)
+ ->setId('sponsor-button')
+ ->setHref('#');
+ $buttonBar->addButton($sponsorButton, ButtonBar::BUTTON_POSITION_LEFT, 1);
}
protected function addRightButtons(): void
{
$buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
- $this->registerAdvancedOptionsButtonToButtonBar($buttonBar, ButtonBar::BUTTON_POSITION_RIGHT, 2);
- $this->registerOpenInNewWindowButtonToButtonBar($buttonBar, ButtonBar::BUTTON_POSITION_RIGHT, 3);
- }
-
- protected function registerOpenInNewWindowButtonToButtonBar(ButtonBar $buttonBar, string $position, int $group): void
- {
- $requestUri = $this->uriBuilder->uriFor('domainmodelling');
-
- $openInNewWindowButton = GeneralUtility::makeInstance(LinkButtonWithId::class)
- ->setHref('#')
- ->setTitle($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.openInNewWindow'))
- ->setIcon($this->iconFactory->getIcon('actions-window-open', Icon::SIZE_SMALL))
- ->setDataAttributes([
- 'dispatch-action' => 'TYPO3.WindowManager.localOpen',
- 'dispatch-args' => GeneralUtility::jsonEncodeForHtmlAttribute([
- $requestUri,
- true, // switchFocus
- 'extension_builder', // windowName,
- 'width=1920,height=1080,status=0,menubar=0,scrollbars=1,resizable=1', // windowFeatures
- ])
- ])
- ->setId('opennewwindow');
-
- $buttonBar->addButton($openInNewWindowButton, $position, $group);
- }
-
- protected function registerAdvancedOptionsButtonToButtonBar(ButtonBar $buttonBar, string $position, int $group): void
- {
$advancedOptionsButton = GeneralUtility::makeInstance(LinkButtonWithId::class)
- ->setIcon($this->iconFactory->getIcon('content-menu-pages', Icon::SIZE_SMALL))
+ ->setIcon($this->iconFactory->getIcon('actions-options', Icon::SIZE_SMALL))
->setTitle($this->getLanguageService()->sL('LLL:EXT:extension_builder/Resources/Private/Language/locallang.xlf:advancedOptions'))
->setId('toggleAdvancedOptions')
->setHref('#')
->setShowLabelText(true);
- $buttonBar->addButton($advancedOptionsButton, $position, $group);
+ $buttonBar->addButton($advancedOptionsButton, ButtonBar::BUTTON_POSITION_RIGHT, 1);
+
+ // $helpButton = GeneralUtility::makeInstance(LinkButtonWithId::class)
+ // ->setIcon($this->iconFactory->getIcon('module-help', Icon::SIZE_SMALL))
+ // ->setTitle($this->getLanguageService()->sL('LLL:EXT:extension_builder/Resources/Private/Language/locallang.xlf:showHelp'))
+ // ->setId('showHelp')
+ // // ->setHref($this->uriBuilder->uriFor('help'))
+ // ->setHref('#')
+ // ->setShowLabelText(true);
+
+ // $buttonBar->addButton($helpButton, ButtonBar::BUTTON_POSITION_RIGHT, 2);
}
protected function getLanguageService(): LanguageService
@@ -316,76 +298,14 @@ protected function getLanguageService(): LanguageService
protected function addAssets(): void
{
- // SECTION: JAVASCRIPT FILES
- // YUI Basis Files
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/lib/yui/utilities/utilities.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/lib/yui/resize/resize-min.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/lib/yui/layout/layout-min.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/lib/yui/container/container-min.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/lib/yui/json/json-min.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/lib/yui/button/button-min.js');
-
- // YUI-RPC
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/lib/yui-rpc.js');
-
- // InputEx with wirable options
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/lib/inputex/js/inputex.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/lib/inputex/js/Field.js');
-
- // extended fields for enabling unique ids
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/extended/ListField.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/extended/Group.js');
-
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/js/util/inputex/WirableField-beta.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/lib/inputex/js/Visus.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/lib/inputex/js/fields/StringField.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/lib/inputex/js/fields/Textarea.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/lib/inputex/js/fields/SelectField.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/lib/inputex/js/fields/EmailField.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/lib/inputex/js/fields/UrlField.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/lib/inputex/js/fields/CheckBox.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/lib/inputex/js/fields/InPlaceEdit.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/lib/inputex/js/fields/MenuField.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/lib/inputex/js/fields/TypeField.js');
-
- // WireIt
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/js/WireIt.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/js/CanvasElement.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/js/Wire.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/js/Terminal.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/js/util/DD.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/js/util/DDResize.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/js/Container.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/js/ImageContainer.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/js/Layer.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/js/util/inputex/FormContainer-beta.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/js/LayerMap.js');
-
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/js/WiringEditor.js');
-
- // Extbase Modelling definition
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/extbaseModeling.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/layout.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/extensionProperties.js');
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/modules/modelObject.js');
-
- // collapsible forms in relations
- $this->pageRenderer->addJsFile('EXT:extension_builder/Resources/Public/jsDomainModeling/modules/extendedModelObject.js');
-
- // SECTION: CSS Files
- // YUI CSS
- $this->pageRenderer->addCssFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/lib/yui/reset-fonts-grids/reset-fonts-grids.css');
- $this->pageRenderer->addCssFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/lib/yui/assets/skins/sam/skin.css');
-
- // InputEx CSS
- $this->pageRenderer->addCssFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/lib/inputex/css/inputEx.css');
-
- // WireIt CSS
- $this->pageRenderer->addCssFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/css/WireIt.css');
- $this->pageRenderer->addCssFile('EXT:extension_builder/Resources/Public/jsDomainModeling/wireit/css/WireItEditor.css');
-
- // Custom CSS
- $this->pageRenderer->addCssFile('EXT:extension_builder/Resources/Public/jsDomainModeling/extbaseModeling.css');
+ // Load sources for react js app
+ $this->pageRenderer->addCssFile('EXT:extension_builder/Resources/Public/Css/main.css');
+ $this->pageRenderer->addCssFile('EXT:extension_builder/Resources/Public/Css/styles.css');
+
+ // Load custom js
+ $this->pageRenderer->loadJavaScriptModule('@friendsoftypo3/extension-builder/main.js');
+ $this->pageRenderer->loadJavaScriptModule('@friendsoftypo3/extension-builder/85.js');
+ $this->pageRenderer->loadJavaScriptModule('@friendsoftypo3/extension-builder/extensionbuilder.js');
}
/**
@@ -420,9 +340,19 @@ protected function setLocallangSettings(): void
* Main entry point for the buttons in the Javascript frontend.
*
* @return ResponseInterface json encoded array
+ * @throws JsonException
*/
- public function dispatchRpcAction(): ResponseInterface
+ public function dispatchRpcAction(ServerRequestInterface $request): ResponseInterface
{
+ $this->fileGenerator->setSettings($this->extensionBuilderSettings);
+
+ $data = $request->getQueryParams()['input'] ?? null;
+ $response = $this->responseFactory->createResponse()
+ ->withHeader('Content-Type', 'application/json; charset=utf-8');
+ $response->getBody()->write(json_encode(['result' => json_encode($data)], JSON_THROW_ON_ERROR));
+ // add status code to response
+ // return $response;
+
try {
$this->extensionBuilderConfigurationManager->parseRequest();
$subAction = $this->extensionBuilderConfigurationManager->getSubActionFromRequest();
@@ -444,7 +374,10 @@ public function dispatchRpcAction(): ResponseInterface
}
} catch (\Exception $e) {
$response = ['error' => $e->getMessage()];
+ // $response = $response->withStatus(404);
}
+
+ // $response = $response->withStatus(200);
return $this->jsonResponse(json_encode($response));
}
@@ -487,6 +420,7 @@ protected function rpcActionSave(): array
}
// Validate the extension
+ // TODO: check, if this is still needed
$validationResult = $this->extensionValidator->isValid($extension);
if (!empty($validationResult['errors'])) {
$errorMessage = '';
@@ -534,7 +468,7 @@ protected function rpcActionSave(): array
// this would result in a total overwrite so we create one and give a warning
$this->extensionBuilderConfigurationManager->createInitialSettingsFile(
$extension,
- $this->extensionBuilderSettings['codeTemplateRootPaths.']
+ $this->extensionBuilderSettings['codeTemplateRootPaths']
);
$extensionPath = Environment::isComposerMode() ? 'packages/' : 'typo3conf/ext/';
return [
@@ -554,7 +488,8 @@ protected function rpcActionSave(): array
throw $e;
}
} else {
- if (!is_array($extensionSettings['ignoreWarnings'])
+ if (!isset($extensionSettings['ignoreWarnings'])
+ || !is_array($extensionSettings['ignoreWarnings'])
|| !in_array(ExtensionValidator::EXTENSION_DIR_EXISTS, $extensionSettings['ignoreWarnings'])
) {
$confirmationRequired = $this->handleValidationWarnings([
@@ -574,7 +509,7 @@ protected function rpcActionSave(): array
$this->extensionInstallationStatus->setExtension($extension);
$this->extensionInstallationStatus->setUsesComposerPath($usesComposerPath);
$message = sprintf(
- '
The Extension was successfully saved in the directory: "%s"
%s',
+ '
The Extension was successfully saved in the directory: "%s"
%s',
$extensionDirectory,
$this->extensionInstallationStatus->getStatusMessage()
);
@@ -592,15 +527,17 @@ protected function rpcActionSave(): array
}
/**
- * Shows a list with available extensions (if they have an ExtensionBuilder.json
- * file).
+ * Shows a list with locally available extensions for editing
+ * (if they have a file `ExtensionBuilder.json`).
*
* @return array
*/
protected function rpcActionList(): array
{
$extensions = $this->extensionRepository->findAll();
+ sort($extensions);
return [
+ 'success' => true,
'result' => $extensions,
'error' => null
];
diff --git a/Classes/Domain/Model/AbstractObject.php b/Classes/Domain/Model/AbstractObject.php
index 655f99bed..cf0c7385c 100644
--- a/Classes/Domain/Model/AbstractObject.php
+++ b/Classes/Domain/Model/AbstractObject.php
@@ -485,7 +485,7 @@ public function getDocComment(): string
foreach ($tags as $tagValue) {
$docCommentLines[] = '@' . $tagName . ' ' . $tagValue;
}
- } elseif (is_array($tags) && empty($tags)) {
+ } elseif (is_array($tags)) {
$docCommentLines[] = '@' . $tagName;
} else {
$docCommentLines[] = '@' . $tagName . ' ' . $tags;
diff --git a/Classes/Domain/Model/DomainObject.php b/Classes/Domain/Model/DomainObject.php
index 730d50bbc..f18017ac1 100644
--- a/Classes/Domain/Model/DomainObject.php
+++ b/Classes/Domain/Model/DomainObject.php
@@ -34,6 +34,8 @@ class DomainObject
* If true, this is an aggregate root.
*/
protected bool $aggregateRoot = false;
+ protected string $controllerScope = "Frontend";
+
/**
* If true, the element is sortable in the TYPO3 backend.
*/
@@ -171,6 +173,16 @@ public function setAggregateRoot(bool $aggregateRoot): void
$this->aggregateRoot = $aggregateRoot;
}
+ public function getControllerScope(): string
+ {
+ return $this->controllerScope;
+ }
+
+ public function setControllerScope(string $controllerScope): void
+ {
+ $this->controllerScope = $controllerScope;
+ }
+
/**
* @return bool true if it is an entity, false if it is a ValueObject
*/
diff --git a/Classes/Domain/Model/DomainObject/AbstractProperty.php b/Classes/Domain/Model/DomainObject/AbstractProperty.php
index fe7097c54..0894f48fe 100644
--- a/Classes/Domain/Model/DomainObject/AbstractProperty.php
+++ b/Classes/Domain/Model/DomainObject/AbstractProperty.php
@@ -92,6 +92,42 @@ abstract class AbstractProperty
protected bool $searchable = false;
+ protected int $size = 0;
+ protected int $maxItems = 0;
+ protected int $minItems = 0;
+
+ // Select Box
+ protected array $selectboxValues = [];
+ protected string $foreignTable = '';
+ protected string $renderType = '';
+ protected string $whereClause = '';
+
+ // Text and RichText
+ protected bool $enableRichtext = false;
+ protected int $rows = 0;
+
+ // Number
+ protected bool $enableSlider = false;
+ protected bool $setRange = false;
+ protected int $lowerRange = 0;
+ protected int $upperRange = 100;
+ protected int|float $steps = 1;
+
+ // Color
+ protected bool $setValuesColorPicker = false;
+ protected array $colorPickerValues = [];
+
+ // Password
+ protected bool $renderPasswordGenerator = false;
+
+ // Boolean
+ protected string $renderTypeBoolean = '';
+ protected array $booleanValues = [];
+
+ // DateTime
+ protected string $dbTypeDateTime = '';
+ protected string $formatDateTime = '';
+
public function __construct(string $propertyName = '')
{
if (!empty($propertyName)) {
@@ -172,15 +208,6 @@ public function isAnyToManyRelation(): bool
return is_subclass_of($this, AnyToManyRelation::class);
}
- /**
- * @return bool true (if property is of type relation any to many)
- * @deprecated Use `!instanceof ZeroToManyRelation` instead
- */
- public function isZeroToManyRelation(): bool
- {
- return false;
- }
-
/**
* @return bool true (if property is of type relation)
*/
@@ -365,7 +392,7 @@ public function getIsDisplayable(): bool
/**
* Is this property persistable in a database?
*
- * @return bool true if this property can be displayed inside a fluid template
+ * @return bool true if this property can be persisted in a database
*/
public function getIsPersistable(): bool
{
@@ -487,4 +514,251 @@ public function isSearchable(): bool
{
return $this->searchable;
}
+
+ public function getSelectboxValues(): array
+ {
+ return $this->selectboxValues;
+ }
+
+
+ public function setSelectboxValues(string $value): void
+ {
+ $pairs = explode("\n", $value);
+ $assocArray = [];
+
+ foreach ($pairs as $pair) {
+ $parts = explode(';', $pair);
+ if (count($parts) == 2) {
+ [$label, $val] = $parts;
+ $assocArray[$label] = $val;
+ }
+ }
+
+ $this->selectboxValues = $assocArray;
+ }
+
+ public function getBooleanValues(): array
+ {
+ return $this->booleanValues;
+ }
+
+ public function setBooleanValues(string $value): void
+ {
+ $pairs = explode("\n", $value);
+ // $assocArray = [];
+//
+ // foreach ($pairs as $pair) {
+ // $parts = explode(';', $pair);
+ // if (count($parts) == 2) {
+ // [$label, $val] = $parts;
+ // $assocArray[$label] = $val;
+ // }
+ // }
+
+ $this->booleanValues = $pairs;
+ }
+
+
+
+ public function isSetValuesColorPicker(): bool
+ {
+ return $this->setValuesColorPicker;
+ }
+
+ public function setSetValuesColorPicker(bool $setValuesColorPicker): void
+ {
+ $this->setValuesColorPicker = $setValuesColorPicker;
+ }
+
+ public function getColorPickerValues(): array
+ {
+ return $this->colorPickerValues;
+ }
+
+ public function setColorPickerValues(string $value): void
+ {
+ $pairs = explode("\n", $value);
+ $assocArray = [];
+
+ foreach ($pairs as $pair) {
+ $parts = explode(';', $pair);
+ if (count($parts) == 2) {
+ [$label, $val] = $parts;
+ $assocArray[$label] = $val;
+ }
+ }
+
+ $this->colorPickerValues = $assocArray;
+ }
+
+
+ public function getForeignTable(): string
+ {
+ return $this->foreignTable;
+ }
+
+ public function setForeignTable(string $foreignTable): void
+ {
+ $this->foreignTable = $foreignTable;
+ }
+
+ public function getRenderType(): string
+ {
+ return $this->renderType;
+ }
+
+ public function setRenderType(string $renderType): void
+ {
+ $this->renderType = $renderType;
+ }
+
+ public function getWhereClause(): string
+ {
+ return $this->whereClause;
+ }
+
+ public function setWhereClause(string $whereClause): void
+ {
+ $this->whereClause = $whereClause;
+ }
+
+ public function getSize(): int
+ {
+ return $this->size;
+ }
+
+ public function setSize(int $size): void
+ {
+ $this->size = $size;
+ }
+
+ public function getMaxItems(): int
+ {
+ return $this->maxItems;
+ }
+
+ public function setMaxItems(int $maxItems): void
+ {
+ $this->maxItems = $maxItems;
+ }
+
+ public function getMinItems(): int
+ {
+ return $this->minItems;
+ }
+
+ public function setMinItems(int $minItems): void
+ {
+ $this->minItems = $minItems;
+ }
+
+ public function isEnableRichtext(): bool
+ {
+ return $this->enableRichtext;
+ }
+
+ public function setEnableRichtext(bool $enableRichtext): void
+ {
+ $this->enableRichtext = $enableRichtext;
+ }
+
+ public function getRows(): int
+ {
+ return $this->rows;
+ }
+
+ public function setRows(int $rows): void
+ {
+ $this->rows = $rows;
+ }
+
+ public function isEnableSlider(): bool
+ {
+ return $this->enableSlider;
+ }
+
+ public function setEnableSlider(bool $enableSlider): void
+ {
+ $this->enableSlider = $enableSlider;
+ }
+
+ public function isSetRange(): bool
+ {
+ return $this->setRange;
+ }
+
+ public function setSetRange(bool $setRange): void
+ {
+ $this->setRange = $setRange;
+ }
+
+ public function getLowerRange(): int
+ {
+ return $this->lowerRange;
+ }
+
+ public function setLowerRange(int $lowerRange): void
+ {
+ $this->lowerRange = $lowerRange;
+ }
+
+ public function getUpperRange(): int
+ {
+ return $this->upperRange;
+ }
+
+ public function setUpperRange(int $upperRange): void
+ {
+ $this->upperRange = $upperRange;
+ }
+
+ public function getSteps(): float|int
+ {
+ return $this->steps;
+ }
+
+ public function setSteps(float|int $steps): void
+ {
+ $this->steps = $steps;
+ }
+
+ public function isRenderPasswordGenerator(): bool
+ {
+ return $this->renderPasswordGenerator;
+ }
+
+ public function setRenderPasswordGenerator(bool $renderPasswordGenerator): void
+ {
+ $this->renderPasswordGenerator = $renderPasswordGenerator;
+ }
+
+ public function isRenderTypeBoolean(): string
+ {
+ return $this->renderTypeBoolean;
+ }
+
+ public function setRenderTypeBoolean(string $renderTypeBoolean): void
+ {
+ $this->renderTypeBoolean = $renderTypeBoolean;
+ }
+
+ public function getDbTypeDateTime(): string
+ {
+ return $this->dbTypeDateTime;
+ }
+
+ public function setDbTypeDateTime(string $dbTypeDateTime): void
+ {
+ $this->dbTypeDateTime = $dbTypeDateTime;
+ }
+
+ public function getFormatDateTime(): string
+ {
+ return $this->formatDateTime;
+ }
+
+ public function setFormatDateTime(string $formatDateTime): void
+ {
+ $this->formatDateTime = $formatDateTime;
+ }
}
diff --git a/Classes/Domain/Model/DomainObject/NoneProperty.php b/Classes/Domain/Model/DomainObject/NoneProperty.php
index f531b700c..a9ad4a0c4 100644
--- a/Classes/Domain/Model/DomainObject/NoneProperty.php
+++ b/Classes/Domain/Model/DomainObject/NoneProperty.php
@@ -26,7 +26,7 @@ class NoneProperty extends AbstractProperty
*/
public function getIsPersistable(): bool
{
- return false;
+ return true;
}
public function getTypeForComment(): string
@@ -41,6 +41,6 @@ public function getTypeHint(): string
public function getSqlDefinition(): string
{
- return '';
+ return $this->getFieldName() . " mediumblob,";
}
}
diff --git a/Classes/Domain/Model/DomainObject/Relation/ZeroToManyRelation.php b/Classes/Domain/Model/DomainObject/Relation/ZeroToManyRelation.php
index 9356f9457..84f79d4af 100644
--- a/Classes/Domain/Model/DomainObject/Relation/ZeroToManyRelation.php
+++ b/Classes/Domain/Model/DomainObject/Relation/ZeroToManyRelation.php
@@ -63,13 +63,4 @@ public function getUseMMTable(): bool
{
return false;
}
-
- /**
- * @return bool true (if property is of type relation any to many)
- * @deprecated Use `instanceof ZeroToManyRelation` instead
- */
- public function isZeroToManyRelation(): bool
- {
- return true;
- }
}
diff --git a/Classes/Domain/Model/DomainObject/SelectProperty.php b/Classes/Domain/Model/DomainObject/SelectProperty.php
index b18a1f01f..492541b39 100644
--- a/Classes/Domain/Model/DomainObject/SelectProperty.php
+++ b/Classes/Domain/Model/DomainObject/SelectProperty.php
@@ -38,6 +38,6 @@ public function getTypeHint(): string
public function getSqlDefinition(): string
{
- return $this->getFieldName() . " int(11) DEFAULT '0' NOT NULL,";
+ return $this->getFieldName() . " varchar(255) DEFAULT '' NOT NULL,";
}
}
diff --git a/Classes/Domain/Model/Extension.php b/Classes/Domain/Model/Extension.php
index c3d3c8444..9d4f659c8 100644
--- a/Classes/Domain/Model/Extension.php
+++ b/Classes/Domain/Model/Extension.php
@@ -637,30 +637,34 @@ public function setSourceLanguage(string $sourceLanguage): void
public function getComposerInfo(): array
{
+ // TODO: consider moving this into the CodeTemplates
+ $authors = [];
+ foreach ($this->persons as $person) {
+ $author = [
+ 'name' => $person->getName()
+ ];
+ if ($person->getRole() !== '') {
+ $author['role'] = $person->getRole();
+ }
+ $authors[] = $author;
+ }
+
$extensionKey = $this->extensionKey;
$composerExtensionKey = strtolower(str_replace('_', '-', $extensionKey));
$info = [
'name' => strtolower(str_replace('_', '', GeneralUtility::camelCaseToLowerCaseUnderscored($this->vendorName))) . '/' . $composerExtensionKey,
'type' => 'typo3-cms-extension',
'description' => $this->description,
- 'authors' => [],
+ 'authors' => $authors,
'license' => 'GPL-2.0-or-later',
'require' => [
- 'typo3/cms-core' => '^11.5'
- ],
- 'require-dev' => [
- 'typo3/testing-framework' => '^6.9.0'
+ 'typo3/cms-core' => '^12.4'
],
'autoload' => [
'psr-4' => [
$this->getNamespaceName() . '\\' => 'Classes'
]
],
- 'autoload-dev' => [
- 'psr-4' => [
- $this->getNamespaceName() . '\\Tests\\' => 'Tests'
- ]
- ],
'replace' => [
'typo3-ter/' . $composerExtensionKey => 'self.version'
],
@@ -680,15 +684,6 @@ public function getComposerInfo(): array
]
]
];
- foreach ($this->persons as $person) {
- $author = [
- 'name' => $person->getName()
- ];
- if ($person->getRole() !== '') {
- $author['role'] = $person->getRole();
- }
- $info['authors'][] = $author;
- }
return $info;
}
}
diff --git a/Classes/Domain/Validator/ExtensionValidator.php b/Classes/Domain/Validator/ExtensionValidator.php
index fae2db8a7..a475f563c 100644
--- a/Classes/Domain/Validator/ExtensionValidator.php
+++ b/Classes/Domain/Validator/ExtensionValidator.php
@@ -191,12 +191,12 @@ public function injectExtensionBuilderConfigurationManager(
/**
* Validate the given extension
*
- * @param Extension $extension
+ * @param mixed $extension
*
* @return array[]
* @throws Exception
*/
- public function isValid($extension): array
+ public function isValid(mixed $extension): void
{
$extensionSettings = $extension->getSettings();
if (isset($extensionSettings['ignoreWarnings'])) {
@@ -222,7 +222,8 @@ public function isValid($extension): array
$this->validationResult['warnings'] = $warningsToKeep;
}
- return $this->validationResult;
+ // TODO void must not return anything
+ // return $this->validationResult;
}
/**
@@ -427,7 +428,7 @@ public function validateConfigurationFormat(array $configuration): array
$propertyNames = [];
if (isset($domainObjectConfiguration['value']['propertyGroup']['properties'])) {
foreach ($domainObjectConfiguration['value']['propertyGroup']['properties'] as $property) {
- if (in_array($property['propertyName'], $propertyNames, true)) {
+ if (in_array($property['propertyName'] ?? '', $propertyNames, true)) {
$this->validationResult['errors'][] = new ExtensionException(
'Property "' . $property['propertyName'] . '" of Model "' . $domainObjectConfiguration['value']['name'] . '" exists twice.',
self::ERROR_PROPERTY_DUPLICATE
diff --git a/Classes/Parser/ClassFactory.php b/Classes/Parser/ClassFactory.php
index ffa5d75aa..7ba5c1d18 100644
--- a/Classes/Parser/ClassFactory.php
+++ b/Classes/Parser/ClassFactory.php
@@ -88,8 +88,8 @@ public function buildPropertyObject(Property $propertyNode): Model\ClassObject\P
foreach ($propertyNode->props as $subNode) {
if ($subNode instanceof PropertyProperty) {
$propertyName = $subNode->name->name;
- if ($subNode->default) {
- $propertyDefault = $subNode->default;
+ if ($subNode->getAttribute('default')) {
+ $propertyDefault = $subNode->getAttribute('default');
}
}
}
@@ -149,8 +149,8 @@ protected function setFunctionProperties(Stmt $node, FunctionObject $object): Fu
$parameter->setTypeForParamTag($paramTag[0]);
}
}
- if ($param->default !== null) {
- $parameter->setDefaultValue($param->default);
+ if ($param->getAttribute('default') !== null) {
+ $parameter->setDefaultValue($param->getAttribute('default'));
}
$object->setParameter($parameter);
$position++;
diff --git a/Classes/Parser/NodeFactory.php b/Classes/Parser/NodeFactory.php
index 4703e8b61..0559a7670 100644
--- a/Classes/Parser/NodeFactory.php
+++ b/Classes/Parser/NodeFactory.php
@@ -226,14 +226,15 @@ public function buildPropertyNode(Property $property): Stmt\Property
foreach ($propertyNode->props as $subNode) {
if ($subNode instanceof PropertyProperty) {
if (null !== $property->getDefaultValueNode()) {
- $subNode->default = $property->getDefaultValueNode();
+ $subNode->setAttribute('default', $property->getDefaultValueNode());
} else {
- $subNode->default = self::buildNodeFromValue($property->getDefault());
+ $subNode->setAttribute('default', self::buildNodeFromValue($property->getDefault()));
}
}
}
$this->addCommentAttributes($property, $propertyNode);
+ $propertyNode->setAttribute('default', $property->getDefault());
return $propertyNode;
}
diff --git a/Classes/Service/ClassBuilder.php b/Classes/Service/ClassBuilder.php
index 38919b0a6..350e971a9 100644
--- a/Classes/Service/ClassBuilder.php
+++ b/Classes/Service/ClassBuilder.php
@@ -256,6 +256,7 @@ protected function addClassProperty(AbstractProperty $domainProperty): void
protected function addInitStorageObjectCalls(DomainObject $domainObject): void
{
$anyToManyRelationProperties = $domainObject->getAnyToManyRelationProperties();
+
if (count($anyToManyRelationProperties) > 0) {
if (!$this->classObject->methodExists('__construct')) {
$constructorMethod = $this->templateClassObject->getMethod('__construct');
@@ -693,7 +694,33 @@ public function generateControllerClassFileObject(
$parentClass = $this->settings['Controller']['parentClass'] ?? '\\TYPO3\\CMS\\Extbase\\Mvc\\Controller\\ActionController';
$this->classObject->setParentClassName($parentClass);
}
+
if ($domainObject->isAggregateRoot()) {
+
+
+ if($domainObject->getControllerScope() === "Backend") {
+ $moduleTemplateName = 'moduleTemplate';
+ if (!$this->classObject->propertyExists($moduleTemplateName)) {
+ /** @var AbstractProperty $classProperty */
+ $classProperty = $this->templateClassObject->getProperty('moduleTemplate');
+ $classProperty->setName($moduleTemplateName);
+ $classProperty->setDescription($moduleTemplateName);
+ // $classProperty->setTag('var', 'ModuleTemplate $moduleTemplate', true);
+ $this->classObject->setProperty($classProperty);
+ }
+
+ // Only set moduleTemplateFactory for Scope -> Backend
+ $moduleTemplateFactoryName = 'moduleTemplateFactory';
+ if (!$this->classObject->propertyExists($moduleTemplateFactoryName)) {
+ /** @var AbstractProperty $classProperty */
+ $classProperty = $this->templateClassObject->getProperty('moduleTemplateFactory');
+ $classProperty->setName($moduleTemplateFactoryName);
+ $classProperty->setDescription($moduleTemplateFactoryName);
+ // $classProperty->setTag('var', 'ModuleTemplate $moduleTemplate', true);
+ $this->classObject->setProperty($classProperty);
+ }
+ }
+
$repositoryName = lcfirst($domainObject->getName() . 'Repository');
// now add the property to class Object (or update an existing class Object property)
if (!$this->classObject->propertyExists($repositoryName)) {
@@ -704,10 +731,24 @@ public function generateControllerClassFileObject(
$classProperty->setTag('var', $domainObject->getFullyQualifiedDomainRepositoryClassName(), true);
$this->classObject->setProperty($classProperty);
}
+
+ if (!$this->classObject->methodExists('__construct')) {
+ $constructorMethod = $this->buildConstructorMethod($domainObject);
+ $this->classObject->addMethod($constructorMethod);
+ }
+
if (!$this->classObject->methodExists('inject' . ucfirst($repositoryName))) {
$injectRepositoryMethod = $this->buildInjectMethod($domainObject);
$this->classObject->addMethod($injectRepositoryMethod);
}
+
+ if($domainObject->getControllerScope() === "Backend") {
+ // Only set initializeAction for Scope -> Backend
+ if (!$this->classObject->methodExists('initializeAction')) {
+ $initializeActionMethod = $this->buildInitializeActionMethod($domainObject);
+ $this->classObject->addMethod($initializeActionMethod);
+ }
+ }
}
foreach ($domainObject->getActions() as $action) {
$actionMethodName = $action->getName() . 'Action';
@@ -722,6 +763,30 @@ public function generateControllerClassFileObject(
return $this->classFileObject;
}
+ protected function buildConstructorMethod(DomainObject $domainObject): Method
+ {
+ $constructorName = '__construct';
+ if ($this->classObject->methodExists($constructorName)) {
+ return $this->classObject->getMethod($constructorName);
+ }
+
+ $constructorMethod = clone $this->templateClassObject->getMethod('__construct')->setName($constructorName);
+
+ return $constructorMethod;
+ }
+
+ protected function buildInitializeActionMethod(DomainObject $domainObject): Method
+ {
+ $initializeActionName = 'initializeAction';
+ if ($this->classObject->methodExists($initializeActionName)) {
+ return $this->classObject->getMethod($initializeActionName);
+ }
+
+ $initializeActionMethod = clone $this->templateClassObject->getMethod('initializeAction')->setName($initializeActionName);
+
+ return $initializeActionMethod;
+ }
+
protected function buildInjectMethod(DomainObject $domainObject): Method
{
$repositoryName = $domainObject->getName() . 'Repository';
diff --git a/Classes/Service/ExtensionService.php b/Classes/Service/ExtensionService.php
index 898d70492..d434d3d84 100644
--- a/Classes/Service/ExtensionService.php
+++ b/Classes/Service/ExtensionService.php
@@ -18,6 +18,10 @@
namespace EBT\ExtensionBuilder\Service;
use TYPO3\CMS\Core\Core\Environment;
+use TYPO3\CMS\Core\Messaging\FlashMessage;
+use TYPO3\CMS\Core\Messaging\FlashMessageQueue;
+use TYPO3\CMS\Core\Messaging\FlashMessageService;
+use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\PathUtility;
@@ -78,9 +82,30 @@ public function resolveComposerStoragePaths(): array
$storagePaths[] = preg_replace('#/[*?/]+$#', '', $repositoryPath);
}
}
+
+ // Check whether $storagePaths is empty and add a notification if so
+ if (empty($storagePaths)) {
+ $this->setNotification('No storage Path detected!', 'There was no storage path detected. Please refer to the documentation (section "Installation") to get more infos on how to solve this issue.', ContextualFeedbackSeverity::ERROR);
+ }
+
return $storagePaths;
}
+ private function setNotification($title = '', $message = '', $severity = ContextualFeedbackSeverity::INFO)
+ {
+ $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
+ $notificationQueue = $flashMessageService->getMessageQueueByIdentifier(
+ FlashMessageQueue::NOTIFICATION_QUEUE
+ );
+ $flashMessage = GeneralUtility::makeInstance(
+ FlashMessage::class,
+ $message,
+ $title,
+ $severity
+ );
+ $notificationQueue->enqueue($flashMessage);
+ }
+
public function isComposerStoragePath(string $path): bool
{
foreach ($this->resolveComposerStoragePaths() as $composerStoragePath) {
diff --git a/Classes/Service/FileGenerator.php b/Classes/Service/FileGenerator.php
index 224572b07..558297c21 100644
--- a/Classes/Service/FileGenerator.php
+++ b/Classes/Service/FileGenerator.php
@@ -1,5 +1,6 @@
roundTripEnabled = true;
$this->roundTripService->initialize($extension);
}
- if (isset($this->settings['codeTemplateRootPaths.'])) {
- $this->codeTemplateRootPaths = $this->settings['codeTemplateRootPaths.'];
+ if (isset($this->settings['codeTemplateRootPaths'])) {
+ $this->codeTemplateRootPaths = $this->settings['codeTemplateRootPaths'];
} else {
throw new Exception('No codeTemplateRootPath configured');
}
- if (isset($this->settings['codeTemplatePartialPaths.'])) {
- $this->codeTemplatePartialPaths = $this->settings['codeTemplatePartialPaths.'];
+ if (isset($this->settings['codeTemplatePartialPaths'])) {
+ $this->codeTemplatePartialPaths = $this->settings['codeTemplatePartialPaths'];
} else {
throw new Exception('No codeTemplatePartialPaths configured');
}
@@ -169,10 +171,19 @@ public function build(Extension $extension): void
$this->generateIconsFile();
+ $this->generateModulesFile();
+
+ // Only execute, if there is one or more domain object
+ if (count($extension->getDomainObjects()) > 0) {
+ $this->generateServicesYamlFile();
+ }
+
$this->copyStaticFiles();
$this->generateTCAFiles();
+ $this->generateFlexFormsFiles();
+
$this->generateExtbaseConfigClass();
$this->generateTyposcriptFiles();
@@ -274,6 +285,47 @@ protected function generateIconsFile(): void
}
}
+ /**
+ * @throws Exception
+ */
+ protected function generateModulesFile(): void
+ {
+ if (!$this->extension->hasBackendModules()) {
+ return;
+ }
+ try {
+ GeneralUtility::mkdir_deep($this->extensionDirectory . 'Configuration/Backend');
+
+ $fileContents = $this->renderTemplate(
+ 'Configuration/Backend/Modules.phpt',
+ [
+ 'extension' => $this->extension
+ ]
+ );
+ $this->writeFile($this->extensionDirectory . 'Configuration/Backend/Modules.php', $fileContents);
+ } catch (Exception $e) {
+ throw new Exception('Could not write Configuration/Backend/Modules.php. Error: ' . $e->getMessage());
+ }
+ }
+
+ protected function generateServicesYamlFile(): void
+ {
+ try {
+ GeneralUtility::mkdir_deep($this->extensionDirectory . 'Configuration');
+
+ $fileContents = $this->renderTemplate(
+ 'Configuration/Services.yamlt',
+ [
+ 'namespace' => $this->extension->getNamespaceName()
+ ]
+ );
+ // $this->writeFile($this->extensionDirectory . 'Configuration/Services.yaml', $yamlContent);
+ $this->writeFile($this->extensionDirectory . 'Configuration/Services.yaml', $fileContents);
+ } catch (Exception $e) {
+ throw new Exception('Could not write Configuration/Services.yaml. Error: ' . $e->getMessage());
+ }
+ }
+
/**
* @throws Exception
*/
@@ -320,6 +372,7 @@ protected function generateTCAFiles(): void
);
if ($this->extension->hasPlugins()) {
+ // write tt_content.php
$fileContents = $this->generateTCAOverrideTtContent();
$this->writeFile(
$this->configurationDirectory . 'TCA/Overrides/tt_content.php',
@@ -536,12 +589,6 @@ protected function generateDomainObjectRelatedFiles(): void
$domainRepositoryDirectory = 'Classes/Domain/Repository/';
$this->mkdir_deep($this->extensionDirectory, $domainRepositoryDirectory);
- $domainModelTestsDirectory = $this->extensionDirectory . 'Tests/Unit/Domain/Model/';
- $this->mkdir_deep($this->extensionDirectory, 'Tests/Unit/Domain/Model');
-
- $crudEnabledControllerTestsDirectory = $this->extensionDirectory . 'Tests/Unit/Controller/';
- $this->mkdir_deep($this->extensionDirectory, 'Tests/Unit/Controller');
-
foreach ($this->extension->getDomainObjects() as $domainObject) {
$destinationFile = $domainModelDirectory . $domainObject->getName() . '.php';
@@ -570,32 +617,11 @@ protected function generateDomainObjectRelatedFiles(): void
$this->writeFile($this->extensionDirectory . $destinationFile, $fileContents);
$this->extension->setMD5Hash($this->extensionDirectory . $destinationFile);
}
-
- // Generate basic UnitTests
- $fileContents = $this->generateDomainModelTests($domainObject);
- $fileContents = preg_replace('#^[ \t]+$#m', '', $fileContents);
- $this->writeFile($domainModelTestsDirectory . $domainObject->getName() . 'Test.php', $fileContents);
}
} catch (Exception $e) {
throw new Exception('Could not generate domain model, error: ' . $e->getMessage());
}
- // Generate Functional Tests
- try {
- $this->mkdir_deep($this->extensionDirectory, 'Tests/Functional');
- $functionalTestsDirectory = $this->extensionDirectory . 'Tests/Functional/';
-
- // Generate basic FunctionalTests
- $fileContents = $this->generateFunctionalTests();
- $fileContents = preg_replace('#^[ \t]+$#m', '', $fileContents);
- $this->writeFile(
- $functionalTestsDirectory . 'BasicTest.php',
- $fileContents
- );
- } catch (Exception $e) {
- throw new Exception('Could not generate functional tests, error: ' . $e->getMessage());
- }
-
// Generate Action Controller
try {
$this->mkdir_deep($this->extensionDirectory, 'Classes/Controller');
@@ -606,17 +632,6 @@ protected function generateDomainObjectRelatedFiles(): void
$fileContents = preg_replace('#^[ \t]+$#m', '', $fileContents);
$this->writeFile($this->extensionDirectory . $destinationFile, $fileContents);
$this->extension->setMD5Hash($this->extensionDirectory . $destinationFile);
-
- // Generate basic UnitTests
- $fileContents = $this->generateControllerTests(
- $domainObject->getName() . 'Controller',
- $domainObject
- );
- $fileContents = preg_replace('#^[ \t]+$#m', '', $fileContents);
- $this->writeFile(
- $crudEnabledControllerTestsDirectory . $domainObject->getName() . 'ControllerTest.php',
- $fileContents
- );
}
} catch (Exception $e) {
throw new Exception('Could not generate action controller, error: ' . $e->getMessage());
@@ -802,14 +817,17 @@ public function renderTemplate(string $filePath, array $variables): ?string
*/
public function generateActionControllerCode(DomainObject $domainObject): string
{
- $controllerTemplateFilePath = $this->getTemplatePath('Classes/Controller/Controller.phpt');
+ $frontendControllerTemplateFilePath = $this->getTemplatePath('Classes/Controller/FrontendController.phpt');
+ $backendControllerTemplateFilePath = $this->getTemplatePath('Classes/Controller/BackendController.phpt');
+
+ $scope = $domainObject->getControllerScope();
$existingClassFileObject = null;
if ($this->roundTripEnabled) {
$existingClassFileObject = $this->roundTripService->getControllerClassFile($domainObject);
}
$controllerClassFileObject = $this->classBuilder->generateControllerClassFileObject(
$domainObject,
- $controllerTemplateFilePath,
+ $domainObject->getControllerScope() === 'Frontend' ? $frontendControllerTemplateFilePath : $backendControllerTemplateFilePath,
$existingClassFileObject
);
// returns a class object if an existing class was found
@@ -882,40 +900,6 @@ public function generateDomainRepositoryCode(DomainObject $domainObject): string
throw new Exception('Class file for repository could not be generated');
}
- /**
- * Generate the tests for a model
- *
- * @param DomainObject $domainObject
- *
- * @return string|null
- * @throws Exception
- */
- public function generateDomainModelTests(DomainObject $domainObject): ?string
- {
- return $this->renderTemplate('Tests/Unit/DomainModelTest.phpt', [
- 'extension' => $this->extension,
- 'domainObject' => $domainObject
- ]);
- }
-
- /**
- * Generate the tests for a CRUD-enabled controller
- *
- * @param string $controllerName
- * @param DomainObject $domainObject
- *
- * @return string|null
- * @throws Exception
- */
- public function generateControllerTests(string $controllerName, DomainObject $domainObject): ?string
- {
- return $this->renderTemplate('Tests/Unit/ControllerTest.phpt', [
- 'extension' => $this->extension,
- 'controllerName' => $controllerName,
- 'domainObject' => $domainObject
- ]);
- }
-
/**
* @throws Exception
*/
@@ -940,19 +924,6 @@ public function generateExtbaseConfigClass(): void
}
}
- /**
- * Generate a functional test
- *
- * @return string|null
- * @throws Exception
- */
- public function generateFunctionalTests(): ?string
- {
- return $this->renderTemplate('Tests/Functional/BasicTest.phpt', [
- 'extension' => $this->extension,
- ]);
- }
-
/**
* @throws Exception
*/
@@ -1236,6 +1207,38 @@ public function generateTCAOverrideTtContent(): ?string
]);
}
+ /**
+ * Generates the content of each FlexForm File
+ *
+ * @return mixed
+ * @throws Exception
+ */
+ public function generateFlexFormsFiles(): void
+ {
+ if($this->extension->hasPlugins()) {
+ $this->mkdir_deep($this->extensionDirectory, 'Configuration/FlexForms');
+ } else {
+ // no plugins, no FlexForms
+ return;
+ }
+
+ foreach ($this->extension->getPlugins() as $plugin) {
+ // check if file already exists
+ if (file_exists($this->extensionDirectory . 'Configuration/FlexForms/flexform_' . $plugin->getKey() . '.xml')) {
+ continue;
+ }
+
+ $fileContents = $this->renderTemplate('Configuration/FlexForms/plugin_flexform.phpt', [
+ 'extension' => $this->extension,
+ 'plugin' => $plugin
+ ]);
+ $this->writeFile(
+ $this->extensionDirectory . 'Configuration/FlexForms/flexform_' . $plugin->getKey() . '.xml',
+ $fileContents
+ );
+ }
+ }
+
/**
* Add TCA configuration for sys_template
*
@@ -1403,7 +1406,7 @@ protected function writeFile(string $targetFile, string $fileContents): void
if (empty($fileContents)) {
return;
}
- $success = GeneralUtility::writeFile($targetFile, $fileContents);
+ $success = GeneralUtility::writeFile($targetFile, $fileContents, true);
if (!$success) {
throw new Exception('File ' . $targetFile . ' could not be created!');
}
diff --git a/Classes/Service/LocalizationService.php b/Classes/Service/LocalizationService.php
index de8d02561..c52e5e07a 100644
--- a/Classes/Service/LocalizationService.php
+++ b/Classes/Service/LocalizationService.php
@@ -105,8 +105,8 @@ public function prepareLabelArrayForContextHelp(DomainObject $domainObject): arr
public function prepareLabelArrayForBackendModule(BackendModule $backendModule): array
{
return [
- 'mlang_labels_tabdescr' => htmlspecialchars($backendModule->getDescription()),
'mlang_tabs_tab' => htmlspecialchars($backendModule->getTabLabel()),
+ 'mlang_labels_tablabel' => htmlspecialchars($backendModule->getDescription()),
];
}
diff --git a/Classes/Service/ObjectSchemaBuilder.php b/Classes/Service/ObjectSchemaBuilder.php
index 9c9cb9729..1081b6dde 100644
--- a/Classes/Service/ObjectSchemaBuilder.php
+++ b/Classes/Service/ObjectSchemaBuilder.php
@@ -64,6 +64,7 @@ public function build(array $jsonDomainObject): DomainObject
$domainObject->setEntity(false);
}
$domainObject->setAggregateRoot($jsonDomainObject['objectsettings']['aggregateRoot'] ?? false);
+ $domainObject->setControllerScope($jsonDomainObject['objectsettings']['controllerScope'] ?? 'Frontend');
$domainObject->setSorting($jsonDomainObject['objectsettings']['sorting'] ?? false);
$domainObject->setAddDeletedField($jsonDomainObject['objectsettings']['addDeletedField'] ?? false);
$domainObject->setAddHiddenField($jsonDomainObject['objectsettings']['addHiddenField'] ?? false);
@@ -81,6 +82,7 @@ public function build(array $jsonDomainObject): DomainObject
if (isset($jsonDomainObject['propertyGroup']['properties'])) {
foreach ($jsonDomainObject['propertyGroup']['properties'] as $propertyJsonConfiguration) {
$propertyType = $propertyJsonConfiguration['propertyType'];
+ // TODO: Check, if this needs to be extended to other types as well
if (in_array($propertyType, ['Image', 'File'])
&& !empty($propertyJsonConfiguration['maxItems'])
&& $propertyJsonConfiguration['maxItems'] > 1
@@ -157,10 +159,10 @@ public function buildRelation(array $relationJsonConfiguration, DomainObject $do
}
/** @var AbstractRelation $relation */
$relation = new $relationSchemaClassName();
- $relation->setName($relationJsonConfiguration['relationName']);
+ $relation->setName($relationJsonConfiguration['relationName'] ?? '');
$relation->setLazyLoading((bool)($relationJsonConfiguration['lazyLoading'] ?? false));
$relation->setNullable((bool)($relationJsonConfiguration['propertyIsNullable'] ?? false));
- $relation->setExcludeField((bool)$relationJsonConfiguration['propertyIsExcludeField']);
+ $relation->setExcludeField((bool)($relationJsonConfiguration['excludeField'] ?? false));
$relation->setDescription($relationJsonConfiguration['relationDescription'] ?? '');
$relation->setUniqueIdentifier($relationJsonConfiguration['uid'] ?? '');
$relation->setType($relationJsonConfiguration['type'] ?? '');
@@ -202,9 +204,14 @@ public function buildRelation(array $relationJsonConfiguration, DomainObject $do
if (!empty($relationJsonConfiguration['maxItems'])) {
/** @var FileProperty $relation */
$relation->setMaxItems((int)$relationJsonConfiguration['maxItems']);
- if (!empty($relationJsonConfiguration['allowedFileTypes'])) {
- $relation->setAllowedFileTypes($relationJsonConfiguration['allowedFileTypes']);
- }
+ }
+ if (!empty($relationJsonConfiguration['minItems'])) {
+ /** @var FileProperty $relation */
+ $relation->setMinItems((int)$relationJsonConfiguration['minItems']);
+ }
+ if (!empty($relationJsonConfiguration['typeFile']['allowedFileTypes'])) {
+ /** @var FileProperty $relation */
+ $relation->setAllowedFileTypes($relationJsonConfiguration['typeFile']['allowedFileTypes']);
}
}
}
@@ -219,7 +226,7 @@ public function buildRelation(array $relationJsonConfiguration, DomainObject $do
public static function buildProperty(array $propertyJsonConfiguration): AbstractProperty
{
$propertyType = $propertyJsonConfiguration['propertyType'];
- $propertyClassName = 'EBT\\ExtensionBuilder\\Domain\Model\\DomainObject\\' . $propertyType . 'Property';
+ $propertyClassName = 'EBT\\ExtensionBuilder\\Domain\\Model\\DomainObject\\' . $propertyType . 'Property';
if (!class_exists($propertyClassName)) {
throw new Exception('Property of type ' . $propertyType . ' not found');
}
@@ -230,19 +237,17 @@ public static function buildProperty(array $propertyJsonConfiguration): Abstract
if (isset($propertyJsonConfiguration['propertyDescription'])) {
$property->setDescription($propertyJsonConfiguration['propertyDescription']);
}
-
if ($propertyType === 'File' && !empty($propertyJsonConfiguration['allowedFileTypes'])) {
$property->setAllowedFileTypes($propertyJsonConfiguration['allowedFileTypes']);
}
-
if (isset($propertyJsonConfiguration['propertyIsRequired'])) {
$property->setRequired($propertyJsonConfiguration['propertyIsRequired']);
}
if (isset($propertyJsonConfiguration['propertyIsNullable'])) {
$property->setNullable($propertyJsonConfiguration['propertyIsNullable']);
}
- if (isset($propertyJsonConfiguration['propertyIsExcludeField'])) {
- $property->setExcludeField($propertyJsonConfiguration['propertyIsExcludeField']);
+ if (isset($propertyJsonConfiguration['excludeField'])) {
+ $property->setExcludeField($propertyJsonConfiguration['excludeField']);
}
if (isset($propertyJsonConfiguration['propertyIsL10nModeExclude'])) {
$property->setL10nModeExclude($propertyJsonConfiguration['propertyIsL10nModeExclude']);
@@ -250,6 +255,70 @@ public static function buildProperty(array $propertyJsonConfiguration): Abstract
if ($property->isFileReference() && !empty($propertyJsonConfiguration['maxItems'])) {
$property->setMaxItems((int)$propertyJsonConfiguration['maxItems']);
}
+ if (isset($propertyJsonConfiguration['typeSelect']['selectboxValues'])) {
+ $property->setSelectboxValues($propertyJsonConfiguration['typeSelect']['selectboxValues']);
+ }
+ if (isset($propertyJsonConfiguration['typeSelect']['foreignTable'])) {
+ $property->setForeignTable($propertyJsonConfiguration['typeSelect']['foreignTable']);
+ }
+ if (isset($propertyJsonConfiguration['typeSelect']['whereClause'])) {
+ $property->setWhereClause($propertyJsonConfiguration['typeSelect']['whereClause']);
+ }
+ if (isset($propertyJsonConfiguration['typeSelect']['renderType'])) {
+ $property->setRenderType($propertyJsonConfiguration['typeSelect']['renderType']);
+ }
+ if (isset($propertyJsonConfiguration['typeText']['enableRichtext'])) {
+ $property->setEnableRichtext($propertyJsonConfiguration['typeText']['enableRichtext']);
+ }
+ if (isset($propertyJsonConfiguration['size'])) {
+ $property->setSize((int)$propertyJsonConfiguration['size']);
+ }
+ if (isset($propertyJsonConfiguration['rows'])) {
+ $property->setRows((int)$propertyJsonConfiguration['rows']);
+ }
+ if (isset($propertyJsonConfiguration['maxItems'])) {
+ $property->setMaxItems((int)$propertyJsonConfiguration['maxItems']);
+ }
+ if (isset($propertyJsonConfiguration['minItems'])) {
+ $property->setMinItems((int)$propertyJsonConfiguration['minItems']);
+ }
+ if (isset($propertyJsonConfiguration['typeNumber']['enableSlider'])) {
+ $property->setEnableSlider($propertyJsonConfiguration['typeNumber']['enableSlider']);
+ }
+ if (isset($propertyJsonConfiguration['typeNumber']['steps'])) {
+ $property->setSteps((float)$propertyJsonConfiguration['typeNumber']['steps']);
+ }
+ if (isset($propertyJsonConfiguration['typeNumber']['setRange'])) {
+ $property->setSetRange($propertyJsonConfiguration['typeNumber']['setRange']);
+ }
+ if (isset($propertyJsonConfiguration['typeNumber']['upperRange'])) {
+ $property->setUpperRange((int)$propertyJsonConfiguration['typeNumber']['upperRange']);
+ }
+ if (isset($propertyJsonConfiguration['typeNumber']['lowerRange'])) {
+ $property->setLowerRange((int)$propertyJsonConfiguration['typeNumber']['lowerRange']);
+ }
+ if (isset($propertyJsonConfiguration['typeColor']['setValuesColorPicker'])) {
+ $property->setSetValuesColorPicker((bool)$propertyJsonConfiguration['typeColor']['setValuesColorPicker']);
+ }
+ if (isset($propertyJsonConfiguration['typeBoolean']['booleanValues'])) {
+ $property->setBooleanValues($propertyJsonConfiguration['typeBoolean']['booleanValues']);
+ }
+ if (isset($propertyJsonConfiguration['typeColor']['colorPickerValues'])) {
+ $property->setColorPickerValues($propertyJsonConfiguration['typeColor']['colorPickerValues']);
+ }
+ if (isset($propertyJsonConfiguration['typePassword']['renderPasswordGenerator'])) {
+ $property->setRenderPasswordGenerator((bool)$propertyJsonConfiguration['typePassword']['renderPasswordGenerator']);
+ }
+ if (isset($propertyJsonConfiguration['typeBoolean']['renderType'])) {
+ $property->setRenderTypeBoolean($propertyJsonConfiguration['typeBoolean']['renderType']);
+ }
+ if (isset($propertyJsonConfiguration['typeDateTime']['dbTypeDateTime'])) {
+ $property->setDbTypeDateTime($propertyJsonConfiguration['typeDateTime']['dbTypeDateTime']);
+ }
+ if (isset($propertyJsonConfiguration['typeDateTime']['formatDateTime'])) {
+ $property->setFormatDateTime($propertyJsonConfiguration['typeDateTime']['formatDateTime']);
+ }
+
return $property;
}
}
diff --git a/Classes/Service/ValidationService.php b/Classes/Service/ValidationService.php
index d741885d2..d0be1136d 100644
--- a/Classes/Service/ValidationService.php
+++ b/Classes/Service/ValidationService.php
@@ -333,7 +333,6 @@ class ValidationService implements SingletonInterface
'fe_group',
'hidden',
'deleted',
- 'cruser_id',
'crdate',
'tstamp',
'sys_language',
diff --git a/Classes/Template/Components/Buttons/LinkButtonWithId.php b/Classes/Template/Components/Buttons/LinkButtonWithId.php
index 814de3082..07eadbc0d 100644
--- a/Classes/Template/Components/Buttons/LinkButtonWithId.php
+++ b/Classes/Template/Components/Buttons/LinkButtonWithId.php
@@ -21,6 +21,11 @@
class LinkButtonWithId extends LinkButton
{
+ /**
+ * id attribute of the link
+ */
+ protected string $id = '';
+
/**
* Get type
* Pretend that we are a link button to make the button valid
@@ -30,11 +35,6 @@ public function getType(): string
return LinkButton::class;
}
- /**
- * id attribute of the link
- */
- protected string $id = '';
-
public function getId(): string
{
return $this->id;
@@ -59,25 +59,23 @@ public function render(): string
];
$labelText = '';
if ($this->showLabelText) {
- $labelText = ' ShowHide ' . $this->title . '.';
+ // $labelText = ' ShowHide ' . $this->title . '.';
+ $labelText = ' ' . $this->title;
}
foreach ($this->dataAttributes as $attributeName => $attributeValue) {
$attributes['data-' . $attributeName] = $attributeValue;
}
- if ($this->onClick !== '') {
- $attributes['onclick'] = $this->onClick;
- }
if ($this->isDisabled()) {
$attributes['disabled'] = 'disabled';
$attributes['class'] .= ' disabled';
}
$attributesString = '';
foreach ($attributes as $key => $value) {
- $attributesString .= ' ' . htmlspecialchars($key) . '="' . htmlspecialchars($value) . '"';
+ $attributesString .= ' ' . htmlspecialchars($key) . '="' . htmlspecialchars($value ?? '') . '"';
}
return ''
- . $this->getIcon()->render() . $labelText // removed htmlspecialchars on purpose!
- . '';
+ . $this->getIcon()->render() . htmlspecialchars($labelText)
+ . '';
}
}
diff --git a/Classes/Utility/ExtensionInstallationStatus.php b/Classes/Utility/ExtensionInstallationStatus.php
index 6b27302f2..cc6a849c6 100644
--- a/Classes/Utility/ExtensionInstallationStatus.php
+++ b/Classes/Utility/ExtensionInstallationStatus.php
@@ -85,72 +85,8 @@ public function getStatusMessage(): string
return $statusMessage;
}
- /*public function checkForDbUpdate(string $extensionKey): void
- {
- $this->dbUpdateNeeded = false;
- if (ExtensionManagementUtility::isLoaded($extensionKey)) {
- $sqlFile = ExtensionManagementUtility::extPath($extensionKey) . 'ext_tables.sql';
- if (@file_exists($sqlFile)) {
- $sqlHandler = GeneralUtility::makeInstance(SqlSchemaMigrationService::class);
-
- $sqlContent = GeneralUtility::getUrl($sqlFile);
- $fieldDefinitionsFromFile = $sqlHandler->getFieldDefinitions_fileContent($sqlContent);
- if (count($fieldDefinitionsFromFile)) {
- $fieldDefinitionsFromCurrentDatabase = $sqlHandler->getFieldDefinitions_database();
- $updateTableDefinition = $sqlHandler->getDatabaseExtra(
- $fieldDefinitionsFromFile,
- $fieldDefinitionsFromCurrentDatabase
- );
- $this->updateStatements = $sqlHandler->getUpdateSuggestions($updateTableDefinition);
- if (!empty($updateTableDefinition['extra']) || !empty($updateTableDefinition['diff']) || !empty($updateTableDefinition['diff_currentValues'])) {
- $this->dbUpdateNeeded = true;
- }
- }
- }
- }
- }
-
- public function performDbUpdates(array $params): array
- {
- $hasErrors = false;
- if (!empty($params['updateStatements']) && !empty($params['extensionKey'])) {
- $this->checkForDbUpdate($params['extensionKey']);
- if ($this->dbUpdateNeeded) {
- foreach ($this->updateStatements as $type => $statements) {
- foreach ($statements as $key => $statement) {
- if (in_array($type, ['change', 'add', 'create_table'])
- && in_array($key, $params['updateStatements'])
- ) {
- $res = $this->getDatabaseConnection()->admin_query($statement);
- if ($res === false) {
- $hasErrors = true;
- } elseif (is_resource($res) || is_a($res, mysqli_result::class)) {
- $this->getDatabaseConnection()->sql_free_result($res);
- }
- }
- }
- }
- }
- }
- if ($hasErrors) {
- return ['error' => 'Database could not be updated. Please check it in the update wizzard of the install tool'];
- }
-
- return ['success' => 'Database was successfully updated'];
- }*/
-
public function isDbUpdateNeeded(): bool
{
return $this->dbUpdateNeeded;
}
-
- /*public function getUpdateStatements(): array
- {
- return $this->updateStatements;
- }
-
- protected function getDatabaseConnection()
- {
- return $GLOBALS['TYPO3_DB'];
- }*/
}
diff --git a/Classes/Utility/SpycYAMLParser.php b/Classes/Utility/SpycYAMLParser.php
deleted file mode 100644
index e2fa62f52..000000000
--- a/Classes/Utility/SpycYAMLParser.php
+++ /dev/null
@@ -1,1177 +0,0 @@
-
- * @author Chris Wanstrath
- * @link http://code.google.com/p/spyc/
- * @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2009 Vlad Andersen
- * @license http://www.opensource.org/licenses/mit-license.php MIT License
- */
-
-/**
- * The Simple PHP YAML Class.
- *
- * This class can be used to read a YAML file and convert its contents
- * into a PHP array. It currently supports a very limited subsection of
- * the YAML spec.
- *
- * Usage:
- *
- * $Spyc = new Spyc;
- * $array = $Spyc->load($file);
- *
- * or:
- *
- * $array = Spyc::YAMLLoad($file);
- *
- * or:
- *
- * $array = spyc_load_file($file);
- *
- */
-class SpycYAMLParser
-{
- /**
- * Setting this to true will force YAMLDump to enclose any string value in
- * quotes. false by default.
- */
- public bool $setting_dump_force_quotes = false;
- /**
- * Setting this to true will force YAMLLoad to use syck_load function when
- * possible. false by default.
- */
- public bool $setting_use_syck_is_possible = false;
- private int $_dumpIndent = 0;
- private int $_dumpWordWrap = 0;
- private bool $_containsGroupAnchor = false;
- private bool $_containsGroupAlias = false;
- private array $path = [];
- private array $result = [];
- private string $LiteralPlaceHolder = '___YAML_Literal_Block___';
- private array $SavedGroups = [];
- private int $indent = 0;
- /**
- * Path modifier that should be applied after adding current element.
- *
- * @var int[]
- */
- private array $delayedPath = [];
- /**
- * @var mixed
- */
- public $_nodeId;
-
- /**
- * Load a valid YAML string to Spyc.
- * @param string $input
- */
- public function load($input): array
- {
- return $this->__loadString($input);
- }
-
- /**
- * Load a valid YAML file to Spyc.
- * @param string $file
- */
- public function loadFile($file): array
- {
- return $this->__load($file);
- }
-
- /**
- * Load YAML into a PHP array statically
- *
- * The load method, when supplied with a YAML stream (string or file),
- * will do its best to convert YAML in a file into a PHP array. Pretty
- * simple.
- * Usage:
- *
- * $array = Spyc::YAMLLoad('lucky.yaml');
- * print_r($array);
- *
- * @param string $input Path of YAML file or string containing YAML
- */
- public static function YAMLLoad($input): array
- {
- $Spyc = new self();
- return $Spyc->__load($input);
- }
-
- /**
- * Load a string of YAML into a PHP array statically
- *
- * The load method, when supplied with a YAML string, will do its best
- * to convert YAML in a string into a PHP array. Pretty simple.
- *
- * Note: use this function if you don't want files from the file system
- * loaded and processed as YAML. This is of interest to people concerned
- * about security whose input is from a string.
- *
- * Usage:
- *
- * $array = Spyc::YAMLLoadString("---\n0: hello world\n");
- * print_r($array);
- *
- * @param string $input String containing YAML
- */
- public static function YAMLLoadString($input): array
- {
- $Spyc = new self();
- return $Spyc->__loadString($input);
- }
-
- /**
- * Dump YAML from PHP array statically
- *
- * The dump method, when supplied with an array, will do its best
- * to convert the array into friendly YAML. Pretty simple. Feel free to
- * save the returned string as nothing.yaml and pass it around.
- *
- * Oh, and you can decide how big the indent is and what the wordwrap
- * for folding is. Pretty cool -- just pass in 'false' for either if
- * you want to use the default.
- *
- * Indent's default is 2 spaces, wordwrap's default is 40 characters. And
- * you can turn off wordwrap by passing in 0.
- *
- * @param array $array PHP array
- * @param int $indent Pass in false to use the default, which is 2
- * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
- *
- *
- * @throws \Exception
- */
- public static function YAMLDump($array, $indent = false, $wordwrap = false): string
- {
- $spyc = new self();
- return $spyc->dump($array, $indent, $wordwrap);
- }
-
- /**
- * Dump PHP array to YAML
- *
- * The dump method, when supplied with an array, will do its best
- * to convert the array into friendly YAML. Pretty simple. Feel free to
- * save the returned string as tasteful.yaml and pass it around.
- *
- * Oh, and you can decide how big the indent is and what the wordwrap
- * for folding is. Pretty cool -- just pass in 'false' for either if
- * you want to use the default.
- *
- * Indent's default is 2 spaces, wordwrap's default is 40 characters. And
- * you can turn off wordwrap by passing in 0.
- *
- * @param array $array PHP array
- * @param int $indent Pass in false to use the default, which is 2
- * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
- *
- *
- * @throws \Exception
- */
- public function dump($array, $indent = false, $wordwrap = false): string
- {
- // Dumps to some very clean YAML. We'll have to add some more features
- // and options soon. And better support for folding.
-
- // New features and options.
- if ($indent === false or !is_numeric($indent)) {
- $this->_dumpIndent = 2;
- } else {
- $this->_dumpIndent = $indent;
- }
-
- if ($wordwrap === false or !is_numeric($wordwrap)) {
- $this->_dumpWordWrap = 40;
- } else {
- $this->_dumpWordWrap = $wordwrap;
- }
-
- // New YAML document
- $string = '---' . LF;
-
- // Start at the base of the array and move through it.
- if ($array) {
- $array = (array)$array;
- $first_key = key($array);
-
- $previous_key = -1;
- foreach ($array as $key => $value) {
- $string .= $this->_yamlize($key, $value, 0, $previous_key, $first_key);
- $previous_key = $key;
- }
- }
- return $string;
- }
-
- /**
- * Attempts to convert a key / value array item to YAML
- *
- * @param string $key The name of the key
- * @param mixed $value The value of the item
- * @param int $indent The indent of the current node
- *
- * @throws \Exception
- */
- private function _yamlize($key, $value, $indent, $previous_key = -1, $first_key = 0): string
- {
- if (is_array($value)) {
- if (empty($value)) {
- return $this->_dumpNode($key, [], $indent, $previous_key, $first_key);
- }
- // It has children. What to do?
- // Make it the right kind of item
- $string = $this->_dumpNode($key, null, $indent, $previous_key, $first_key);
- // Add the indent
- $indent += $this->_dumpIndent;
- // Yamlize the array
- $string .= $this->_yamlizeArray($value, $indent);
- } elseif (!is_array($value)) {
- // It doesn't have children. Yip.
- $string = $this->_dumpNode($key, $value, $indent, $previous_key, $first_key);
- } else {
- $string = '';
- }
-
- return $string;
- }
-
- /**
- * Attempts to convert an array to YAML
- *
- * @param array $array The array you want to convert
- * @param int $indent The indent of the current level
- *
- * @return string
- *
- * @throws \Exception
- */
- private function _yamlizeArray($array, $indent)
- {
- if (is_array($array)) {
- $string = '';
- $previous_key = -1;
- $first_key = key($array);
- foreach ($array as $key => $value) {
- $string .= $this->_yamlize($key, $value, $indent, $previous_key, $first_key);
- $previous_key = $key;
- }
- return $string;
- }
-
- return false;
- }
-
- /**
- * Returns YAML from a key and a value
- *
- * @param string $key The name of the key
- * @param mixed $value The value of the item
- * @param int $indent The indent of the current node
- *
- * @throws \Exception
- */
- private function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0): string
- {
- // do some folding here, for blocks
- if (is_string($value)
- && (
- (
- strpos($value, PHP_EOL) !== false
- || strpos($value, ': ') !== false
- || strpos($value, '- ') !== false
- || strpos($value, '*') !== false
- || strpos($value, '#') !== false
- || strpos($value, '<') !== false
- || strpos($value, '>') !== false
- || strpos($value, '[') !== false
- || strpos($value, ']') !== false
- || strpos($value, '{') !== false
- || strpos($value, '}') !== false
- )
- || substr($value, -1, 1) == ':'
- )
- ) {
- $value = $this->_doLiteralBlock($value, $indent);
- } else {
- $value = $this->_doFolding($value, $indent);
- if (is_bool($value)) {
- $value = ($value) ? 'true' : 'false';
- }
- }
-
- if ($value === []) {
- $value = '[ ]';
- }
-
- $spaces = str_repeat(' ', $indent);
-
- if (is_int($key) && $key - 1 == $previous_key && $first_key === 0) {
- // It's a sequence
- $string = $spaces . '- ' . $value . PHP_EOL;
- } else {
- if ($first_key === 0) {
- throw new \Exception('Keys are all screwy. The first one was zero, now it\'s "' . $key . '"');
- }
- // It's mapped
- if (strpos($key, ':') !== false) {
- $key = '"' . $key . '"';
- }
- $string = $spaces . $key . ': ' . $value . PHP_EOL;
- }
- return $string;
- }
-
- /**
- * Creates a literal block for dumping
- *
- * @param $value
- * @param $indent int The value of the indent
- * @return string
- */
- private function _doLiteralBlock($value, $indent): string
- {
- if (strpos($value, PHP_EOL) === false && strpos($value, "'") === false) {
- return sprintf("'%s'", $value);
- }
- if (strpos($value, PHP_EOL) === false && strpos($value, '"') === false) {
- return sprintf('"%s"', $value);
- }
- $exploded = explode(LF, $value);
- $newValue = '|';
- $indent += $this->_dumpIndent;
- $spaces = str_repeat(' ', $indent);
- foreach ($exploded as $line) {
- $newValue .= PHP_EOL . $spaces . trim($line);
- }
- return $newValue;
- }
-
- /**
- * Folds a string of text, if necessary
- *
- * @param string $value The string you wish to fold
- */
- private function _doFolding($value, $indent): string
- {
- // Don't do anything if wordwrap is set to 0
-
- if ($this->_dumpWordWrap !== 0 && is_string($value) && strlen($value) > $this->_dumpWordWrap) {
- $indent += $this->_dumpIndent;
- $indent = str_repeat(' ', $indent);
- $wrapped = wordwrap($value, $this->_dumpWordWrap, PHP_EOL . $indent);
- $value = '>' . PHP_EOL . $indent . $wrapped;
- } else {
- if ($this->setting_dump_force_quotes && is_string($value)) {
- $value = '"' . $value . '"';
- }
- }
-
- return $value;
- }
-
- // LOADING FUNCTIONS
-
- private function __load($input)
- {
- $Source = $this->loadFromSource($input);
- return $this->loadWithSource($Source);
- }
-
- private function __loadString($input)
- {
- $Source = $this->loadFromString($input);
- return $this->loadWithSource($Source);
- }
-
- private function loadWithSource($Source)
- {
- if (empty($Source)) {
- return [];
- }
- if ($this->setting_use_syck_is_possible && function_exists('syck_load')) {
- $array = syck_load(implode('', $Source));
- return is_array($array) ? $array : [];
- }
-
- $this->path = [];
- $this->result = [];
-
- $cnt = count($Source);
- for ($i = 0; $i < $cnt; $i++) {
- $line = $Source[$i];
-
- $this->indent = strlen($line) - strlen(ltrim($line));
- $tempPath = $this->getParentPathByIndent($this->indent);
- $line = self::stripIndent($line, $this->indent);
- if (self::isComment($line)) {
- continue;
- }
- if (self::isEmpty($line)) {
- continue;
- }
- $this->path = $tempPath;
-
- $literalBlock = '';
- $literalBlockStyle = self::startsLiteralBlock($line);
- if ($literalBlockStyle) {
- $line = rtrim($line, $literalBlockStyle . ' ' . PHP_EOL);
- $literalBlock = '';
- $line .= $this->LiteralPlaceHolder;
-
- while (++$i < $cnt && $this->literalBlockContinues($Source[$i], $this->indent)) {
- $literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle);
- }
- $i--;
- }
-
- while (++$i < $cnt && self::greedilyNeedNextLine($line)) {
- $line = rtrim($line, ' ' . PHP_EOL . "\t" . CR) . ' ' . ltrim($Source[$i], ' ' . "\t");
- }
- $i--;
-
- if (strpos($line, '#')) {
- if (strpos($line, '"') === false && strpos($line, "'") === false) {
- $line = preg_replace('/\\s+#(.+)$/', '', $line);
- }
- }
-
- $lineArray = $this->_parseLine($line);
-
- if ($literalBlockStyle) {
- $lineArray = $this->revertLiteralPlaceHolder($lineArray, $literalBlock);
- }
-
- $this->addArray($lineArray, $this->indent);
-
- foreach ($this->delayedPath as $indent => $delayedPath) {
- $this->path[$indent] = $delayedPath;
- }
-
- $this->delayedPath = [];
- }
- return $this->result;
- }
-
- private function loadFromSource($input)
- {
- if (!empty($input) && strpos($input, PHP_EOL) === false && file_exists($input)) {
- return file($input);
- }
-
- return $this->loadFromString($input);
- }
-
- private function loadFromString($input): array
- {
- $lines = explode(LF, $input);
- foreach ($lines as $k => $_) {
- $lines[$k] = rtrim($_, CR);
- }
- return $lines;
- }
-
- /**
- * Parses YAML code and returns an array for a node
- * @param string $line A line from the YAML file
- * @return array
- */
- private function _parseLine($line)
- {
- if (!$line) {
- return [];
- }
- $line = trim($line);
-
- if (!$line) {
- return [];
- }
- $array = [];
-
- $group = $this->nodeContainsGroup($line);
- if ($group) {
- $this->addGroup($line, $group);
- $line = $this->stripGroup($line, $group);
- }
-
- if ($this->startsMappedSequence($line)) {
- return $this->returnMappedSequence($line);
- }
-
- if ($this->startsMappedValue($line)) {
- return $this->returnMappedValue($line);
- }
-
- if ($this->isArrayElement($line)) {
- return $this->returnArrayElement($line);
- }
-
- if ($this->isPlainArray($line)) {
- return $this->returnPlainArray($line);
- }
-
- return $this->returnKeyValuePair($line);
- }
-
- /**
- * Finds the type of the passed value, returns the value as the new type.
- * @param string $value
- * @return mixed
- */
- private function _toType($value)
- {
- if ($value === '') {
- return null;
- }
- $first_character = $value[0];
- $last_character = substr($value, -1, 1);
-
- $is_quoted = false;
- do {
- if (!$value) {
- break;
- }
- if ($first_character != '"' && $first_character != "'") {
- break;
- }
- if ($last_character != '"' && $last_character != "'") {
- break;
- }
- $is_quoted = true;
- } while (0);
-
- if ($is_quoted) {
- return strtr(substr($value, 1, -1), ['\\"' => '"', '\'\'' => '\'', '\\\'' => '\'']);
- }
-
- if (strpos($value, ' #') !== false) {
- $value = preg_replace('/\\s+#(.+)$/', '', $value);
- }
-
- if ($first_character == '[' && $last_character == ']') {
- // Take out strings sequences and mappings
- $innerValue = trim(substr($value, 1, -1));
- if ($innerValue === '') {
- return [];
- }
- $explode = $this->_inlineEscape($innerValue);
- // Propagate value array
- $value = [];
- foreach ($explode as $v) {
- $value[] = $this->_toType($v);
- }
- return $value;
- }
-
- if (strpos($value, ': ') !== false && $first_character != '{') {
- $array = explode(': ', $value);
- $key = trim($array[0]);
- array_shift($array);
- $value = trim(implode(': ', $array));
- $value = $this->_toType($value);
- return [$key => $value];
- }
-
- if ($first_character == '{' && $last_character == '}') {
- $innerValue = trim(substr($value, 1, -1));
- if ($innerValue === '') {
- return [];
- }
- // Inline Mapping
- // Take out strings sequences and mappings
- $explode = $this->_inlineEscape($innerValue);
- // Propagate value array
- $array = [];
- foreach ($explode as $v) {
- $SubArr = $this->_toType($v);
- if (empty($SubArr)) {
- continue;
- }
- if (is_array($SubArr)) {
- $array[key($SubArr)] = $SubArr[key($SubArr)];
- continue;
- }
- $array[] = $SubArr;
- }
- return $array;
- }
-
- if ($value == 'null' || $value == 'null' || $value == 'Null' || $value == '' || $value == '~') {
- return null;
- }
-
- if ((int)$first_character > 0 && preg_match('/^[1-9]+[0-9]*$/', $value)) {
- $intvalue = (int)$value;
- if ($intvalue != PHP_INT_MAX) {
- $value = $intvalue;
- }
- return $value;
- }
-
- if (in_array(
- $value,
- ['true', 'on', '+', 'yes', 'y', 'True', 'TRUE', 'On', 'ON', 'YES', 'Yes', 'Y']
- )
- ) {
- return true;
- }
-
- if (in_array(
- strtolower($value),
- ['false', 'off', '-', 'no', 'n']
- )
- ) {
- return false;
- }
-
- if (is_numeric($value)) {
- if ($value === '0') {
- return 0;
- }
- if (trim($value, 0) === $value) {
- $value = (float)$value;
- }
- return $value;
- }
-
- return $value;
- }
-
- /**
- * Used in inlines to check for more inlines or quoted strings
- */
- private function _inlineEscape($inline): array
- {
- // There's gotta be a cleaner way to do this...
- // While pure sequences seem to be nesting just fine,
- // pure mappings and mappings with sequences inside can't go very
- // deep. This needs to be fixed.
-
- $seqs = [];
- $maps = [];
- $saved_strings = [];
-
- // Check for strings
- $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/';
- if (preg_match_all($regex, $inline, $strings)) {
- $saved_strings = $strings[0];
- $inline = preg_replace($regex, 'YAMLString', $inline);
- }
- unset($regex);
-
- $i = 0;
- do {
-
- // Check for sequences
- while (preg_match('/\[([^{}\[\]]+)\]/U', $inline, $matchseqs)) {
- $seqs[] = $matchseqs[0];
- $inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1);
- }
-
- // Check for mappings
- while (preg_match('/{([^\[\]{}]+)}/U', $inline, $matchmaps)) {
- $maps[] = $matchmaps[0];
- $inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1);
- }
-
- if ($i++ >= 10) {
- break;
- }
- } while (strpos($inline, '[') !== false || strpos($inline, '{') !== false);
-
- $explode = explode(', ', $inline);
- $stringi = 0;
- $i = 0;
-
- while (1) {
-
- // Re-add the sequences
- if (!empty($seqs)) {
- foreach ($explode as $key => $value) {
- if (strpos($value, 'YAMLSeq') !== false) {
- foreach ($seqs as $seqk => $seq) {
- $explode[$key] = str_replace(('YAMLSeq' . $seqk . 's'), $seq, $value);
- $value = $explode[$key];
- }
- }
- }
- }
-
- // Re-add the mappings
- if (!empty($maps)) {
- foreach ($explode as $key => $value) {
- if (strpos($value, 'YAMLMap') !== false) {
- foreach ($maps as $mapk => $map) {
- $explode[$key] = str_replace(('YAMLMap' . $mapk . 's'), $map, $value);
- $value = $explode[$key];
- }
- }
- }
- }
-
- // Re-add the strings
- if (!empty($saved_strings)) {
- foreach ($explode as $key => $value) {
- while (strpos($value, 'YAMLString') !== false) {
- $explode[$key] = preg_replace('/YAMLString/', $saved_strings[$stringi], $value, 1);
- unset($saved_strings[$stringi]);
- ++$stringi;
- $value = $explode[$key];
- }
- }
- }
-
- $finished = true;
- foreach ($explode as $key => $value) {
- if (strpos($value, 'YAMLSeq') !== false) {
- $finished = false;
- break;
- }
- if (strpos($value, 'YAMLMap') !== false) {
- $finished = false;
- break;
- }
- if (strpos($value, 'YAMLString') !== false) {
- $finished = false;
- break;
- }
- }
- if ($finished) {
- break;
- }
-
- $i++;
- if ($i > 10) {
- break;
- } // Prevent infinite loops.
- }
-
- return $explode;
- }
-
- private function literalBlockContinues($line, $lineIndent): bool
- {
- if (!trim($line)) {
- return true;
- }
- if (strlen($line) - strlen(ltrim($line)) > $lineIndent) {
- return true;
- }
- return false;
- }
-
- private function referenceContentsByAlias($alias)
- {
- $value = null;
-
- do {
- if (!isset($this->SavedGroups[$alias])) {
- echo "Bad group name: $alias.";
- break;
- }
- $groupPath = $this->SavedGroups[$alias];
- $value = $this->result;
- foreach ($groupPath as $k) {
- $value = $value[$k];
- }
- } while (false);
- return $value;
- }
-
- private function addArrayInline($array, $indent): bool
- {
- $CommonGroupPath = $this->path;
- if (empty($array)) {
- return false;
- }
-
- foreach ($array as $k => $_) {
- $this->addArray([$k => $_], $indent);
- $this->path = $CommonGroupPath;
- }
- return true;
- }
-
- private function addArray($incoming_data, $incoming_indent)
- {
-
- // print_r ($incoming_data);
-
- if (count($incoming_data) > 1) {
- return $this->addArrayInline($incoming_data, $incoming_indent);
- }
-
- $key = key($incoming_data);
- $value = isset($incoming_data[$key]) ? $incoming_data[$key] : null;
- if ($key === '__!YAMLZero') {
- $key = '0';
- }
-
- if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values.
- if ($key || $key === '' || $key === '0') {
- $this->result[$key] = $value;
- } else {
- $this->result[] = $value;
- end($this->result);
- $key = key($this->result);
- }
- $this->path[$incoming_indent] = $key;
- return;
- }
-
- $history = [];
- // Unfolding inner array tree.
- $history[] = $_arr = $this->result;
- foreach ($this->path as $k) {
- $history[] = $_arr = $_arr[$k];
- }
-
- if ($this->_containsGroupAlias) {
- $value = $this->referenceContentsByAlias($this->_containsGroupAlias);
- $this->_containsGroupAlias = false;
- }
-
- // Adding string or numeric key to the innermost level or $this->arr.
- if (is_string($key) && $key == '<<') {
- if (!is_array($_arr)) {
- $_arr = [];
- }
-
- $_arr = array_merge($_arr, $value);
- } elseif ($key || $key === '' || $key === '0') {
- if (!is_array($_arr)) {
- $_arr = [];
- }
- $_arr[$key] = $value;
- } else {
- if (!is_array($_arr)) {
- $_arr = [$value];
- $key = 0;
- } else {
- $_arr[] = $value;
- end($_arr);
- $key = key($_arr);
- }
- }
-
- $reverse_path = array_reverse($this->path);
- $reverse_history = array_reverse($history);
- $reverse_history[0] = $_arr;
- $cnt = count($reverse_history) - 1;
- for ($i = 0; $i < $cnt; $i++) {
- $reverse_history[$i + 1][$reverse_path[$i]] = $reverse_history[$i];
- }
- $this->result = $reverse_history[$cnt];
-
- $this->path[$incoming_indent] = $key;
-
- if ($this->_containsGroupAnchor) {
- $this->SavedGroups[$this->_containsGroupAnchor] = $this->path;
- if (is_array($value)) {
- $k = key($value);
- if (!is_int($k)) {
- $this->SavedGroups[$this->_containsGroupAnchor][$incoming_indent + 2] = $k;
- }
- }
- $this->_containsGroupAnchor = false;
- }
- }
-
- private static function startsLiteralBlock($line)
- {
- $lastChar = substr(trim($line), -1);
- if ($lastChar != '>' && $lastChar != '|') {
- return false;
- }
- if ($lastChar == '|') {
- return $lastChar;
- }
- // HTML tags should not be counted as literal blocks.
- if (preg_match('#<.*?>$#', $line)) {
- return false;
- }
- return $lastChar;
- }
-
- private static function greedilyNeedNextLine($line): bool
- {
- $line = trim($line);
- if (!strlen($line)) {
- return false;
- }
- if (substr($line, -1, 1) == ']') {
- return false;
- }
- if ($line[0] == '[') {
- return true;
- }
- if (preg_match('#^[^:]+?:\\s*\\[#', $line)) {
- return true;
- }
- return false;
- }
-
- private function addLiteralLine($literalBlock, $line, $literalBlockStyle): string
- {
- $line = self::stripIndent($line);
- $line = rtrim($line, CRLF . TAB) . PHP_EOL;
- if ($literalBlockStyle == '|') {
- return $literalBlock . $line;
- }
- if (strlen($line) == 0) {
- return rtrim($literalBlock, ' ') . PHP_EOL;
- }
- if ($line == PHP_EOL && $literalBlockStyle == '>') {
- return rtrim($literalBlock, " \t") . PHP_EOL;
- }
- if ($line != PHP_EOL) {
- $line = trim($line, CRLF . ' ') . ' ';
- }
- return $literalBlock . $line;
- }
-
- public function revertLiteralPlaceHolder($lineArray, $literalBlock)
- {
- foreach ($lineArray as $k => $_) {
- if (is_array($_)) {
- $lineArray[$k] = $this->revertLiteralPlaceHolder($_, $literalBlock);
- } elseif (substr($_, -1 * strlen($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder) {
- $lineArray[$k] = rtrim($literalBlock, ' ' . CRLF);
- }
- }
- return $lineArray;
- }
-
- private static function stripIndent($line, $indent = -1): string
- {
- if ($indent == -1) {
- $indent = strlen($line) - strlen(ltrim($line));
- }
- return substr($line, $indent);
- }
-
- private function getParentPathByIndent($indent)
- {
- if ($indent == 0) {
- return [];
- }
- $linePath = $this->path;
- do {
- end($linePath);
- $lastIndentInParentPath = key($linePath);
- if ($indent <= $lastIndentInParentPath) {
- array_pop($linePath);
- }
- } while ($indent <= $lastIndentInParentPath);
- return $linePath;
- }
-
- private function clearBiggerPathValues($indent): bool
- {
- if ($indent == 0) {
- $this->path = [];
- }
- if (empty($this->path)) {
- return true;
- }
-
- foreach ($this->path as $k => $_) {
- if ($k > $indent) {
- unset($this->path[$k]);
- }
- }
-
- return true;
- }
-
- private static function isComment($line): bool
- {
- if (!$line) {
- return false;
- }
- if ($line[0] == '#') {
- return true;
- }
- if (trim($line, ' ' . CRLF . "\t") == '---') {
- return true;
- }
- return false;
- }
-
- private static function isEmpty($line): bool
- {
- return trim($line) === '';
- }
-
- private function isArrayElement($line): bool
- {
- if (!$line) {
- return false;
- }
- if ($line[0] != '-') {
- return false;
- }
- if (strlen($line) > 3) {
- if (substr($line, 0, 3) == '---') {
- return false;
- }
- }
-
- return true;
- }
-
- private function isHashElement($line)
- {
- return strpos($line, ':');
- }
-
- private function isLiteral($line): bool
- {
- if ($this->isArrayElement($line)) {
- return false;
- }
- if ($this->isHashElement($line)) {
- return false;
- }
- return true;
- }
-
- private static function unquote($value)
- {
- if (!$value) {
- return $value;
- }
- if (!is_string($value)) {
- return $value;
- }
- if ($value[0] == '\'') {
- return trim($value, '\'');
- }
- if ($value[0] == '"') {
- return trim($value, '"');
- }
- return $value;
- }
-
- private function startsMappedSequence($line): bool
- {
- return $line[0] == '-' && substr($line, -1, 1) == ':';
- }
-
- private function returnMappedSequence($line): array
- {
- $array = [];
- $key = self::unquote(trim(substr($line, 1, -1)));
- $array[$key] = [];
- $this->delayedPath = [strpos($line, $key) + $this->indent => $key];
- return [$array];
- }
-
- private function returnMappedValue($line): array
- {
- $array = [];
- $key = self::unquote(trim(substr($line, 0, -1)));
- $array[$key] = '';
- return $array;
- }
-
- private function startsMappedValue($line): bool
- {
- return substr($line, -1, 1) == ':';
- }
-
- private function isPlainArray($line): bool
- {
- return $line[0] == '[' && substr($line, -1, 1) == ']';
- }
-
- private function returnPlainArray($line)
- {
- return $this->_toType($line);
- }
-
- private function returnKeyValuePair($line): array
- {
- $array = [];
- $key = '';
- if (strpos($line, ':')) {
- // It's a key/value pair most likely
- // If the key is in double quotes pull it out
- if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\\s)*:)/', $line, $matches)) {
- $value = trim(str_replace($matches[1], '', $line));
- $key = $matches[2];
- } else {
- // Do some guesswork as to the key and the value
- $explode = explode(':', $line);
- $key = trim($explode[0]);
- array_shift($explode);
- $value = trim(implode(':', $explode));
- }
- // Set the type of the value. Int, string, etc
- $value = $this->_toType($value);
- if ($key === '0') {
- $key = '__!YAMLZero';
- }
- $array[$key] = $value;
- } else {
- $array = [$line];
- }
- return $array;
- }
-
- private function returnArrayElement($line): array
- {
- if (strlen($line) <= 1) {
- return [[]];
- } // Weird %)
- $array = [];
- $value = trim(substr($line, 1));
- $value = $this->_toType($value);
- $array[] = $value;
- return $array;
- }
-
- private function nodeContainsGroup($line)
- {
- $symbolsForReference = 'A-z0-9_\-';
- if (strpos($line, '&') === false && strpos($line, '*') === false) {
- return false;
- } // Please die fast ;-)
- if ($line[0] == '&' && preg_match('/^(&[' . $symbolsForReference . ']+)/', $line, $matches)) {
- return $matches[1];
- }
- if ($line[0] == '*' && preg_match('/^(\*[' . $symbolsForReference . ']+)/', $line, $matches)) {
- return $matches[1];
- }
- if (preg_match('/(&[' . $symbolsForReference . ']+)$/', $line, $matches)) {
- return $matches[1];
- }
- if (preg_match('/(\*[' . $symbolsForReference . ']+$)/', $line, $matches)) {
- return $matches[1];
- }
- if (preg_match('#^\\s*<<\\s*:\\s*(\\*[^\\s]+).*$#', $line, $matches)) {
- return $matches[1];
- }
- return false;
- }
-
- private function addGroup($line, $group): void
- {
- if ($group[0] == '&') {
- $this->_containsGroupAnchor = substr($group, 1);
- }
- if ($group[0] == '*') {
- $this->_containsGroupAlias = substr($group, 1);
- }
- }
-
- private function stripGroup($line, $group): string
- {
- $line = trim(str_replace($group, '', $line));
- return $line;
- }
-}
diff --git a/Classes/Utility/Tools.php b/Classes/Utility/Tools.php
index 9e0f727b4..cc91085ac 100644
--- a/Classes/Utility/Tools.php
+++ b/Classes/Utility/Tools.php
@@ -25,14 +25,14 @@ class Tools implements SingletonInterface
{
public static function parseTableNameFromClassName($className): string
{
- if (strpos($className, '\\') !== false) {
- if (strpos($className, '\\') === 0) {
+ if (str_contains((string) $className, '\\')) {
+ if (str_starts_with((string) $className, '\\')) {
// remove trailing slash
- $className = substr($className, 1);
+ $className = substr((string) $className, 1);
}
- $classNameParts = explode('\\', $className, 6);
+ $classNameParts = explode('\\', (string) $className, 6);
} else {
- $classNameParts = explode('_', $className, 6);
+ $classNameParts = explode('_', (string) $className, 6);
}
// could be: TYPO3\CMS\Extbase\Domain\Model\FrontendUser
// or: VENDOR\Extension\Domain\Model\Foo
@@ -44,26 +44,18 @@ public static function parseTableNameFromClassName($className): string
}
/**
- * @param AbstractProperty $domainProperty
* @param string $methodType (set,add,remove)
- *
* @return string method body
*/
public static function getParameterName(AbstractProperty $domainProperty, string $methodType): ?string
{
$propertyName = $domainProperty->getName();
-
- switch ($methodType) {
- case 'set':
- return $propertyName;
-
- case 'add':
- return Inflector::singularize($propertyName);
-
- case 'remove':
- return Inflector::singularize($propertyName) . 'ToRemove';
- }
- return null;
+ return match ($methodType) {
+ 'set' => $propertyName,
+ 'add' => Inflector::singularize($propertyName),
+ 'remove' => Inflector::singularize($propertyName) . 'ToRemove',
+ default => null,
+ };
}
public static function getParamTag(AbstractProperty $domainProperty, string $methodType): ?string
@@ -75,23 +67,19 @@ public static function getParamTag(AbstractProperty $domainProperty, string $met
case 'add':
/** @var AbstractRelation $domainProperty */
$paramTag = $domainProperty->getForeignClassName();
- $paramTag .= ' $' . self::getParameterName($domainProperty, 'add');
- return $paramTag;
+ return $paramTag . (' $' . self::getParameterName($domainProperty, 'add'));
case 'remove':
/** @var AbstractRelation $domainProperty */
$paramTag = $domainProperty->getForeignClassName();
$paramTag .= ' $' . self::getParameterName($domainProperty, 'remove');
- $paramTag .= ' The ' . $domainProperty->getForeignModelName() . ' to be removed';
- return $paramTag;
+ return $paramTag . (' The ' . $domainProperty->getForeignModelName() . ' to be removed');
}
return null;
}
/**
* Build record type from TX_Vendor_Package_Modelname
- * @param string $className
- * @return string
*/
public static function convertClassNameToRecordType(string $className): string
{
diff --git a/Classes/ViewHelpers/DomainObjectChecksViewHelper.php b/Classes/ViewHelpers/DomainObjectChecksViewHelper.php
index f1f07df73..3c7b8f08f 100644
--- a/Classes/ViewHelpers/DomainObjectChecksViewHelper.php
+++ b/Classes/ViewHelpers/DomainObjectChecksViewHelper.php
@@ -25,9 +25,6 @@ class DomainObjectChecksViewHelper extends AbstractConditionViewHelper
{
protected ExtensionBuilderConfigurationManager $configurationManager;
- /**
- * @param ExtensionBuilderConfigurationManager $configurationManager
- */
public function injectExtensionBuilderConfigurationManager(
ExtensionBuilderConfigurationManager $configurationManager
): void {
@@ -59,34 +56,15 @@ public function render()
// table name is only set, if the model is mapped to a table or if the domain object extends a class
$tableName = $domainObject->getMapToTable();
- if ($tableName && strpos($tableName, strtolower($extensionPrefix) . '_domain_model_') === false) {
+ if ($tableName && !str_contains($tableName, strtolower($extensionPrefix) . '_domain_model_')) {
$isMappedToExternalTable = true;
}
-
- switch ($this->arguments['renderCondition']) {
- case 'isMappedToInternalTable':
- if (!$isMappedToExternalTable) {
- return true;
- }
-
- return false;
-
- case 'isMappedToExternalTable':
- if ($isMappedToExternalTable) {
- return true;
- }
-
- return false;
-
- case 'needsTypeField':
- if ($this->needsTypeField($domainObject, $isMappedToExternalTable)) {
- return true;
- }
-
- return false;
- }
-
- return '';
+ return match ($this->arguments['renderCondition']) {
+ 'isMappedToInternalTable' => !$isMappedToExternalTable,
+ 'isMappedToExternalTable' => $isMappedToExternalTable,
+ 'needsTypeField' => $this->needsTypeField($domainObject, $isMappedToExternalTable),
+ default => '',
+ };
}
/**
@@ -98,7 +76,6 @@ public function render()
*
* @param DomainObject $domainObject
* @param bool $isMappedToExternalTable
- * @return bool
*/
protected function needsTypeField(DomainObject $domainObject, bool $isMappedToExternalTable): bool
{
diff --git a/Classes/ViewHelpers/Format/IndentViewHelper.php b/Classes/ViewHelpers/Format/IndentViewHelper.php
index 707fd5359..d9df01816 100644
--- a/Classes/ViewHelpers/Format/IndentViewHelper.php
+++ b/Classes/ViewHelpers/Format/IndentViewHelper.php
@@ -36,7 +36,7 @@ public function initializeArguments(): void
public static function renderStatic(array $arguments, Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
{
$content = $renderChildrenClosure();
- $lineArray = explode(chr(10), $content);
+ $lineArray = explode(chr(10), (string) $content);
$indentString = str_repeat(' ', $arguments['indentation']);
return implode(chr(10) . $indentString, $lineArray);
}
diff --git a/Classes/ViewHelpers/Format/LowercaseFirstViewHelper.php b/Classes/ViewHelpers/Format/LowercaseFirstViewHelper.php
index 6169efa51..848fd2e52 100644
--- a/Classes/ViewHelpers/Format/LowercaseFirstViewHelper.php
+++ b/Classes/ViewHelpers/Format/LowercaseFirstViewHelper.php
@@ -43,6 +43,6 @@ public static function renderStatic(
\Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext
) {
- return lcfirst($renderChildrenClosure());
+ return lcfirst((string) $renderChildrenClosure());
}
}
diff --git a/Classes/ViewHelpers/Format/QuoteStringViewHelper.php b/Classes/ViewHelpers/Format/QuoteStringViewHelper.php
index fdbbf1e70..55e35d36c 100644
--- a/Classes/ViewHelpers/Format/QuoteStringViewHelper.php
+++ b/Classes/ViewHelpers/Format/QuoteStringViewHelper.php
@@ -44,13 +44,14 @@ public static function renderStatic(
\Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext
) {
- return addslashes(self::getValue($arguments, $renderChildrenClosure));
+ return addslashes((string) self::getValue($arguments, $renderChildrenClosure));
}
private static function getValue(
array $arguments,
\Closure $renderChildrenClosure
) {
+ $rguments = [];
if (isset($rguments['value'])) {
return $arguments['value'];
}
diff --git a/Classes/ViewHelpers/Format/RemoveMultipleNewlinesViewHelper.php b/Classes/ViewHelpers/Format/RemoveMultipleNewlinesViewHelper.php
index 474ad4a84..6c7cdbd1e 100644
--- a/Classes/ViewHelpers/Format/RemoveMultipleNewlinesViewHelper.php
+++ b/Classes/ViewHelpers/Format/RemoveMultipleNewlinesViewHelper.php
@@ -33,7 +33,7 @@ public static function renderStatic(
\Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext
) {
- $content = trim($renderChildrenClosure());
+ $content = trim((string) $renderChildrenClosure());
// Collapse whitespace lines
$content = preg_replace('/^\\s+$/m', '', $content);
diff --git a/Classes/ViewHelpers/Format/TrimViewHelper.php b/Classes/ViewHelpers/Format/TrimViewHelper.php
index ca8674c8e..4b32fab06 100644
--- a/Classes/ViewHelpers/Format/TrimViewHelper.php
+++ b/Classes/ViewHelpers/Format/TrimViewHelper.php
@@ -33,6 +33,6 @@ public static function renderStatic(
\Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext
) {
- return trim($renderChildrenClosure());
+ return trim((string) $renderChildrenClosure());
}
}
diff --git a/Classes/ViewHelpers/Format/UppercaseFirstViewHelper.php b/Classes/ViewHelpers/Format/UppercaseFirstViewHelper.php
index c84f94e0e..4cd54cc78 100644
--- a/Classes/ViewHelpers/Format/UppercaseFirstViewHelper.php
+++ b/Classes/ViewHelpers/Format/UppercaseFirstViewHelper.php
@@ -43,6 +43,6 @@ public static function renderStatic(
\Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext
) {
- return ucfirst($renderChildrenClosure());
+ return ucfirst((string) $renderChildrenClosure());
}
}
diff --git a/Classes/ViewHelpers/ListForeignKeyRelationsViewHelper.php b/Classes/ViewHelpers/ListForeignKeyRelationsViewHelper.php
index e7437e28b..108cefc9d 100644
--- a/Classes/ViewHelpers/ListForeignKeyRelationsViewHelper.php
+++ b/Classes/ViewHelpers/ListForeignKeyRelationsViewHelper.php
@@ -37,7 +37,7 @@ public function render(): array
$extension = $expectedDomainObject->getExtension();
$results = [];
foreach ($extension->getDomainObjects() as $domainObject) {
- if (!count($domainObject->getProperties())) {
+ if ((is_countable($domainObject->getProperties()) ? count($domainObject->getProperties()) : 0) === 0) {
continue;
}
foreach ($domainObject->getProperties() as $property) {
diff --git a/Classes/ViewHelpers/MappingViewHelper.php b/Classes/ViewHelpers/MappingViewHelper.php
index 8d8b8574c..d0b28b338 100644
--- a/Classes/ViewHelpers/MappingViewHelper.php
+++ b/Classes/ViewHelpers/MappingViewHelper.php
@@ -25,9 +25,6 @@ class MappingViewHelper extends AbstractConditionViewHelper
{
protected ExtensionBuilderConfigurationManager $configurationManager;
- /**
- * @param ExtensionBuilderConfigurationManager $configurationManager
- */
public function injectExtensionBuilderConfigurationManager(
ExtensionBuilderConfigurationManager $configurationManager
): void {
@@ -59,7 +56,7 @@ public function render()
// table name is only set, if the model is mapped to a table or if the domain object extends a class
$tableName = $domainObject->getMapToTable();
- if ($tableName && strpos($tableName, strtolower($extensionPrefix) . '_domain_model_') === false) {
+ if ($tableName && !str_contains($tableName, strtolower($extensionPrefix) . '_domain_model_')) {
$isMappedToExternalTable = true;
}
@@ -98,7 +95,6 @@ public function render()
*
* @param DomainObject $domainObject
* @param bool $isMappedToExternalTable
- * @return bool
*/
protected function needsTypeField(DomainObject $domainObject, bool $isMappedToExternalTable): bool
{
diff --git a/Classes/ViewHelpers/MatchStringViewHelper.php b/Classes/ViewHelpers/MatchStringViewHelper.php
index dc8c6f769..e63a1131c 100644
--- a/Classes/ViewHelpers/MatchStringViewHelper.php
+++ b/Classes/ViewHelpers/MatchStringViewHelper.php
@@ -51,6 +51,6 @@ public static function renderStatic(
if (!$arguments['caseSensitive']) {
$matchAsRegularExpression .= 'i';
}
- return preg_match($matchAsRegularExpression, $arguments['in']) !== 0;
+ return preg_match($matchAsRegularExpression, (string) $arguments['in']) !== 0;
}
}
diff --git a/Classes/ViewHelpers/PregReplaceViewHelper.php b/Classes/ViewHelpers/PregReplaceViewHelper.php
index 225809044..41e60f586 100644
--- a/Classes/ViewHelpers/PregReplaceViewHelper.php
+++ b/Classes/ViewHelpers/PregReplaceViewHelper.php
@@ -53,6 +53,6 @@ public static function renderStatic(
return '';
}
- return preg_replace($arguments['match'], $arguments['replace'], $subject);
+ return preg_replace($arguments['match'], (string) $arguments['replace'], (string) $subject);
}
}
diff --git a/Classes/ViewHelpers/RecordTypeViewHelper.php b/Classes/ViewHelpers/RecordTypeViewHelper.php
index 2ad23e32f..9901dd5a2 100644
--- a/Classes/ViewHelpers/RecordTypeViewHelper.php
+++ b/Classes/ViewHelpers/RecordTypeViewHelper.php
@@ -17,6 +17,7 @@
namespace EBT\ExtensionBuilder\ViewHelpers;
+use TYPO3\CMS\Extbase\Persistence\Generic\Exception;
use EBT\ExtensionBuilder\Domain\Model\DomainObject;
use EBT\ExtensionBuilder\Utility\Tools;
use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper;
@@ -42,8 +43,7 @@ public function initializeArguments(): void
/**
* Helper function to find the parents class recordType
*
- * @return string
- * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception
+ * @throws Exception
*/
public function render(): string
{
@@ -68,7 +68,7 @@ public function render(): string
}
}
}
- $parts = explode('\\', $domainObject->getParentClass());
+ $parts = explode('\\', (string) $domainObject->getParentClass());
$this->templateVariableContainer->add('parentModelName', end($parts));
$this->templateVariableContainer->add('parentRecordType', $parentRecordType);
$content = $this->renderChildren();
diff --git a/Configuration/Backend/AjaxRoutes.php b/Configuration/Backend/AjaxRoutes.php
index 19d57482e..25a6c83be 100644
--- a/Configuration/Backend/AjaxRoutes.php
+++ b/Configuration/Backend/AjaxRoutes.php
@@ -1,10 +1,19 @@
[
+ 'eb_wiringEditorSmdEndpoint' => [
'path' => '/extensionBuilder/wireEditor',
'target' => ExtensionBuilderConfigurationManager::class . '::getWiringEditorSmd'
],
-];
+ 'eb_dispatchRpcAction' => [
+ 'path' => '/extensionBuilder/dispatchRpcAction',
+ 'target' => BuilderModuleController::class . '::dispatchRpcAction'
+ ],
+ 'eb_ajaxTesting' => [
+ 'path' => '/extensionBuilder/ajaxTesting',
+ 'target' => BuilderModuleController::class . '::ajaxTestingAction'
+ ],
+];
\ No newline at end of file
diff --git a/Configuration/Backend/Modules.php b/Configuration/Backend/Modules.php
new file mode 100644
index 000000000..042d664d6
--- /dev/null
+++ b/Configuration/Backend/Modules.php
@@ -0,0 +1,31 @@
+ [
+ 'parent' => 'tools',
+ 'position' => ['after' => 'tools_ExtensionmanagerExtensionmanager'],
+ 'access' => 'admin',
+ 'workspaces' => 'live',
+ 'iconIdentifier' => 'extensionbuilder-module',
+ 'path' => '/module/tools/extensionBuilder',
+ 'labels' => 'LLL:EXT:extension_builder/Resources/Private/Language/locallang_mod.xlf',
+ 'extensionName' => 'ExtensionBuilder',
+ 'controllerActions' => [
+ BuilderModuleController::class => [
+ 'domainmodelling',
+ 'index',
+ 'help',
+ 'dispatchRpc'
+ ],
+ ],
+ 'routeOptions' => [
+ 'sudoMode' => [
+ 'group' => 'systemMaintainer',
+ 'lifetime' => AccessLifetime::veryShort,
+ ],
+ ],
+ ],
+];
diff --git a/Configuration/Icons.php b/Configuration/Icons.php
new file mode 100644
index 000000000..ab8a80d7d
--- /dev/null
+++ b/Configuration/Icons.php
@@ -0,0 +1,10 @@
+ [
+ 'provider' => SvgIconProvider::class,
+ 'source' => 'EXT:extension_builder/Resources/Public/Icons/Extension.svg',
+ ],
+];
diff --git a/Configuration/JavaScriptModules.php b/Configuration/JavaScriptModules.php
new file mode 100644
index 000000000..d4bc31a4e
--- /dev/null
+++ b/Configuration/JavaScriptModules.php
@@ -0,0 +1,21 @@
+ ['core', 'backend'],
+ 'imports' => [
+ '@friendsoftypo3/extension-builder/' => 'EXT:extension_builder/Resources/Public/JavaScript/',
+ ],
+];
diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml
index fa67ef369..ff4a45eaa 100644
--- a/Configuration/Services.yaml
+++ b/Configuration/Services.yaml
@@ -12,3 +12,10 @@ services:
EBT\ExtensionBuilder\Service\Printer:
public: true
+
+ EBT\ExtensionBuilder\Command\MigrateExtensionCommand:
+ tags:
+ - name: 'console.command'
+ command: 'extension-builder:migrate-extension'
+ description: 'Reads older extensions and rewrite the ExtensionBuilder.json file to match the current TYPO3 version'
+ schedulable: false
diff --git a/Documentation/ChangeLog/12-0-0.rst b/Documentation/ChangeLog/12-0-0.rst
new file mode 100644
index 000000000..d7e7b5dd3
--- /dev/null
+++ b/Documentation/ChangeLog/12-0-0.rst
@@ -0,0 +1,87 @@
+.. include:: /Includes.rst.txt
+.. _changelog:
+
+==============
+Version 12.0.0
+==============
+
+Superfluous dashes in the settings.yaml
+^^^^^^^^^^
+
+Because of some important changes it could be necessary to update your :file:`EXT:my_extension/Configuration/ExtensionBuilder/settings.yaml` file manually.
+
+Please remove the dashes, as they could cause some problems while saving the extension.
+
+.. code-block:: yaml
+ :caption: EXT:my_extension/Configuration/ExtensionBuilder/settings.yaml
+ :emphasize-lines: 8
+
+ #
+ # Extension Builder settings for extension my_extension
+ # generated 2024-01-01 12:00:00
+ #
+ # See http://www.yaml.org/spec/1.2/spec.html
+ #
+
+ ---
+
+ ############# Overwrite settings ###########
+ #
+ # These settings only apply, if the roundtrip feature of the extension builder
+ # is enabled in the extension manager
+
+.. note::
+
+ We haven't implemented an Upgrade wizard for this. This might change in the future. Feel free to open an Pull-Request on `GitHub `__ for this.
+
+.. versionchanged:: v12.0.0-beta.3
+
+ Converting propertyIsExcludeField to excludeField
+ ^^^^^^^^^^
+
+ If you used a version prior to v12.0.0-beta.3, you might need to change the property `propertyIsExcludeField` to `excludeField` in your TCA ExtensionBuilder.json file manually.
+
+Converting propertyIsExcludeField to excludeField
+^^^^^^^^^^
+
+If you used a version prior to `v12.0.0-beta.3`, you might need to change the property `propertyIsExcludeField` for relations to `excludeField` in your TCA ExtensionBuilder.json file manually.
+
+Example:
+
+.. code-block:: json
+ :caption: EXT:your_ext/Configuration/ExtensionBuilder/settings.yaml
+
+.. code-block:: json
+ :caption: from:
+
+ {
+ "nodes": [
+ {
+ "data": {
+ "relations": [
+ {
+ "propertyIsExcludeField": true
+ }
+ ]
+ }
+ }
+ ]
+ }
+
+.. code-block:: json
+ :caption: to:
+
+ {
+ "nodes": [
+ {
+ "data": {
+ "relations": [
+ {
+ "excludeField": true
+ }
+ ]
+ }
+ }
+ ]
+ }
+
diff --git a/Documentation/ChangeLog/Index.rst b/Documentation/ChangeLog/Index.rst
index 9f6d26a2f..c0458db46 100644
--- a/Documentation/ChangeLog/Index.rst
+++ b/Documentation/ChangeLog/Index.rst
@@ -1,11 +1,30 @@
.. include:: /Includes.rst.txt
-
.. _changelog:
==========
Change log
==========
+Important release notes
+=======================
+
+.. toctree::
+ :maxdepth: 1
+ :titlesonly:
+ :glob:
+
+ 12-0-0
+
+Version 12.0.0
+--------------
+* [TASK] Rework the whole JS GUI of this extension
+* [TASK] Raise new versions for new TYPO3 12 release
+* [TASK] Drop support for TYPO3 11, add support for TYPO3 12
+* [TASK] Drop support for PHP 7.x, add support for PHP 8.1 and 8.2
+* [TASK] Register each plugin as its own CType
+* [DOCS] Update the documentation
+* [TASK] Removed generation of Tests for the extensions
+
Version 11.0.13
---------------
* [DOCS] Adds information about a possible missing storage path when using composer mode
@@ -40,6 +59,18 @@ Version 11.0.8
* [TASK] Set the description field of backend module to textarea
* [BUGFIX] Fix issue in JS - "Relations"
+Version 11.0.7
+--------------
+* Fix release number inside ext_emconf.php
+
+Version 11.0.6
+--------------
+* [BUGFIX] Revert deletion inside composer.json
+
+Version 11.0.5
+--------------
+* [BUGFIX] revert deletion of code templates
+
Version 11.0.4
--------------
* [BUGFIX] Fix warning if setDefaultValuesForClassProperties does not exist
@@ -67,3 +98,12 @@ Version 11.0.2
* [TASK] Align with new TYPO3 documentation standards
* [TASK] Align with new TYPO3 documentation standards (follow-up)
* [BUGFIX] Fix PHP8 warning because overwriteSettings not found in empty settings
+
+Version 11.0.1
+--------------
+* Small bugfixes
+* Several improvements inside documentation
+* [TASK] Switch extension stability from "beta" to "stable"
+* [TASK] Remove suffix from generated folder Documentation.tmpl
+* [TASK] Remove plugin type
+* [TASK] Adapt public resources url for acceptance tests
diff --git a/Documentation/Configuration/Index.rst b/Documentation/Configuration/Index.rst
index 2510019ca..0e44c6bef 100644
--- a/Documentation/Configuration/Index.rst
+++ b/Documentation/Configuration/Index.rst
@@ -1,5 +1,4 @@
.. include:: /Includes.rst.txt
-
.. _configuration:
=============
@@ -29,23 +28,31 @@ In the TYPO3 backend go to :guilabel:`Settings > Extension Configuration` and
open the configuration of the Extension Builder. Here are several settings
configurable:
-+----------------------------+-------------------------------------------------------------------------------+------------------------------------+
-|**Setting** |**Description** |**Default** |
-+----------------------------+-------------------------------------------------------------------------------+------------------------------------+
-|Enable roundtrip mode |If you enable the *roundtrip mode*, you can modify the generated files and |true |
-| |your changes will be preserved even if you customize the extension again in | |
-| |the Extension Builder. For more information on the roundtrip mode, see the | |
-| |page ":doc:`/InDepth/Roundtrip`". | |
-| | | |
-| |If you disable it (*kickstart mode*), all files are regenerated every time you | |
-| |save in the Extension Builder. | |
-+----------------------------+-------------------------------------------------------------------------------+------------------------------------+
-|Backup on save |The Extension Builder creates a backup of the extension every time it is saved |true |
-| |if this option is set to true. | |
-+----------------------------+-------------------------------------------------------------------------------+------------------------------------+
-|Backup directory |The directory where the Extension Builder stores the backup – |var/tx_extensionbuilder/backups |
-| |specified as an absolute path or relative to ``PATH_site``. | |
-+----------------------------+-------------------------------------------------------------------------------+------------------------------------+
+.. confval:: Enable roundtrip mode
+
+ :type: boolean
+ :Default: true
+ :Path: basic.enableRoundtrip
+
+ If you enable the *roundtrip mode*, you can modify the generated files and your changes will be preserved even if you customize the extension again in the Extension Builder. For more information on the roundtrip mode, see the page :doc:`/InDepth/Roundtrip`.
+
+ If you disable it (*kickstart mode*), all files are regenerated every time you save in the Extension Builder.
+
+.. confval:: Backup on save
+
+ :type: boolean
+ :Default: true
+ :Path: basic.backupExtension
+
+ The Extension Builder creates a backup of the extension every time it is saved if this option is set to true.
+
+.. confval:: Backup directory
+
+ :type: string
+ :Default: `var/tx_extensionbuilder/backups`
+ :Path: basic.backupDir
+
+ The directory where the Extension Builder stores the backup – specified as an absolute path or relative to ``PATH_site``.
.. _local-configuration:
@@ -69,21 +76,29 @@ Overwrite settings
The nesting reflects the file structure and a setting applies recursively to all
files and subfolders of a file path.
-+----------------------------+-------------------------------------------------------------------------------+
-|**Setting** |**Description** |
-+----------------------------+-------------------------------------------------------------------------------+
-|merge |All properties, methods and method bodies of class files are modified |
-| |and not overwritten. |
-| | |
-| |Existing keys and identifiers in language files are preserved. |
-| | |
-| |In any other file you will find a split token at the end of the file. |
-| |The part before this token is overwritten, the part after is preserved. |
-+----------------------------+-------------------------------------------------------------------------------+
-|keep |These files are never overwritten.\* |
-+----------------------------+-------------------------------------------------------------------------------+
-|skip |These files are not created.\* |
-+----------------------------+-------------------------------------------------------------------------------+
+.. t3-field-list-table::
+ :header-rows: 1
+
+ - :Setting:
+ Setting:
+ :Description:
+ Description:
+ - :Setting:
+ merge
+ :Description:
+ All properties, methods and method bodies of class files are modified and not overwritten.
+
+ Existing keys and identifiers in language files are preserved.
+
+ In any other file you will find a split token at the end of the file. The part before this token is overwritten, the part after is preserved.
+ - :Setting:
+ keep
+ :Description:
+ These files are never overwritten.\*
+ - :Setting:
+ skip
+ :Description:
+ These files are not created.\*
.. warning::
@@ -130,18 +145,23 @@ The nesting reflects the class hierarchy and is restricted to the classes
with these options available:
-+------------------------------------+-------------------------------------------------------------------------------+
-|**Setting** |**Description** |
-+------------------------------------+-------------------------------------------------------------------------------+
-|parentClass |The fully qualified class name of the class to inherit from. |
-+------------------------------------+-------------------------------------------------------------------------------+
-|setDefaultValuesForClassProperties |By default, the class builder initializes class properties with the default |
-| |value of their type, for example integer types with 0, string types with "", |
-| |etc. |
-| |Set this option to false if class properties should not be initialized, |
-| |for example if you want to distinguish whether a property is not yet set |
-| |or has been explicitly set to the default value. |
-+------------------------------------+-------------------------------------------------------------------------------+
+.. t3-field-list-table::
+ :header-rows: 1
+
+ - :Setting:
+ Setting:
+ :Description:
+ Description:
+ - :Setting:
+ parentClass
+ :Description:
+ The fully qualified class name of the class to inherit from.
+ - :Setting:
+ setDefaultValuesForClassProperties
+ :Description:
+ By default, the class builder initializes class properties with the default value of their type, for example integer types with 0, string types with "", etc.
+
+ Set this option to false if class properties should not be initialized, for example if you want to distinguish whether a property is not yet set or has been explicitly set to the default value.
This is an example of the :file:`settings.yaml` file:
@@ -171,25 +191,21 @@ Miscellaneous
There are more options both for the timestamps of the language files and for
working with the Extension Builder itself.
-+----------------------------+-------------------------------------------------------------------------------+
-|**Setting** |**Description** |
-+----------------------------+-------------------------------------------------------------------------------+
-|staticDateInXliffFiles |By default, the date attribute in language files is updated every time you |
-| |save in the Extension Builder. |
-| |This can be confusing in a version control system if all language files are |
-| |marked as changed even if no labels have been added or changed. |
-| |To prevent this effect, you can set a static date – |
-| |although this is not recommended because the modification date can be useful |
-| |in the translation context. |
-+----------------------------+-------------------------------------------------------------------------------+
-|ignoreWarnings |Some modeling configurations result in warnings. |
-| |For example, if you configure a show action as a default action, you are |
-| |warned that you need to define a parameter of a domain object to be shown. |
-| |However, there may be use cases where you want to ignore the warning and thus |
-| |prevent it from appearing every time you save. Add the warning code that will |
-| |be displayed with the warning to the list of this setting. Each code should be |
-| |listed on its own line and indented by 2 spaces. |
-+----------------------------+-------------------------------------------------------------------------------+
+.. t3-field-list-table::
+ :header-rows: 1
+
+ - :Setting:
+ Setting:
+ :Description:
+ Description:
+ - :Setting:
+ staticDateInXliffFiles
+ :Description:
+ By default, the date attribute in language files is updated every time you save in the Extension Builder. This can be confusing in a version control system if all language files are marked as changed even if no labels have been added or changed. To prevent this effect, you can set a static date – although this is not recommended because the modification date can be useful in the translation context.
+ - :Setting:
+ ignoreWarnings
+ :Description:
+ Some modeling configurations result in warnings. For example, if you configure a show action as a default action, you are warned that you need to define a parameter of a domain object to be shown. However, there may be use cases where you want to ignore the warning and thus prevent it from appearing every time you save. Add the warning code that will be displayed with the warning to the list of this setting. Each code should be listed on its own line and indented by 2 spaces.
This is an example of the :file:`settings.yaml` file:
diff --git a/Documentation/Contribution/Index.rst b/Documentation/Contribution/Index.rst
index 5bf0aaceb..55764cdc5 100644
--- a/Documentation/Contribution/Index.rst
+++ b/Documentation/Contribution/Index.rst
@@ -1,5 +1,4 @@
.. include:: /Includes.rst.txt
-
.. _contribution:
============
diff --git a/Documentation/Development/Index.rst b/Documentation/Development/Index.rst
index b99c2cb18..c116b581b 100644
--- a/Documentation/Development/Index.rst
+++ b/Documentation/Development/Index.rst
@@ -1,5 +1,4 @@
.. include:: /Includes.rst.txt
-
.. _development:
===========
@@ -9,6 +8,11 @@ Development
If you want to participate in the development of the Extension Builder, set up
your local development environment as usual.
+.. hint::
+
+ This section is not completely finished. You also need some npm commands for
+ compiling the React JS app. This will be added in the future.
+
Compile SCSS
============
@@ -22,3 +26,10 @@ but npm also works. In this case, simply replace :bash:`yarn` with :bash:`npm`.
yarn build-css
– *The TYPO3 project - Inspiring people to share*
+
+DDEV environment
+================
+
+We are planning to also include a DDEV environment for the Extension Builder which helps you to get started with the development of the Extension Builder. This will be added soon.
+
+
diff --git a/Documentation/GeneratedExtension/Index.rst b/Documentation/GeneratedExtension/Index.rst
index 8cb16438d..deae6b44e 100644
--- a/Documentation/GeneratedExtension/Index.rst
+++ b/Documentation/GeneratedExtension/Index.rst
@@ -1,5 +1,4 @@
.. include:: /Includes.rst.txt
-
.. _generated-extension:
===================
@@ -26,6 +25,7 @@ previous chapter:
└── Repository/..
├── Configuration/
├── ExtensionBuilder/..
+ ├── FlexForms/..
├── TCA/..
└── TypoScript/..
├── Documentation/..
@@ -37,10 +37,6 @@ previous chapter:
└── Templates/..
└── Public/
└── Icons/..
- └── Tests/
- ├── Functional/..
- └── Unit/..
-
It is explained in more detail in the following sections:
.. contents::
@@ -116,9 +112,6 @@ frontend plugins and backend modules:
└── Templates/..
└── Public/
└── Icons/..
- └── Tests/
- ├── Functional/..
- └── Unit/..
The frontend plugins are registered in the :file:`ext_localconf.php` file and
the backend modules are registered in the :file:`ext_tables.php` file.
@@ -141,6 +134,23 @@ the official TYPO3 documentation.
.. _documentation:
+FlexForms for Plugins
+=====================
+The Extension Builder generates a FlexForm for each plugin. The FlexForm is
+configured in the :file:`Configuration/FlexForms/` folder and is used to
+configure the plugin in the TYPO3 backend. The FlexForm is a XML file that
+defines the fields and their properties. The FlexForm is used to configure the
+plugin in the TYPO3 backend.
+
+The FlexForm is only created at the first time the plugin is created. If you
+change the plugin configuration in the Extension Builder, the FlexForm is not
+updated. You have to delete the FlexForm manually and then create the plugin
+again.
+
+.. admonition::
+ The generated FlexForm only contains one example field. You can add more fields
+ to the FlexForm by editing the XML file.
+
Documentation
=============
@@ -204,6 +214,11 @@ rendered documentation - including, of course, putting it under version control.
Tests
=====
+.. versionchanged:: 12.0.0
+ The extension_builder does not generate tests for the extension anymore.
+
+ Since the tests were a little bit confusing for the users, we decided to remove them from the generated extension. We recommend to write tests for your extension by yourself.
+
The TYPO3 Core is covered by thousands of tests of varying complexity:
Unit tests (testing part of a class), functional tests (testing multiple classes
in combination) and acceptance tests (testing the entire website user
@@ -211,105 +226,8 @@ experience). To simplify testing, the general functionality for writing tests is
bundled in the `TYPO3 Testing Framework `__,
and all custom tests should use it by inheriting from its base classes.
-The Extension Builder generates a set of unit tests and a dummy functional test
-that easily cover the generated classes of your extension. The generated tests
-should encourage you to write your own tests once you start customizing the
-code.
-
If you are new to testing, we recommend that you invest
some time to learn the benefits of software testing. It will certainly improve
the quality of your software, but it will also boost your programming skills.
Moreover, it will allow you to refactor without fear of breaking anything:
Code that is covered by tests shows less unexpected behavior after refactoring.
-
-.. _covered-classes-and-methods:
-
-Covered classes and methods
----------------------------
-
-The Extension Builder generates unit tests for the public API of
-
-1. domain objects and
-2. default controller actions.
-
-.. _covered-domain-object-methods:
-
-Covered domain object methods
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The covered methods of domain object classes match the patterns
-
-* get*()
-* set*()
-* add*()
-* remove*().
-
-For example:
-
-.. code-block:: php
-
- /**
- * @test
- */
- public function setTitleForStringSetsTitle(): void
- {
- $this->subject->setTitle('Conceived at T3CON10');
-
- self::assertEquals('Conceived at T3CON10', $this->subject->_get('title'));
- }
-
-All types of properties are covered, for example integers, strings, file
-references or relations to other domain objects.
-
-.. _covered-controller-actions:
-
-Covered controller actions
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The covered controller actions match the names
-
-* listAction()
-* showAction()
-* newAction()
-* createAction()
-* editAction()
-* updateAction()
-* deleteAction()
-
-and test the following behavior:
-
-* asserting data in the action is assigned to the view and
-* asserting the action delegates data modifications to a repository,
- like adding, updating, removing or fetching objects.
-
-For example:
-
-.. code-block:: php
-
- /**
- * @test
- */
- public function deleteActionRemovesTheGivenBlogFromBlogRepository(): void
- {
- $blog = new \Ebt\EbtBlog\Domain\Model\Blog();
-
- $blogRepository = $this->getMockBuilder(\Ebt\EbtBlog\Domain\Repository\BlogRepository::class)
- ->onlyMethods(['remove'])
- ->disableOriginalConstructor()
- ->getMock();
-
- $blogRepository->expects(self::once())->method('remove')->with($blog);
- $this->subject->_set('blogRepository', $blogRepository);
-
- $this->subject->deleteAction($blog);
- }
-
-.. _running-tests:
-
-Running tests
--------------
-
-Unit tests of your extension can be executed in the TYPO3 backend using the
-`phpunit `__ extension or on the
-command line by following the :doc:`testing pages `
-of the official TYPO3 documentation.
diff --git a/Documentation/GraphicalEditor/BackendModules/Index.rst b/Documentation/GraphicalEditor/BackendModules/Index.rst
new file mode 100644
index 000000000..3dcc18214
--- /dev/null
+++ b/Documentation/GraphicalEditor/BackendModules/Index.rst
@@ -0,0 +1,69 @@
+.. include:: /Includes.rst.txt
+.. _backend-modules:
+
+=======================
+Create a backend module
+=======================
+
+If your extension should provide a TYPO3 backend module,
+add a module in the :guilabel:`Backend modules` subsection of the properties form.
+It will then be available in the module menu on the left side of the TYPO3
+backend.
+
+.. t3-field-list-table::
+ :header-rows: 0
+
+ - :Field:
+ **Name**
+ :Description:
+ The module name can be any string. It is currently used only internally in the Extension Builder, for example in validation results. An example is "EBT Blogs".
+ - :Field:
+ **Key**
+ :Description:
+ The module key must be a lowercase, alphanumeric string. It is used to identify the module of your extension. An example is "ebtblogs".
+ - :Field:
+ **Description**
+ :Description:
+ The module description can be any text. It is displayed in the *About* module of the TYPO3 backend.
+ - :Field:
+ **Tab label**
+ :Description:
+ The module name in the TYPO3 module menu can be any string.
+ - :Field:
+ **Main module**
+ :Description:
+ This is the module key of the section in the TYPO3 module menu to which the module is assigned. For example, "web" or "site".
+
+ The following module locations are available:
+
+ - :guilabel:`web`
+ A pagetree will be rendered beside the module.
+ - :guilabel:`file`
+ A filetree will be rendered beside the module.
+ - :guilabel:`site`
+ Neither a pagetree, nor a filetree will be rendered beside the module.
+ - :guilabel:`system`
+ The module will be accessible from the system settings and **therefore only be available for system-administrators**.
+ - :guilabel:`tools`
+ Neither a pagetree, nor a filetree will be rendered beside the module.
+ - :guilabel:`user`
+ The module will be accessible from the user settings.
+ - :guilabel:`help`
+ The module will be accessible from the help menu.
+ - :Field:
+ **Controller action combinations**
+ :Description:
+ In each line all actions of a controller supported by this module are listed by `` => ,,...``. The first action of the first line is the default action. Actions are defined in the related aggregate root object, and the controller name corresponds to the object name.
+
+ An example is
+
+ .. code-block:: none
+
+ Blog => list,show,new,create,edit,update,delete,duplicate
+ Author => list,show,new,create,edit,update,delete
+
+.. figure:: /Images/AutomaticScreenshots/BackendModule.png
+ :alt: Backend module
+ :width: 250px
+
+ The backend modules
diff --git a/Documentation/GraphicalEditor/ContinueDeveloping/Index.rst b/Documentation/GraphicalEditor/ContinueDeveloping/Index.rst
new file mode 100644
index 000000000..021ed0647
--- /dev/null
+++ b/Documentation/GraphicalEditor/ContinueDeveloping/Index.rst
@@ -0,0 +1,14 @@
+.. include:: /Includes.rst.txt
+.. _continue-developing:
+
+===================
+Continue developing
+===================
+
+Now you can start modifying the generated files in your IDE. If you still want
+to be able to modify the domain model in the graphical editor you have to make
+sure that the *roundtrip mode* is activated in the
+:doc:`configuration `, before loading the extension in the
+Extension Builder again.
+
+.. include:: /Images/AutomaticScreenshots/GraphicalEditorBlogExampleFullPage.rst.txt
diff --git a/Documentation/GraphicalEditor/DomainObject/Index.rst b/Documentation/GraphicalEditor/DomainObject/Index.rst
new file mode 100644
index 000000000..6798a8585
--- /dev/null
+++ b/Documentation/GraphicalEditor/DomainObject/Index.rst
@@ -0,0 +1,213 @@
+.. include:: /Includes.rst.txt
+.. _domain-object:
+
+======================
+Create a domain object
+======================
+
+If you want to extend the extension skeleton to implement business logic, create
+at least one domain object by dragging the gray :guilabel:`New Model Object` tile onto
+the canvas.
+Give it a meaningful name, which must be an UpperCamelCase, alphanumeric string,
+for example "Blog".
+
+3.a. Edit domain object settings
+--------------------------------
+
+Edit the general settings of the domain object by opening the
+:guilabel:`Domain object settings` subsection.
+
+
+.. confval:: Is aggregate root?
+
+ Check this option if this domain object combines other objects into an aggregate. Objects outside the aggregate may contain references to this root object, but not to other objects in the aggregate. The aggregate root checks the consistency of changes in the aggregate. An example is a blog object that has a related post object that can only be accessed through the blog object with ``$blog->getPosts()``.
+
+ Checking this option in the Extension Builder means that a controller class is generated for this object, whose actions can be defined in the following :guilabel:`Default actions` subsection. Additionally, a repository class is generated that allows to retrieve all instances of this domain object from the persistence layer, i.e. in most scenarios from the database.
+
+.. confval:: Description
+ :name: domain-object-description
+
+ The domain object description can be any text. It is used in the PHPDoc comment of its class
+
+.. confval:: Object type
+
+ Select whether the domain object is an *entity* or a *value object*.
+
+ An entity is identified by a unique identifier and its properties usually change during the application run. An example is a customer whose name, address, email, etc. may change, but can always be identified by the customer ID.
+
+ A value object is identified by its property values and is usually used as a more complex entity property. An example is an address that is identified by its street, house number, city and postal code and would no longer be the same address if any of its values changed.
+
+ .. note::
+
+ **Note**: As of TYPO3 v11, it is recommended to specify any domain object of type "entity" due to the implementation details of Extbase. However, this might change in upcoming TYPO3 versions.
+
+.. confval:: Map to existing table
+
+ Instead of creating a new database table for the domain object, you can let it use an existing table. This can be useful if there is no domain object class using this table yet. Enter the appropriate table name in this field. Each object property will be assigned to an existing table field if both names match, otherwise the table field will be created. This check takes into account that the property name is a lowerCamelCase and the table field name is a lowercase, underscored string, for example the ``firstName`` property matches the ``first_name`` field. For more information on this topic, see the page :doc:`/InDepth/ExtendingDomainObjects`.
+
+ An example is "tt_address". .
+
+.. confval:: Extend existing model class
+
+ Extbase supports *single table inheritance*, which means that a domain object class can inherit from another domain object class and instances of both are persisted in the same database table, optionally using only a subset of the table fields. The class to inherit from must be specified as a fully qualified class name and must exist in the current TYPO3 instance.
+
+ Each object property will be assigned to an existing table field if both names match, otherwise the table field will be newly created. Additionally, a table field :sql:`tx_extbase_type` is created to specify the domain object class stored in this table row. For more information on this topic, see the :doc:`/InDepth/ExtendingDomainObjects` page.
+
+ An example is "\\TYPO3\\CMS\\Extbase\\Domain\\Model\\Category".
+
+.. figure:: /Images/AutomaticScreenshots/DomainObjectSettings.png
+ :alt: Domain object settings
+ :width: 250px
+
+ Domain object settings
+
+3.b. Add actions
+----------------
+
+If the domain object is an aggregate root, open the :guilabel:`Default actions` section
+and select the actions you need and add custom actions if required.
+All selected actions are made available in the controller class that is created
+along with the domain object class, and a Fluid template with an appropriate name is
+generated for each action.
+
+.. figure:: /Images/AutomaticScreenshots/Actions.png
+ :alt: Default actions
+ :width: 250px
+
+ The associated controller actions
+
+
+3.c. Add properties
+-------------------
+
+Expand the :guilabel:`properties` subsection to add domain object properties:
+
+.. t3-field-list-table::
+ :header-rows: 0
+
+ - :Field:
+ **Property name**
+ :Description:
+ The property name must be a lowerCamelCase, alphanumeric string. It is used
+
+ - in language files and domain object classes as ```` and
+ - in the database table as ````.
+
+ An example is "firstName".
+ - :Field:
+ **Property type**
+ :Description:
+ Select the type of the property. This determines the field type in the database table, the TCA type for TYPO3 backend rendering, and the Fluid type for TYPO3 frontend rendering.
+
+ .. note::
+
+ As of TYPO3 v11, the types marked with an asterisk (\*) are not fully implemented for frontend rendering for various reasons. For example, the frontend handling of the types "file" and "image" is not yet implemented, because an implementation in Extbase is missing. For these, many implementation examples can be found on the Internet.
+ - :Field:
+ **Description**
+ (advanced options)
+ :Description:
+ The property description can be any text. It is displayed in the *List* module of the TYPO3 backend as context sensitive help when you click on the property field.
+ - :Field:
+ **Is required?**
+ (advanced options)
+ :Description:
+ Enable this option if this property must be set in TYPO3 frontend. Required properties are provided with a :php:`@TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")` PHPDoc annotation in the domain object class.
+ - :Field:
+ **Is exclude field?**
+ (advanced options)
+ :Description:
+ Enable this option if you want to be able to hide this property from non-administrators in the TYPO3 backend.
+
+.. figure:: /Images/AutomaticScreenshots/ObjectProperties.png
+ :alt: Object properties
+ :width: 250px
+
+ The domain object properties
+
+3.d. Add relations
+------------------
+
+If you create multiple domain objects you may want to connect them by relations.
+A relation property can be added in the :guilabel:`relations` subsection.
+When being added, it can be connected to the related object by dragging the
+round connector of the relation property and dropping it at the connector of the
+related object. When expanding the relation property panel you can refine the
+type of relation.
+
+.. t3-field-list-table::
+ :header-rows: 0
+
+ - :Field:
+ **Name**
+ :Description:
+ The relation property name must be a lowerCamelCase, alphanumeric string. It is used like an ordinary property.
+ - :Field:
+ **Type**
+ :Description:
+ These relation types are available:
+
+ **one-to-one (1:1)**
+
+ This relation property can be associated with a specific instance of the related domain object and that instance has no other relation. An example is a person who has only one account and this account is not used by any other person.
+
+ This setting results in a side-by-side selection field with a maximum of 1 selected item in the TYPO3 backend.
+
+ **one-to-many (1:n)**
+
+ This relation property can be associated with multiple instances of the related domain object, but each of those instances has no other relation. An example is a blog with multiple posts, but each post belongs to only one blog.
+
+ See *Render type* description for more details on the rendering of the property in the TYPO3 backend.
+
+ **many-to-one (n:1)**
+
+ This relation property can be associated with a specific instance of the related domain object, but that instance can have multiple relations. An example is when each person has a specific birthplace, but many people can have the same birthplace.
+
+ This is represented in the TYPO3 backend as a side-by-side selection field with a maximum number of 1 selected item.
+
+ **many-to-many (m:n)**
+
+ This relation property can be associated with multiple instances of the related domain object, and each of these instances can also have multiple relations. An example is when a book may have multiple authors and each author has written multiple books.
+
+ See *Render type* description for more details on the rendering of the property in the TYPO3 backend.
+
+ .. note::
+
+ **Note**: For the many-to-many relation to work properly, you must perform two additional tasks:
+
+ 1. Add a many-to-many relation property in the related domain object as well and connect it to this object.
+ 2. Match the database table name in the :ref:`MM property ` of the TCA files of both domain objects in the generated extension. If this is not the case, the relations of one object are stored in a different database table than the relations of the related object.
+ - :Field:
+ **Render type**
+ :Description:
+ This option is only available for the one-to-many and many-to-many relations and defines the display of the relation property field in the TYPO3 backend:
+
+ **one-to-many (1:n)**
+
+ This can be rendered either as a :doc:`side-by-side selection box ` or as an :doc:`inline-relational-record-editing field `.
+
+ **many-to-many (m:n)**
+
+ This can be represented as either a :doc:`side-by-side selection box `, a :doc:`multi-select checkbox `, or a :doc:`multi-select selection box `.
+ - :Field:
+ **Description**
+ :Description:
+ The relation description can be any text. It is displayed in the *List* module of the TYPO3 backend as context sensitive help when you click on the relation property field.
+ - :Field:
+ **Is exclude field?**
+ (advanced options)
+ :Description:
+ Enable this option if you want to be able to hide this relation property from non-administrators in the TYPO3 backend.
+ - :Field:
+ **Lazy loading**
+ (advanced options)
+ :Description:
+ Should the related instances be loaded when an instance of this domain is created (*eager loading*) or on demand (*lazy loading*). Lazy loading relation properties are provided with a :php:`@TYPO3\CMS\Extbase\Annotation\ORM\Lazy` PHPDoc annotation in the domain object class.
+
+.. figure:: /Images/AutomaticScreenshots/ObjectRelations.png
+ :alt: Object relations
+ :width: 250px
+
+ The domain object relations
+
+
+
diff --git a/Documentation/GraphicalEditor/FrontendPlugins/Index.rst b/Documentation/GraphicalEditor/FrontendPlugins/Index.rst
new file mode 100644
index 000000000..7480ea7ca
--- /dev/null
+++ b/Documentation/GraphicalEditor/FrontendPlugins/Index.rst
@@ -0,0 +1,56 @@
+.. include:: /Includes.rst.txt
+.. _frontend-plugins:
+
+=========================
+Crreate a frontend plugin
+=========================
+
+If you want to create an extension that generates output in the TYPO3 frontend,
+add a plugin in the :guilabel:`Frontend plugins` subsection of the properties form.
+It will then be available for selection in the type field of the
+TYPO3 content element "General Plugin".
+
+.. t3-field-list-table::
+ :header-rows: 0
+
+ - :Field:
+ **Name**
+ :Description:
+ The plugin name can be any string. It is displayed in the list of available plugins in the TYPO3 content element wizard. An example is "Latest articles".
+ - :Field:
+ **Key**
+ :Description:
+ The plugin key must be a lowercase, alphanumeric string. It is used to identify the plugin of your extension. An example is "latestarticles".
+ - :Field:
+ **Description**
+ :Description:
+ The plugin description can be any text. It is displayed in the list of available plugins in the TYPO3 content element wizard below the plugin name.
+ - :Field:
+ **Controller action combinations**
+ (advanced options)
+ :Description:
+ In each line all actions of a controller supported by this plugin are listed by `` => ,,...``. The first action of the first line is the default action. Actions are defined in the related aggregate root object, and the controller name corresponds to the object name.
+
+ An example is
+
+ .. code-block:: none
+
+ Blog => list,show,new,create,edit,update
+ Author => list,show
+ - :Field:
+ **Non cacheable actions**
+ (advanced options)
+ :Description:
+ Each line lists all actions of a controller that should not be cached. This list is a subset of the *Controller action combinations* property list.
+
+ An example is
+
+ .. code-block:: none
+
+ Blog => new,create,edit,update
+
+.. figure:: /Images/AutomaticScreenshots/FrontendPlugin.png
+ :alt: Frontend plugin
+ :width: 250px
+
+ The frontend plugins
diff --git a/Documentation/GraphicalEditor/GraphicalEditorOverview/Index.rst b/Documentation/GraphicalEditor/GraphicalEditorOverview/Index.rst
new file mode 100644
index 000000000..f0172a3d8
--- /dev/null
+++ b/Documentation/GraphicalEditor/GraphicalEditorOverview/Index.rst
@@ -0,0 +1,16 @@
+.. include:: /Includes.rst.txt
+.. _graphical-editor-overview:
+
+================================
+Overview of the graphical editor
+================================
+
+Go to the backend module of the Extension Builder, the graphical editor will appear directly. At the left side you will see the properties area (1), in which you can setup the extension properties, add authors (2), plugins (3) and modules (4).
+
+Please note that some configuration options are only available if the advanced options are enabled by clicking the :guilabel:`Show advanced options` button in the upper left corner (5) beside the properties area. These options are mainly intended for experienced TYPO3 developers.
+
+.. figure:: /Images/AutomaticScreenshots/GraphicalEditor.jpg
+ :alt: Graphical editor
+ :class: with-shadow
+
+ Graphical editor
diff --git a/Documentation/GraphicalEditor/Index.rst b/Documentation/GraphicalEditor/Index.rst
index b61448ca3..25be6b804 100644
--- a/Documentation/GraphicalEditor/Index.rst
+++ b/Documentation/GraphicalEditor/Index.rst
@@ -1,5 +1,4 @@
.. include:: /Includes.rst.txt
-
.. _graphical-editor:
================
@@ -8,434 +7,100 @@ Graphical editor
To create a TYPO3 extension based on Extbase & Fluid, follow these steps:
-.. contents::
- :backlinks: top
- :class: compact-list
- :depth: 2
- :local:
-
-1. Open the graphical editor
-============================
-
-Go to the backend module of the Extension Builder,
-switch to the graphical editor by selecting the :guilabel:`Domain Modelling`
-view (1)
-and ensure that the properties form (2) is expanded, located on the left side of
-the graphical modeler (3).
-
-Please note that some configuration options are only available if the advanced
-options are enabled by clicking the :guilabel:`Show advanced options` button
-in the upper right corner (4). These options are mainly intended for experienced
-TYPO3 developers.
-
-.. include:: /Images/AutomaticScreenshots/GraphicalEditor.rst.txt
-
-2. Insert meta data of extension
-================================
-
-Enter meaningful meta data of your extension in the properties form (2) on the
-left side.
-
-Once you have filled in the required *Name*, *Vendor name* and *Key* fields,
-you can click the :guilabel:`Save` button at the top to create the extension
-skeleton in your file system based on your configuration.
-Feel encouraged to save frequently.
-
-+----------------------+----------------------------------------------------------------------------------------------------------+
-|**Name** |The extension name can be any string and is used as ``title`` property in the extension configuration |
-| |file :file:`ext_emconf.php`. |
-| |It is displayed, for example, in the `TYPO3 Extension Repository (TER) `__ |
-| |and the Extension Manager module. |
-| | |
-| |An example is "The EBT Blog". |
-+----------------------+----------------------------------------------------------------------------------------------------------+
-|**Vendor name** |The vendor name must be an UpperCamelCase, alphanumeric string. It is used |
-| | |
-| |- in the namespace of PHP classes: ``\\\\`` and |
-| |- in the ``name`` property of the :file:`composer.json`: ``/``. |
-| | |
-| |An example is "Ebt". |
-+----------------------+----------------------------------------------------------------------------------------------------------+
-|**Key** |The extension key must be a lowercase, underscored, alphanumeric string. |
-| |It must be unique throughout the TER and is best composed of the vendor name and an extension specific |
-| |name, such as ``_``, where it must not start with "tx\_", "pages\_", "sys\_", |
-| |"ts\_language\_", and "csh\_". It is used |
-| | |
-| |- as extension directory name :file:`/`, |
-| |- in the language files: ``product-name=`` and |
-| |- in the :file:`composer.json`: ``name: /``. |
-| | |
-| |An example is "ebt_blog". |
-+----------------------+----------------------------------------------------------------------------------------------------------+
-|**Description** |The extension description can be any text. It is used as ``description`` property in extension |
-| |configuration files :file:`ext_emconf.php` and :file:`composer.json`. |
-+----------------------+----------------------------------------------------------------------------------------------------------+
-|**Version** |A good versioning scheme helps to track the changes. We recommend *semantic versioning*. |
-|(More options) | |
-+----------------------+----------------------------------------------------------------------------------------------------------+
-|**State** |The status indicates whether the extension has already reached a stable phase, or whether it is still in |
-|(More options) |alpha or beta. |
-+----------------------+----------------------------------------------------------------------------------------------------------+
-|**Extension authors** |There is a possibility to add developers or project managers here. |
-+----------------------+----------------------------------------------------------------------------------------------------------+
-
-3. Create a domain object
-=========================
-
-If you want to extend the extension skeleton to implement business logic, create
-at least one domain object by dragging the gray :guilabel:`New Model Object` tile onto
-the canvas.
-Give it a meaningful name, which must be an UpperCamelCase, alphanumeric string,
-for example "Blog".
-
-3.a. Edit domain object settings
---------------------------------
-
-Edit the general settings of the domain object by opening the
-:guilabel:`Domain object settings` subsection.
-
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Is aggregate root?** |Check this option if this domain object combines other objects into an aggregate. Objects |
-| |outside the aggregate may contain references to this root object, but not to other objects |
-| |in the aggregate. The aggregate root checks the consistency of changes in the aggregate. |
-| |An example is a blog object that has a related post object that can only be accessed through |
-| |the blog object with ``$blog->getPosts()``. |
-| | |
-| |Checking this option in the Extension Builder means that a controller class is generated for |
-| |this object, whose actions can be defined in the following :guilabel:`Default actions` |
-| |subsection. |
-| |Additionally, a repository class is generated that allows to retrieve all instances of this |
-| |domain object from the persistence layer, i.e. in most scenarios from the database. |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Description** |The domain object description can be any text. It is used in the PHPDoc comment of its |
-| |class. |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Object type** |Select whether the domain object is an *entity* or a *value object*. |
-|(Advanced options) | |
-| |An entity is identified by a unique identifier and its properties usually change during the |
-| |application run. An example is a customer whose name, address, email, etc. may change, but |
-| |can always be identified by the customer ID. |
-| | |
-| |A value object is identified by its property values and is usually used as a more complex |
-| |entity property. An example is an address that is identified by its street, house number, |
-| |city and postal code and would no longer be the same address if any of its values changed. |
-| | |
-| |**Note**: As of TYPO3 v11, it is recommended to specify any domain object of type "entity" |
-| |due to the implementation details of Extbase. However, this might change in upcoming TYPO3 |
-| |versions. |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Map to existing table** |Instead of creating a new database table for the domain object, you can let it use an |
-|(Advanced options) |existing table. This can be useful if there is no domain object class using this table yet. |
-| |Enter the appropriate table name in this field. Each object property will be assigned to an |
-| |existing table field if both names match, otherwise the table field will be created. |
-| |This check takes into account that the property name is a lowerCamelCase and the table field |
-| |name is a lowercase, underscored string, for example the ``firstName`` property matches the |
-| |``first_name`` field. For more information on this topic, see the page |
-| |":doc:`/InDepth/ExtendingDomainObjects`". |
-| | |
-| |An example is "tt_address". |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Extend existing model class** |Extbase supports *single table inheritance*, which means that a domain object class can |
-|(Advanced options) |inherit from another domain object class and instances of both are persisted in the same |
-| |database table, optionally using only a subset of the table fields. The class to inherit |
-| |from must be specified as a fully qualified class name and must exist in the current TYPO3 |
-| |instance. |
-| |Each object property will be assigned to an existing table field if both names match, |
-| |otherwise the table field will be newly created. Additionally, a table field |
-| |:sql:`tx_extbase_type` is created to specify the domain object class stored in this table |
-| |row. For more information on this topic, see the ":doc:`/InDepth/ExtendingDomainObjects`" |
-| |page. |
-| | |
-| |An example is "\\TYPO3\\CMS\\Extbase\\Domain\\Model\\Category". |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-
-.. include:: /Images/AutomaticScreenshots/DomainObjectSettings.rst.txt
-
-3.b. Add actions
-----------------
-
-If the domain object is an aggregate root, open the :guilabel:`Default actions` section
-and select the actions you need and add custom actions if required.
-All selected actions are made available in the controller class that is created
-along with the domain object class, and a Fluid template with an appropriate name is
-generated for each action.
-
-.. include:: /Images/AutomaticScreenshots/Actions.rst.txt
-
-3.c. Add properties
--------------------
-
-Expand the :guilabel:`properties` subsection to add domain object properties:
-
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Property name** |The property name must be a lowerCamelCase, alphanumeric string. It is used |
-| | |
-| |- in language files and domain object classes as ```` and |
-| |- in the database table as ````. |
-| | |
-| |An example is "firstName". |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Property type** |Select the type of the property. This determines the field type in the database table, the |
-| |TCA type for TYPO3 backend rendering, and the Fluid type for TYPO3 frontend rendering. |
-| | |
-| |**Note**: As of TYPO3 v11, the types marked with an asterisk (\*) are not fully implemented |
-| |for frontend rendering for various reasons. For example, the frontend handling of the types |
-| |"file" and "image" is not yet implemented, because an implementation in Extbase is missing. |
-| |For these, many implementation examples can be found on the Internet. |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Description** |The property description can be any text. It is displayed in the *List* module of the TYPO3 |
-|(Advanced options) |backend as context sensitive help when you click on the property field. |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Is required?** |Enable this option if this property must be set in TYPO3 frontend. Required properties are |
-|(Advanced options) |provided with a :php:`@TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")` PHPDoc annotation |
-| |in the domain object class. |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Is exclude field?** |Enable this option if you want to be able to hide this property from non-administrators |
-|(Advanced options) |in the TYPO3 backend. |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-
-.. include:: /Images/AutomaticScreenshots/Properties.rst.txt
-
-3.d. Add relations
-------------------
-
-If you create multiple domain objects you may want to connect them by relations.
-A relation property can be added in the :guilabel:`relations` subsection.
-When being added, it can be connected to the related object by dragging the
-round connector of the relation property and dropping it at the connector of the
-related object. When expanding the relation property panel you can refine the
-type of relation.
-
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Name** |The relation property name must be a lowerCamelCase, alphanumeric string. It is used like an |
-| |ordinary property. |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Type** |These relation types are available: |
-| | |
-| |**one-to-one (1:1)** |
-| | |
-| |This relation property can be associated with a specific instance of the related domain |
-| |object and that instance has no other relation. An example is a person who has only one |
-| |account and this account is not used by any other person. |
-| | |
-| |This setting results in a side-by-side selection field with a maximum of 1 selected item in |
-| |the TYPO3 backend. |
-| | |
-| |**one-to-many (1:n)** |
-| | |
-| |This relation property can be associated with multiple instances of the related domain |
-| |object, but each of those instances has no other relation. An example is a blog with |
-| |multiple posts, but each post belongs to only one blog. |
-| | |
-| |See *Render type* description for more details on the rendering of the property in the TYPO3 |
-| |backend. |
-| | |
-| |**many-to-one (n:1)** |
-| | |
-| |This relation property can be associated with a specific instance of the related domain |
-| |object, but that instance can have multiple relations. An example is when each person has |
-| |a specific birthplace, but many people can have the same birthplace. |
-| | |
-| |This is represented in the TYPO3 backend as a side-by-side selection field with a maximum |
-| |number of 1 selected item. |
-| | |
-| |**many-to-many (m:n)** |
-| | |
-| |This relation property can be associated with multiple instances of the related domain |
-| |object, and each of these instances can also have multiple relations. An example is when a |
-| |book may have multiple authors and each author has written multiple books. |
-| | |
-| |See *Render type* description for more details on the rendering of the property in the TYPO3 |
-| |backend. |
-| | |
-| |**Note**: For the many-to-many relation to work properly, you must perform two additional |
-| |tasks: |
-| | |
-| |1. Add a many-to-many relation property in the related domain object as well and connect it |
-| | to this object. |
-| |2. Match the database table name in the |
-| | :ref:`MM property ` of the TCA files of both domain |
-| | objects in the generated extension. If this is not the case, the relations of one object |
-| | are stored in a different database table than the relations of the related object. |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Render type** |This option is only available for the one-to-many and many-to-many relations and defines the |
-| |display of the relation property field in the TYPO3 backend: |
-| | |
-| |**one-to-many (1:n)** |
-| | |
-| |This can be rendered either as a |
-| |:doc:`side-by-side selection box ` |
-| |or as an |
-| |:doc:`inline-relational-record-editing field `. |
-| | |
-| |**many-to-many (m:n)** |
-| | |
-| |This can be represented as either a |
-| |:doc:`side-by-side selection box ` |
-| |, a :doc:`multi-select checkbox `, |
-| |or a :doc:`multi-select selection box `. |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Description** |The relation description can be any text. It is displayed in the *List* module of the TYPO3 |
-| |backend as context sensitive help when you click on the relation property field. |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Is exclude field?** |Enable this option if you want to be able to hide this relation property from |
-|(Advanced options) |non-administrators in the TYPO3 backend. |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Lazy loading** |Should the related instances be loaded when an instance of this domain is created |
-|(Advanced options) |(*eager loading*) or on demand (*lazy loading*). Lazy loading relation properties are |
-| |provided with a :php:`@TYPO3\CMS\Extbase\Annotation\ORM\Lazy` PHPDoc annotation in the |
-| |domain object class. |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-
-.. include:: /Images/AutomaticScreenshots/Relations.rst.txt
-
-4. Create a frontend plugin
-===========================
-
-If you want to create an extension that generates output in the TYPO3 frontend,
-add a plugin in the :guilabel:`Frontend plugins` subsection of the properties form.
-It will then be available for selection in the type field of the
-TYPO3 content element "General Plugin".
-
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Name** |The plugin name can be any string. It is displayed in the list of available plugins in the |
-| |TYPO3 content element wizard. An example is "Latest articles". |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Key** |The plugin key must be a lowercase, alphanumeric string. It is used to identify the plugin |
-| |of your extension. An example is "latestarticles". |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Description** |The plugin description can be any text. It is displayed in the list of available plugins in |
-| |the TYPO3 content element wizard below the plugin name. |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Controller action combinations** |In each line all actions of a controller supported by this plugin are listed by |
-|(Advanced options) |`` => ,,...``. The first action of the first line is the |
-| |default action. Actions are defined in the related aggregate root object, and the controller |
-| |name corresponds to the object name. |
-| | |
-| |An example is |
-| | |
-| |.. code-block:: none |
-| | |
-| | Blog => list,show,new,create,edit,update |
-| | Author => list,show |
-| | |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Non cacheable actions** |Each line lists all actions of a controller that should not be cached. This list is a subset |
-|(Advanced options) |of the *Controller action combinations* property list. |
-| | |
-| |An example is |
-| | |
-| |.. code-block:: none |
-| | |
-| | Blog => new,create,edit,update |
-| | |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-
-.. include:: /Images/AutomaticScreenshots/FrontendPlugins.rst.txt
-
-5. Create a backend module
-==========================
-
-If your extension should provide a TYPO3 backend module,
-add a module in the :guilabel:`Backend modules` subsection of the properties form.
-It will then be available in the module menu on the left side of the TYPO3
-backend.
-
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Name** |The module name can be any string. It is currently used only internally in the |
-| |Extension Builder, for example in validation results. An example is "EBT Blogs". |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Key** |The module key must be a lowercase, alphanumeric string. It is used to identify the module |
-| |of your extension. An example is "ebtblogs". |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Description** |The module description can be any text. It is displayed in the *About* module of the |
-| |TYPO3 backend. |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Tab label** |The module name in the TYPO3 module menu can be any string. |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Main module** |This is the module key of the section in the TYPO3 module menu to which the module is |
-| |assigned. For example, "web" or "site". |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-|**Controller action combinations** |In each line all actions of a controller supported by this module are listed by |
-|(Advanced options) |`` => ,,...``. The first action of the first line is the |
-| |default action. Actions are defined in the related aggregate root object, and the controller |
-| |name corresponds to the object name. |
-| | |
-| |An example is |
-| | |
-| |.. code-block:: none |
-| | |
-| | Blog => list,show,new,create,edit,update,delete,duplicate |
-| | Author => list,show,new,create,edit,update,delete |
-| | |
-+-----------------------------------+---------------------------------------------------------------------------------------------+
-
-.. include:: /Images/AutomaticScreenshots/BackendModules.rst.txt
-
-6. Save the extension
-=====================
-
-If your model represents the domain you wanted to implement you can hit the
-:guilabel:`Save` button at the top.
-The Extension Builder generates all required files for you in a location that
-depends on your local setup:
-
-6.a. Composer mode
-------------------
-
-If you run TYPO3 in :doc:`Composer mode `, you
-have to specify and configure a `local path repository `_
-before saving your extension. Extension Builder reads the path from the TYPO3
-project :file:`composer.json` and offers it as a target path to save the
-extension.
-
-The local path repository is normally configured as follows:
-
-.. code-block:: js
-
- {
- "repositories": {
- "packages": {
- "type": "path",
- "url": "packages/*"
- }
- }
- }
-
-To install the extension in the TYPO3 instance you have to execute the usual:
-
-.. code-block:: bash
-
- composer require :@dev
-
-, for example:
-
-.. code-block:: bash
-
- composer require ebt/ebt-blog:@dev
-
-which will cause a symlink :file:`typo3conf/ext//` to your extension
-to be created and the extension to be recognized in the Extension Manager.
-
-Before TYPO3 11.4 you had to install the extension additionally in the Extension
-Manager.
-
-6.b. Legacy mode
-----------------
-
-If you run TYPO3 in :doc:`Legacy mode `
-the extension will be generated directly at :file:`typo3conf/ext//`.
-
-Once the extension is saved you should be able to install it in the Extension
-Manager.
-
-7. Continue developing
-======================
-
-Now you can start modifying the generated files in your IDE. If you still want
-to be able to modify the domain model in the graphical editor you have to make
-sure that the *roundtrip mode* is activated in the
-:doc:`configuration `, before loading the extension in the
-Extension Builder again.
-
-.. include:: /Images/AutomaticScreenshots/GraphicalEditorBlogExampleFullPage.rst.txt
+.. container:: row m-0 p-0
+
+ .. container:: col-md-6 pl-0 pr-3 py-3 m-0
+
+ .. container:: card px-0 h-100
+
+ .. rst-class:: card-header h3
+
+ .. rubric:: :ref:`Overview of the graphical editor `
+
+ .. container:: card-body
+
+ With the graphical editor you can easily create a TYPO3 extension based on Extbase & Fluid.
+
+ .. container:: col-md-6 pl-0 pr-3 py-3 m-0
+
+ .. container:: card px-0 h-100
+
+ .. rst-class:: card-header h3
+
+ .. rubric:: :ref:`Insert meta data of extension `
+
+ .. container:: card-body
+
+ The meta data like *name* and *extension_key* are required for each extension.
+
+ .. container:: col-md-6 pl-0 pr-3 py-3 m-0
+
+ .. container:: card px-0 h-100
+
+ .. rst-class:: card-header h3
+
+ .. rubric:: :ref:`Create a domain object `
+
+ .. container:: card-body
+
+ If you want to extend the extension skeleton to implement business logic, you need at least one domain object.
+
+ .. container:: col-md-6 pl-0 pr-3 py-3 m-0
+
+ .. container:: card px-0 h-100
+
+ .. rst-class:: card-header h3
+
+ .. rubric:: :ref:`Frontend plugins `
+
+ .. container:: card-body
+
+ If you want to create an extension that generates output in the TYPO3 frontend, you need to create a frontend plugin.
+
+ .. container:: col-md-6 pl-0 pr-3 py-3 m-0
+
+ .. container:: card px-0 h-100
+
+ .. rst-class:: card-header h3
+
+ .. rubric:: :ref:`Backend modules `
+
+ .. container:: card-body
+
+ If your extension should provide a TYPO3 backend module, you need to create a backend module.
+
+ .. container:: col-md-6 pl-0 pr-3 py-3 m-0
+
+ .. container:: card px-0 h-100
+
+ .. rst-class:: card-header h3
+
+ .. rubric:: :ref:`Saving and publishing your extension `
+
+ .. container:: card-body
+
+ After saving and finishing your extension, you could publish it into the TER and/or packagist.
+
+ .. container:: col-md-6 pl-0 pr-3 py-3 m-0
+
+ .. container:: card px-0 h-100
+
+ .. rst-class:: card-header h3
+
+ .. rubric:: :ref:`Continue developing `
+
+ .. container:: card-body
+
+ You can continue developing your extension by adding more features, or by improving the existing ones.
+
+.. toctree::
+ :maxdepth: 5
+ :titlesonly:
+
+ GraphicalEditorOverview/Index
+ MetaData/Index
+ DomainObject/Index
+ FrontendPlugins/Index
+ BackendModules/Index
+ SavingAndPublishing/Index
+ ContinueDeveloping/Index
diff --git a/Documentation/GraphicalEditor/MetaData/Index.rst b/Documentation/GraphicalEditor/MetaData/Index.rst
new file mode 100644
index 000000000..64430f67d
--- /dev/null
+++ b/Documentation/GraphicalEditor/MetaData/Index.rst
@@ -0,0 +1,75 @@
+.. include:: /Includes.rst.txt
+.. _meta-data:
+
+=============================
+Insert meta data of extension
+=============================
+
+Enter meaningful meta data of your extension in the properties form (1) on the
+left side.
+
+Once you have filled in the required *Name*, *Vendor name*, *Key*, *Description* and *Status* fields,
+you can click the :guilabel:`Save` button at the top to create the extension
+skeleton in your file system based on your configuration.
+Feel encouraged to save and optionally commit all your changes frequently.
+
+.. confval:: Name
+
+ The extension name can be any string and is used as ``title`` property in the extension configuration file :file:`ext_emconf.php`. It is displayed, for example, in the `TYPO3 Extension Repository (TER) `__ and the Extension Manager module.
+
+ An example is "The EBT Blog".
+
+.. confval:: Vendor name
+
+ The vendor name must be an UpperCamelCase, alphanumeric string. It is used
+
+ - in the namespace of PHP classes: ``\\\\`` and
+ - in the ``name`` property of the :file:`composer.json`: ``/``.
+
+ An example is "Ebt".
+
+.. confval:: Extension key
+
+ The extension key must be a lowercase, underscored, alphanumeric string. If you want to publish your extension to the TER, it must be unique throughout the TER and is best composed of the vendor name and an extension specific name, such as ``_``, where it must not start with "tx\_", "pages\_", "sys\_", "ts\_language\_", and "csh\_". It is used
+
+ - as extension directory name :file:`/`,
+ - in the language files: ``product-name=`` and
+ - in the :file:`composer.json`: ``name: /``.
+
+ An example is "ebt_blog".
+
+.. confval:: Description
+ :name: extension-description
+
+ The extension description can be any text. It is used as ``description`` property in extension configuration files :file:`ext_emconf.php` and :file:`composer.json`.
+
+.. confval:: Category
+
+ Which category the extension belongs to.
+
+.. confval:: Version
+
+ A good versioning scheme helps to track the changes. We recommend `semantic versioning `__ .
+
+.. confval:: State
+
+ The status indicates whether the extension has already reached a stable phase, or whether it is still in alpha or beta.
+
+ Extensions with the state *excludeFromUpdates* will not be updated by the Extension Manager.
+
+ .. hint::
+
+ Extension with state *alpha* are not possible to be uploaded to the TER.
+
+.. confval:: Source language
+
+ The source language represents the source language for the `.xliff` translation files. It is common to use "en" for English.
+
+.. confval:: Depends on
+
+ This represents the extensions, which are required by the current extension. The required extensions are listed in the :file:`composer.json` and :file:`ext_emconf.php` files.
+
+.. confval:: Authors
+
+ There is a possibility to add developers or project managers here. These authors will be listed inside :file:`composer.json` and :file:`ext_emconf.php`
+
diff --git a/Documentation/GraphicalEditor/SavingAndPublishing/Index.rst b/Documentation/GraphicalEditor/SavingAndPublishing/Index.rst
new file mode 100644
index 000000000..e142eed03
--- /dev/null
+++ b/Documentation/GraphicalEditor/SavingAndPublishing/Index.rst
@@ -0,0 +1,58 @@
+.. include:: /Includes.rst.txt
+.. _saving-and-publishing:
+
+====================================
+Saving and publishing your extension
+====================================
+
+If your model represents the domain you wanted to implement you can hit the
+:guilabel:`Save` button at the top.
+The Extension Builder generates all required files for you in a location that
+depends on your local setup:
+
+.. tabs::
+
+ .. group-tab:: Composer mode
+
+ If you run TYPO3 in :doc:`Composer mode `, you have to specify and configure a `local path repository `_ before saving your extension. Extension Builder reads the path from the TYPO3 project :file:`composer.json` and offers it as a target path to save the extension.
+
+ The local path repository is normally configured as follows inside the `composer.json`:
+
+ .. code-block:: js
+
+ {
+ "repositories": {
+ "packages": {
+ "type": "path",
+ "url": "packages/*"
+ }
+ }
+ }
+
+ To install the extension in the TYPO3 instance you have to execute the following command:
+
+ .. code-block:: bash
+
+ composer require :@dev
+
+ .. note::
+
+ You only need the `@dev` dependency, if you install packages from a local path repository. If you install packages from a public repository (like `packagist.org `__ ), you can omit the `@dev` dependency or use a specific version like `^6.1.0`.
+
+ The final command could be look like this:
+
+ .. code-block:: bash
+
+ composer require ebt/ebt-blog:@dev
+
+ This will result into a symlink :file:`typo3conf/ext//` to your extension and the extension to be recognized in the Extension Manager.
+
+ .. hint::
+
+ Before TYPO3 11.4 you had to install the extension additionally in the Extension Manager.
+
+ .. group-tab:: Legacy mode
+
+ If you run TYPO3 in :doc:`Legacy mode ` the extension will be generated directly at :file:`typo3conf/ext//`.
+
+ Once the extension is saved you should be able to install it in the Extension Manager.
diff --git a/Documentation/Images/AffinityPhoto/OverviewEBDomainModule.afphoto b/Documentation/Images/AffinityPhoto/OverviewEBDomainModule.afphoto
new file mode 100644
index 000000000..5bfa1802e
Binary files /dev/null and b/Documentation/Images/AffinityPhoto/OverviewEBDomainModule.afphoto differ
diff --git a/Documentation/Images/AffinityPhoto/OverviewEBDomainModule.jpg b/Documentation/Images/AffinityPhoto/OverviewEBDomainModule.jpg
new file mode 100644
index 000000000..223572cc3
Binary files /dev/null and b/Documentation/Images/AffinityPhoto/OverviewEBDomainModule.jpg differ
diff --git a/Documentation/Images/AutomaticScreenshots/Actions.png b/Documentation/Images/AutomaticScreenshots/Actions.png
index b6bfcc3b4..71a891d73 100644
Binary files a/Documentation/Images/AutomaticScreenshots/Actions.png and b/Documentation/Images/AutomaticScreenshots/Actions.png differ
diff --git a/Documentation/Images/AutomaticScreenshots/Actions.rst.txt b/Documentation/Images/AutomaticScreenshots/Actions.rst.txt
deleted file mode 100644
index 98ca4c264..000000000
--- a/Documentation/Images/AutomaticScreenshots/Actions.rst.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-.. =========================================================
-.. Automatically generated by the TYPO3 Screenshots project.
-.. https://github.com/TYPO3-Documentation/t3docs-screenshots
-.. =========================================================
-
-.. figure:: /Images/AutomaticScreenshots/Actions.png
- :alt: The associated controller actions
- :class: with-shadow
-
- The associated controller actions
\ No newline at end of file
diff --git a/Documentation/Images/AutomaticScreenshots/BackendModule.png b/Documentation/Images/AutomaticScreenshots/BackendModule.png
new file mode 100644
index 000000000..9367a9073
Binary files /dev/null and b/Documentation/Images/AutomaticScreenshots/BackendModule.png differ
diff --git a/Documentation/Images/AutomaticScreenshots/BackendModules.png b/Documentation/Images/AutomaticScreenshots/BackendModules.png
deleted file mode 100644
index 68c7838b3..000000000
Binary files a/Documentation/Images/AutomaticScreenshots/BackendModules.png and /dev/null differ
diff --git a/Documentation/Images/AutomaticScreenshots/BackendModules.rst.txt b/Documentation/Images/AutomaticScreenshots/BackendModules.rst.txt
deleted file mode 100644
index 0630d2129..000000000
--- a/Documentation/Images/AutomaticScreenshots/BackendModules.rst.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-.. =========================================================
-.. Automatically generated by the TYPO3 Screenshots project.
-.. https://github.com/TYPO3-Documentation/t3docs-screenshots
-.. =========================================================
-
-.. figure:: /Images/AutomaticScreenshots/BackendModules.png
- :alt: The backend modules
- :class: with-shadow
-
- The backend modules
\ No newline at end of file
diff --git a/Documentation/Images/AutomaticScreenshots/DomainObjectSettings.png b/Documentation/Images/AutomaticScreenshots/DomainObjectSettings.png
index 2738c39c3..7057d6e4b 100644
Binary files a/Documentation/Images/AutomaticScreenshots/DomainObjectSettings.png and b/Documentation/Images/AutomaticScreenshots/DomainObjectSettings.png differ
diff --git a/Documentation/Images/AutomaticScreenshots/DomainObjectSettings.rst.txt b/Documentation/Images/AutomaticScreenshots/DomainObjectSettings.rst.txt
deleted file mode 100644
index 332857a2a..000000000
--- a/Documentation/Images/AutomaticScreenshots/DomainObjectSettings.rst.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-.. =========================================================
-.. Automatically generated by the TYPO3 Screenshots project.
-.. https://github.com/TYPO3-Documentation/t3docs-screenshots
-.. =========================================================
-
-.. figure:: /Images/AutomaticScreenshots/DomainObjectSettings.png
- :alt: The domain object settings
- :class: with-shadow
-
- The domain object settings
\ No newline at end of file
diff --git a/Documentation/Images/AutomaticScreenshots/FrontendPlugin.png b/Documentation/Images/AutomaticScreenshots/FrontendPlugin.png
new file mode 100644
index 000000000..b9aa596f2
Binary files /dev/null and b/Documentation/Images/AutomaticScreenshots/FrontendPlugin.png differ
diff --git a/Documentation/Images/AutomaticScreenshots/FrontendPlugins.png b/Documentation/Images/AutomaticScreenshots/FrontendPlugins.png
deleted file mode 100644
index b0ad04f62..000000000
Binary files a/Documentation/Images/AutomaticScreenshots/FrontendPlugins.png and /dev/null differ
diff --git a/Documentation/Images/AutomaticScreenshots/FrontendPlugins.rst.txt b/Documentation/Images/AutomaticScreenshots/FrontendPlugins.rst.txt
deleted file mode 100644
index f6c62eb40..000000000
--- a/Documentation/Images/AutomaticScreenshots/FrontendPlugins.rst.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-.. =========================================================
-.. Automatically generated by the TYPO3 Screenshots project.
-.. https://github.com/TYPO3-Documentation/t3docs-screenshots
-.. =========================================================
-
-.. figure:: /Images/AutomaticScreenshots/FrontendPlugins.png
- :alt: The frontend plugins
- :class: with-shadow
-
- The frontend plugins
\ No newline at end of file
diff --git a/Documentation/Images/AutomaticScreenshots/GraphicalEditor.jpg b/Documentation/Images/AutomaticScreenshots/GraphicalEditor.jpg
new file mode 100644
index 000000000..223572cc3
Binary files /dev/null and b/Documentation/Images/AutomaticScreenshots/GraphicalEditor.jpg differ
diff --git a/Documentation/Images/AutomaticScreenshots/GraphicalEditor.png b/Documentation/Images/AutomaticScreenshots/GraphicalEditor.png
deleted file mode 100644
index cdb7dfd5e..000000000
Binary files a/Documentation/Images/AutomaticScreenshots/GraphicalEditor.png and /dev/null differ
diff --git a/Documentation/Images/AutomaticScreenshots/GraphicalEditor.rst.txt b/Documentation/Images/AutomaticScreenshots/GraphicalEditor.rst.txt
deleted file mode 100644
index 34707510f..000000000
--- a/Documentation/Images/AutomaticScreenshots/GraphicalEditor.rst.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-.. =========================================================
-.. Automatically generated by the TYPO3 Screenshots project.
-.. https://github.com/TYPO3-Documentation/t3docs-screenshots
-.. =========================================================
-
-.. figure:: /Images/AutomaticScreenshots/GraphicalEditor.png
- :alt: Graphical editor
- :class: with-shadow
-
- Graphical editor
\ No newline at end of file
diff --git a/Documentation/Images/AutomaticScreenshots/ObjectProperties.png b/Documentation/Images/AutomaticScreenshots/ObjectProperties.png
new file mode 100644
index 000000000..cd964cbf2
Binary files /dev/null and b/Documentation/Images/AutomaticScreenshots/ObjectProperties.png differ
diff --git a/Documentation/Images/AutomaticScreenshots/ObjectRelations.png b/Documentation/Images/AutomaticScreenshots/ObjectRelations.png
new file mode 100644
index 000000000..b5538ce9f
Binary files /dev/null and b/Documentation/Images/AutomaticScreenshots/ObjectRelations.png differ
diff --git a/Documentation/Images/AutomaticScreenshots/Properties.png b/Documentation/Images/AutomaticScreenshots/Properties.png
deleted file mode 100644
index 4b17d5101..000000000
Binary files a/Documentation/Images/AutomaticScreenshots/Properties.png and /dev/null differ
diff --git a/Documentation/Images/AutomaticScreenshots/Properties.rst.txt b/Documentation/Images/AutomaticScreenshots/Properties.rst.txt
deleted file mode 100644
index 5bbe6074b..000000000
--- a/Documentation/Images/AutomaticScreenshots/Properties.rst.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-.. =========================================================
-.. Automatically generated by the TYPO3 Screenshots project.
-.. https://github.com/TYPO3-Documentation/t3docs-screenshots
-.. =========================================================
-
-.. figure:: /Images/AutomaticScreenshots/Properties.png
- :alt: The domain object properties
- :class: with-shadow
-
- The domain object properties
diff --git a/Documentation/InDepth/ExtendingDomainObjects.rst b/Documentation/InDepth/ExtendingDomainObjects.rst
index a054c30c3..a9db7ac43 100644
--- a/Documentation/InDepth/ExtendingDomainObjects.rst
+++ b/Documentation/InDepth/ExtendingDomainObjects.rst
@@ -1,4 +1,5 @@
.. include:: /Includes.rst.txt
+.. _extending-domain-objects:
=========================================================
Extending domain objects or map to existing tables
diff --git a/Documentation/InDepth/Index.rst b/Documentation/InDepth/Index.rst
index b8e76f71e..a2610dc70 100644
--- a/Documentation/InDepth/Index.rst
+++ b/Documentation/InDepth/Index.rst
@@ -1,5 +1,4 @@
.. include:: /Includes.rst.txt
-
.. _in-depth:
========
diff --git a/Documentation/InDepth/Roundtrip.rst b/Documentation/InDepth/Roundtrip.rst
index a05f4b3a2..c1484b703 100644
--- a/Documentation/InDepth/Roundtrip.rst
+++ b/Documentation/InDepth/Roundtrip.rst
@@ -1,4 +1,5 @@
.. include:: /Includes.rst.txt
+.. _roundtrip-mode:
==============
Roundtrip mode
diff --git a/Documentation/Index.rst b/Documentation/Index.rst
index e0044ea0f..304a1dc23 100644
--- a/Documentation/Index.rst
+++ b/Documentation/Index.rst
@@ -17,7 +17,7 @@ Extension Builder
en
:Author:
- Nico de Haen & contributors
+ Extension Builder Team
:License:
This document is published under the
@@ -47,6 +47,116 @@ even if you change the extension in the graphical editor.
.. _Extbase: https://docs.typo3.org/m/typo3/reference-coreapi/11.5/en-us/ExtensionArchitecture/Extbase/Index.html
.. _Fluid: https://docs.typo3.org/m/typo3/reference-coreapi/11.5/en-us/ApiOverview/Fluid/Introduction.html
+.. container:: row m-0 p-0
+
+ .. container:: col-md-6 pl-0 pr-3 py-3 m-0
+
+ .. container:: card px-0 h-100
+
+ .. rst-class:: card-header h3
+
+ .. rubric:: :ref:`Introduction `
+
+ .. container:: card-body
+
+ What is the extension builder?
+
+ .. container:: col-md-6 pl-0 pr-3 py-3 m-0
+
+ .. container:: card px-0 h-100
+
+ .. rst-class:: card-header h3
+
+ .. rubric:: :ref:`Installation `
+
+ .. container:: card-body
+
+ Install the Extension Builder extension.
+
+ .. container:: col-md-6 pl-0 pr-3 py-3 m-0
+
+ .. container:: card px-0 h-100
+
+ .. rst-class:: card-header h3
+
+ .. rubric:: :ref:`Configuration `
+
+ .. container:: card-body
+
+ Configuration of the Extension Builder.
+
+ .. container:: col-md-6 pl-0 pr-3 py-3 m-0
+
+ .. container:: card px-0 h-100
+
+ .. rst-class:: card-header h3
+
+ .. rubric:: :ref:`Graphical editor `
+
+ .. container:: card-body
+
+ Overview of the graphical editor.
+
+ .. container:: col-md-6 pl-0 pr-3 py-3 m-0
+
+ .. container:: card px-0 h-100
+
+ .. rst-class:: card-header h3
+
+ .. rubric:: :ref:`Generated extension `
+
+ .. container:: card-body
+
+ What do you get after generating the extension?
+
+ .. container:: col-md-6 pl-0 pr-3 py-3 m-0
+
+ .. container:: card px-0 h-100
+
+ .. rst-class:: card-header h3
+
+ .. rubric:: :ref:`Security `
+
+ .. container:: card-body
+
+ Keep Security in mind.
+
+ .. container:: col-md-6 pl-0 pr-3 py-3 m-0
+
+ .. container:: card px-0 h-100
+
+ .. rst-class:: card-header h3
+
+ .. rubric:: :ref:`Publishing to TER `
+
+ .. container:: card-body
+
+ How to publish your extension to the TER or Packagist.
+
+ .. container:: col-md-6 pl-0 pr-3 py-3 m-0
+
+ .. container:: card px-0 h-100
+
+ .. rst-class:: card-header h3
+
+ .. rubric:: :ref:`Roundtrip mode `
+
+ .. container:: card-body
+
+ When do you need the roundtrip mode?
+
+ .. container:: col-md-6 pl-0 pr-3 py-3 m-0
+
+ .. container:: card px-0 h-100
+
+ .. rst-class:: card-header h3
+
+ .. rubric:: :ref:`Contribution mode `
+
+ .. container:: card-body
+
+ How you can help with developing the Extension Builder.
+
----
**Table of Contents:**
diff --git a/Documentation/Installation/Index.rst b/Documentation/Installation/Index.rst
index 89e28ab6f..0c44a38f6 100644
--- a/Documentation/Installation/Index.rst
+++ b/Documentation/Installation/Index.rst
@@ -1,5 +1,4 @@
.. include:: /Includes.rst.txt
-
.. _installation:
============
@@ -26,12 +25,23 @@ through:
composer require friendsoftypo3/extension-builder
-If you are not using the latest version of the Extension Builder, you need to
-add a version constraint, for example:
+.. tip::
-.. code-block:: bash
+ Although it will still be possible to install extensions in legacy mode,
+ composer mode is still recommended.
+
+.. warning::
+
+ If you are in composer mode, you need to add at least one entry inside "repositories" in your composer.json file. Otherwise the extension_builder will fail to save your extension. The extension_builder will store your generated extension in this folder.
+
+ .. code-block:: php
- composer require friendsoftypo3/extension-builder:"^10.0"
+ "repositories": [
+ "local": {
+ "type": "path",
+ "url": "Packages/*"
+ }
+ ]
.. warning::
@@ -63,7 +73,7 @@ Legacy mode
===========
If you are working with a TYPO3 installation that does not use Composer, install
-the extension in the Extension Manager:
+the extension in the Extension Manager as follows:
- Navigate to :guilabel:`Admin Tools > Extensions > Get Extensions`.
- Click on :guilabel:`Update now`
diff --git a/Documentation/Introduction/Index.rst b/Documentation/Introduction/Index.rst
index 247f2b223..583740e27 100644
--- a/Documentation/Introduction/Index.rst
+++ b/Documentation/Introduction/Index.rst
@@ -1,5 +1,4 @@
.. include:: /Includes.rst.txt
-
.. _introduction:
============
@@ -32,8 +31,8 @@ and actions:
.. include:: /Images/AutomaticScreenshots/GraphicalEditorBlogExampleWindow.rst.txt
-Finally, it generates a basic extension with that can be installed
-and further developed:
+Finally, it generates a basic extension which can be installed
+and developed further:
.. code-block:: none
@@ -48,15 +47,14 @@ and further developed:
├── Classes/..
├── Configuration/..
├── Documentation/..
- ├── Resources/..
- └── Tests/..
+ └── Resources/..
-In addition to the *kickstart mode*, the Extension Builder also provides a
-*roundtrip mode* that allows you to use the graphical editor
+In addition to the *kickstart mode*, the Extension Builder also provides a :ref:`roundtrip mode `
+that allows you to use the :ref:`graphical editor `
even after you have started making manual changes to the files.
In this mode, the Extension Builder retains the manual changes,
such as new methods, changed method bodies, comments and annotations,
-even if you change the extension in the graphical editor.
+even if you change the extension in the :ref:`graphical editor `.
.. _what-does-it-not-do:
@@ -74,9 +72,10 @@ To create them, you should either use the Extension Builder to create a TYPO3
extension skeleton (without domain objects, controllers, plugins and modules)
and add
:doc:`TYPO3 content elements manually `,
-or use one of the dedicate extensions like `Mask `__
-or `Dynamic Content Elements (DCE) `__
-instead.
+use the extension `Mask `__
+or the new system extension `content blocks `__
+which is already available for TYPO3 12 as a 3rd party extension and will be
+included in the TYPO3 core in version 13.
Compatibility of existing extension with newer TYPO3
----------------------------------------------------
@@ -85,3 +84,11 @@ To make an existing TYPO3 extension compatible with a newer TYPO3 version,
we recommend using `TYPO3 Rector `__
instead of trying to load and save the extension in the Extension Builder of
the newer TYPO3 version.
+
+.. admonition:: What about upgrading from 11 to 12?
+
+ As for now, it is not possible to load an extension from an older TYPO3 into
+ the extension_builder. This is, because the whole UI was remade vor version 12
+ and there would be some important missing informations in older extensions.
+
+ If you want to :ref:`contribute ` on this feature, please let us know via `slack #extension-builder `__ or `github `__.
diff --git a/Documentation/PublishToTer/Index.rst b/Documentation/PublishToTer/Index.rst
index c3eb196e6..2ce8559f8 100644
--- a/Documentation/PublishToTer/Index.rst
+++ b/Documentation/PublishToTer/Index.rst
@@ -1,4 +1,5 @@
.. include:: /Includes.rst.txt
+.. _publishing-to-ter:
============================
Publish to TER and Packagist
diff --git a/Documentation/Security/Index.rst b/Documentation/Security/Index.rst
index 3d1644354..9fbc33814 100644
--- a/Documentation/Security/Index.rst
+++ b/Documentation/Security/Index.rst
@@ -1,5 +1,4 @@
.. include:: /Includes.rst.txt
-
.. _security:
========
diff --git a/Documentation/Sponsoring/Index.rst b/Documentation/Sponsoring/Index.rst
index c1672f3b1..fc86476cf 100755
--- a/Documentation/Sponsoring/Index.rst
+++ b/Documentation/Sponsoring/Index.rst
@@ -1,5 +1,4 @@
.. include:: /Includes.rst.txt
-
.. _sponsoring:
==========
diff --git a/Documentation/guides.xml b/Documentation/guides.xml
index de2933882..30187462d 100644
--- a/Documentation/guides.xml
+++ b/Documentation/guides.xml
@@ -10,7 +10,7 @@
project-issues="https://github.com/FriendsOfTYPO3/extension_builder/issues"
edit-on-github-branch="master"
edit-on-github="FriendsOfTYPO3/extension_builder"
- typo3-core-preferred="11.5"
+ typo3-core-preferred="12.4"
interlink-shortcode="friendsoftypo3/extension-builder"
/>
moduleTemplateFactory = $moduleTemplateFactory;
+ }
+
+ /**
+ * @param \VENDOR\Package\Domain\Repository\DomainObjectRepository
+ */
+ public function injectDomainObjectRepository(VENDOR\Package\Domain\Repository\DomainObjectRepository $domainObjectRepository): void
+ {
+ $this->domainObjectRepository = $domainObjectRepository;
+ }
+
+ /**
+ * @return void
+ */
+ protected function initializeAction()
+ {
+ $this->moduleTemplate = $this->moduleTemplateFactory->create($this->request);
+ }
+
+ /**
+ * action list
+ *
+ * @return \Psr\Http\Message\ResponseInterface
+ */
+ public function listAction(): \Psr\Http\Message\ResponseInterface
+ {
+ $domainObjects = $this->domainObjectRepository->findAll();
+ $this->view->assign('domainObjects', $domainObjects);
+ $this->moduleTemplate->setContent($this->view->render());
+
+ return $this->htmlResponse($this->moduleTemplate->renderContent());
+ }
+
+ /**
+ * action show
+ *
+ * @param \VENDOR\Package\Domain\Model\DomainObject $domainObject
+ * @return \Psr\Http\Message\ResponseInterface
+ */
+ public function showAction(\VENDOR\Package\Domain\Model\DomainObject $domainObject): \Psr\Http\Message\ResponseInterface
+ {
+ $this->view->assign('domainObject', $domainObject);
+ $this->moduleTemplate->setContent($this->view->render());
+
+ return $this->htmlResponse($this->moduleTemplate->renderContent());
+ }
+
+ /**
+ * action new
+ *
+ * @return \Psr\Http\Message\ResponseInterface
+ */
+ public function newAction(): \Psr\Http\Message\ResponseInterface
+ {
+ $this->moduleTemplate->setContent($this->view->render());
+
+ return $this->htmlResponse($this->moduleTemplate->renderContent());
+ }
+
+ /**
+ * action create
+ *
+ * @param \VENDOR\Package\Domain\Model\DomainObject $newDomainObject
+ */
+ public function createAction(\VENDOR\Package\Domain\Model\DomainObject $newDomainObject): \Psr\Http\Message\ResponseInterface
+ {
+ $this->addFlashMessage('The object was created. Please be aware that this action is publicly accessible unless you implement an access check. See https://docs.typo3.org/p/friendsoftypo3/extension-builder/master/en-us/User/Index.html', '', \TYPO3\CMS\Core\Messaging\AbstractMessage::WARNING);
+ $this->domainObjectRepository->add($newDomainObject);
+ return $this->redirect('list');
+ }
+
+ /**
+ * action edit
+ *
+ * @param \VENDOR\Package\Domain\Model\DomainObject $domainObject
+ * @return \Psr\Http\Message\ResponseInterface
+ */
+ public function editAction(\VENDOR\Package\Domain\Model\DomainObject $domainObject): \Psr\Http\Message\ResponseInterface
+ {
+ $this->view->assign('domainObject', $domainObject);
+ $this->moduleTemplate->setContent($this->view->render());
+
+ return $this->htmlResponse($this->moduleTemplate->renderContent());
+ }
+
+ /**
+ * action update
+ *
+ * @param \VENDOR\Package\Domain\Model\DomainObject $domainObject
+ */
+ public function updateAction(\VENDOR\Package\Domain\Model\DomainObject $domainObject): \Psr\Http\Message\ResponseInterface
+ {
+ $this->addFlashMessage('The object was updated. Please be aware that this action is publicly accessible unless you implement an access check. See https://docs.typo3.org/p/friendsoftypo3/extension-builder/master/en-us/User/Index.html', '', \TYPO3\CMS\Core\Messaging\AbstractMessage::WARNING);
+ $this->domainObjectRepository->update($domainObject);
+ return $this->redirect('list');
+ }
+
+ /**
+ * action delete
+ *
+ * @param \VENDOR\Package\Domain\Model\DomainObject $domainObject
+ */
+ public function deleteAction(\VENDOR\Package\Domain\Model\DomainObject $domainObject): \Psr\Http\Message\ResponseInterface
+ {
+ $this->addFlashMessage('The object was deleted. Please be aware that this action is publicly accessible unless you implement an access check. See https://docs.typo3.org/p/friendsoftypo3/extension-builder/master/en-us/User/Index.html', '', \TYPO3\CMS\Core\Messaging\AbstractMessage::WARNING);
+ $this->domainObjectRepository->remove($domainObject);
+ return $this->redirect('list');
+ }
+
+ /**
+ * @return \Psr\Http\Message\ResponseInterface
+ */
+ public function genericAction(): \Psr\Http\Message\ResponseInterface
+ {
+ $this->moduleTemplate->setContent($this->view->render());
+
+ return $this->htmlResponse($this->moduleTemplate->renderContent());
+ }
+}
diff --git a/Resources/Private/CodeTemplates/Extbase/Classes/Controller/Controller.phpt b/Resources/Private/CodeTemplates/Extbase/Classes/Controller/FrontendController.phpt
similarity index 84%
rename from Resources/Private/CodeTemplates/Extbase/Classes/Controller/Controller.phpt
rename to Resources/Private/CodeTemplates/Extbase/Classes/Controller/FrontendController.phpt
index 03226e598..e09ec1af6 100644
--- a/Resources/Private/CodeTemplates/Extbase/Classes/Controller/Controller.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Classes/Controller/FrontendController.phpt
@@ -9,11 +9,25 @@ namespace VENDOR\Package\Controller;
*/
class MyController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
{
+ /**
+ * @var ModuleTemplate $moduleTemplate
+ */
+ protected ModuleTemplate $moduleTemplate;
+
+ /**
+ * @var ModuleTemplateFactory $moduleTemplateFactory
+ */
+ protected ModuleTemplateFactory $moduleTemplateFactory;
+
/**
* @var \VENDOR\Package\Domain\Repository\DomainObjectRepository
*/
protected $domainObjectRepository;
+ public function __construct() {
+
+ }
+
/**
* @param \VENDOR\Package\Domain\Repository\DomainObjectRepository
*/
@@ -22,6 +36,14 @@ class MyController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
$this->domainObjectRepository = $domainObjectRepository;
}
+ /**
+ * @return void
+ */
+ protected function initializeAction()
+ {
+
+ }
+
/**
* action list
*
@@ -31,6 +53,7 @@ class MyController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
{
$domainObjects = $this->domainObjectRepository->findAll();
$this->view->assign('domainObjects', $domainObjects);
+
return $this->htmlResponse();
}
@@ -43,6 +66,7 @@ class MyController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
public function showAction(\VENDOR\Package\Domain\Model\DomainObject $domainObject): \Psr\Http\Message\ResponseInterface
{
$this->view->assign('domainObject', $domainObject);
+
return $this->htmlResponse();
}
@@ -61,11 +85,11 @@ class MyController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
*
* @param \VENDOR\Package\Domain\Model\DomainObject $newDomainObject
*/
- public function createAction(\VENDOR\Package\Domain\Model\DomainObject $newDomainObject): void
+ public function createAction(\VENDOR\Package\Domain\Model\DomainObject $newDomainObject): \Psr\Http\Message\ResponseInterface
{
$this->addFlashMessage('The object was created. Please be aware that this action is publicly accessible unless you implement an access check. See https://docs.typo3.org/p/friendsoftypo3/extension-builder/master/en-us/User/Index.html', '', \TYPO3\CMS\Core\Messaging\AbstractMessage::WARNING);
$this->domainObjectRepository->add($newDomainObject);
- $this->redirect('list');
+ return $this->redirect('list');
}
/**
@@ -77,6 +101,7 @@ class MyController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
public function editAction(\VENDOR\Package\Domain\Model\DomainObject $domainObject): \Psr\Http\Message\ResponseInterface
{
$this->view->assign('domainObject', $domainObject);
+
return $this->htmlResponse();
}
@@ -85,11 +110,11 @@ class MyController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
*
* @param \VENDOR\Package\Domain\Model\DomainObject $domainObject
*/
- public function updateAction(\VENDOR\Package\Domain\Model\DomainObject $domainObject): void
+ public function updateAction(\VENDOR\Package\Domain\Model\DomainObject $domainObject): \Psr\Http\Message\ResponseInterface
{
$this->addFlashMessage('The object was updated. Please be aware that this action is publicly accessible unless you implement an access check. See https://docs.typo3.org/p/friendsoftypo3/extension-builder/master/en-us/User/Index.html', '', \TYPO3\CMS\Core\Messaging\AbstractMessage::WARNING);
$this->domainObjectRepository->update($domainObject);
- $this->redirect('list');
+ return $this->redirect('list');
}
/**
@@ -97,11 +122,11 @@ class MyController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
*
* @param \VENDOR\Package\Domain\Model\DomainObject $domainObject
*/
- public function deleteAction(\VENDOR\Package\Domain\Model\DomainObject $domainObject): void
+ public function deleteAction(\VENDOR\Package\Domain\Model\DomainObject $domainObject): \Psr\Http\Message\ResponseInterface
{
$this->addFlashMessage('The object was deleted. Please be aware that this action is publicly accessible unless you implement an access check. See https://docs.typo3.org/p/friendsoftypo3/extension-builder/master/en-us/User/Index.html', '', \TYPO3\CMS\Core\Messaging\AbstractMessage::WARNING);
$this->domainObjectRepository->remove($domainObject);
- $this->redirect('list');
+ return $this->redirect('list');
}
/**
@@ -111,5 +136,4 @@ class MyController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
{
return $this->htmlResponse();
}
-
}
diff --git a/Resources/Private/CodeTemplates/Extbase/Configuration/Backend/Modules.phpt b/Resources/Private/CodeTemplates/Extbase/Configuration/Backend/Modules.phpt
new file mode 100644
index 000000000..982b4dab3
--- /dev/null
+++ b/Resources/Private/CodeTemplates/Extbase/Configuration/Backend/Modules.phpt
@@ -0,0 +1,23 @@
+
+ '{backendModule.key}' => [
+ 'parent' => '{backendModule.mainModule}',
+ 'position' => ['bottom'],
+
+ 'access' => 'systemMaintainer',
+ 'access' => 'admin',
+ 'access' => 'user',
+
+ 'workspaces' => 'live',
+ 'path' => '/module/{extension.vendorName}/{backendModule.key}',
+ 'labels' => 'LLL:EXT:{extension.extensionKey}/Resources/Private/Language/locallang_{backendModule.key}.xlf',
+ 'extensionName' => '{extension.extensionName}',
+ 'controllerActions' => [
+ \{extension.namespaceName}\Controller\{controllerKey}Controller::class => [
+ '{action}'{f:if(condition: actionIterator.isLast, then: '', else: ',')}
+ ]{f:if(condition: controllerIterator.isLast, then: '', else: ',')}
+ ],
+ ],
+
+];
diff --git a/Resources/Private/CodeTemplates/Extbase/Configuration/Extbase/Persistence/Classes.phpt b/Resources/Private/CodeTemplates/Extbase/Configuration/Extbase/Persistence/Classes.phpt
index e7d695256..61e0b52a0 100644
--- a/Resources/Private/CodeTemplates/Extbase/Configuration/Extbase/Persistence/Classes.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Configuration/Extbase/Persistence/Classes.phpt
@@ -6,7 +6,7 @@ return ['tableName' => '{domainObject.databaseTableName}',
'properties' => [
- '{property.name}' => [
+ '{property.propertyName}' => [
'fieldName' => '{property.fieldName}'
],
]
diff --git a/Resources/Private/CodeTemplates/Extbase/Configuration/ExtensionBuilder/settings.yamlt b/Resources/Private/CodeTemplates/Extbase/Configuration/ExtensionBuilder/settings.yamlt
index 849f0b9bf..f371ca900 100644
--- a/Resources/Private/CodeTemplates/Extbase/Configuration/ExtensionBuilder/settings.yamlt
+++ b/Resources/Private/CodeTemplates/Extbase/Configuration/ExtensionBuilder/settings.yamlt
@@ -5,8 +5,6 @@
# See http://www.yaml.org/spec/1.2/spec.html
#
----
-
############# Overwrite settings ###########
#
# These settings only apply, if the roundtrip feature of the extension builder
@@ -17,11 +15,11 @@
# a setting applies to a file or recursive to all files and subfolders
#
# merge:
-# means for classes: All properties ,methods and method bodies
+# means for classes: All properties, methods and method bodies
# of the existing class will be modified according to the new settings
# but not overwritten
#
-# for locallang xlf files: Existing keys and labels are always
+# for locallang.xlf files: Existing keys and labels are always
# preserved (renaming a property or DomainObject will result in new keys and new labels)
#
# for other files: You will find a Split token at the end of the file
@@ -34,7 +32,7 @@
# files are never overwritten
# These settings may break the functionality of the extension builder!
# Handle with care!
-#
+
############# Extension settings ###########
@@ -46,7 +44,7 @@ overwriteSettings:
Repository: merge
Configuration:
- #TCA merge not possible - use overrides directory
+ # TCA merge not possible - use overrides directory
#TypoScript: keep
Resources:
@@ -61,15 +59,15 @@ overwriteSettings:
#Templates: keep
user_extension.svg: keep
-# ext_localconf.php: merge
-# ext_tables.php: merge
-# ext_tables.sql: merge
+ #ext_localconf.php: merge
+ #ext_tables.php: merge
+ #ext_tables.sql: merge
## add declare strict types in php files
declareStrictTypes: true
## use static date attribute in xliff files
-#staticDateInXliffFiles: '{f:format.date(format:'Y-m-d\TH:i:s\Z',date:'now')}'
+staticDateInXliffFiles: '{f:format.date(format:'Y-m-d\TH:i:s\Z',date:'now')}'
## skip docComment (license header)
#skipDocComment: false
diff --git a/Resources/Private/CodeTemplates/Extbase/Configuration/FlexForms/plugin_flexform.phpt b/Resources/Private/CodeTemplates/Extbase/Configuration/FlexForms/plugin_flexform.phpt
new file mode 100644
index 000000000..b8562246c
--- /dev/null
+++ b/Resources/Private/CodeTemplates/Extbase/Configuration/FlexForms/plugin_flexform.phpt
@@ -0,0 +1,24 @@
+
+
+
+ 1
+
+
+
+
+ Plugin Options
+ array
+
+
+
+
+ input
+ 50
+ trim
+
+
+
+
+
+
+
diff --git a/Resources/Private/CodeTemplates/Extbase/Configuration/Icons.phpt b/Resources/Private/CodeTemplates/Extbase/Configuration/Icons.phpt
index fb5426bb7..3cdc905a7 100644
--- a/Resources/Private/CodeTemplates/Extbase/Configuration/Icons.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Configuration/Icons.phpt
@@ -1,7 +1,7 @@
- '{extension.extensionKey}-plugin-{plugin.key}' => [
+ '{extension.shortExtensionKey}_{plugin.key}' => [
'provider' => \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class,
'source' => 'EXT:{extension.extensionKey}/Resources/Public/Icons/user_plugin_{plugin.key}.svg'
],
diff --git a/Resources/Private/CodeTemplates/Extbase/Configuration/Services.yamlt b/Resources/Private/CodeTemplates/Extbase/Configuration/Services.yamlt
new file mode 100644
index 000000000..ae4e5bfda
--- /dev/null
+++ b/Resources/Private/CodeTemplates/Extbase/Configuration/Services.yamlt
@@ -0,0 +1,10 @@
+services:
+ _defaults:
+ autowire: true
+ autoconfigure: true
+ public: false
+
+ {namespace}\:
+ resource: '../Classes/*'
+ exclude: '../Classes/Domain/Model/*'
+
diff --git a/Resources/Private/CodeTemplates/Extbase/Configuration/TCA/Overrides/tt_content.phpt b/Resources/Private/CodeTemplates/Extbase/Configuration/TCA/Overrides/tt_content.phpt
index d741350b6..a7b3c70ea 100644
--- a/Resources/Private/CodeTemplates/Extbase/Configuration/TCA/Overrides/tt_content.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Configuration/TCA/Overrides/tt_content.phpt
@@ -4,7 +4,54 @@ defined('TYPO3') || die();
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
'{extension.extensionName}',
- '{plugin.key -> k:format.uppercaseFirst()}',
- '{plugin.name -> k:format.quoteString()}'
+ '{plugin.key}',
+ '{plugin.name -> k:format.quoteString()}',
+ '{extension.unprefixedShortExtensionKey}_{plugin.key}'
);
+
+
+if (!is_array($GLOBALS['TCA']['tt_content']['types']['{extension.unprefixedShortExtensionKey}_{plugin.key}'] ?? false)) {
+ $GLOBALS['TCA']['tt_content']['types']['{extension.unprefixedShortExtensionKey}_{plugin.key}'] = [];
+}
+
+
+// Add content element to selector list
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTcaSelectItem(
+ 'tt_content',
+ 'CType',
+ [
+ 'label' => '{plugin.name -> k:format.quoteString()}',
+ 'value' => '{extension.unprefixedShortExtensionKey}_{plugin.key}',
+ 'icon' => '{extension.shortExtensionKey}_{plugin.key}',
+ 'group' => '{extension.extensionKey}'
+ ]
+);
+
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
+ '*',
+ 'FILE:EXT:{extension.extensionKey}/Configuration/FlexForms/flexform_{plugin.key}.xml',
+ '{extension.unprefixedShortExtensionKey}_{plugin.key}'
+);
+
+$GLOBALS['TCA']['tt_content']['types']['{extension.unprefixedShortExtensionKey}_{plugin.key}']['showitem'] = '
+ --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
+ --palette--;;general,
+ --palette--;;headers,
+ --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.plugin,
+ pi_flexform,
+ --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance,
+ --palette--;;frames,
+ --palette--;;appearanceLinks,
+ --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language,
+ --palette--;;language,
+ --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,
+ --palette--;;hidden,
+ --palette--;;access,
+ --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:categories,
+ categories,
+ --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:notes,
+ rowDescription,
+ --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:extended,
+';
diff --git a/Resources/Private/CodeTemplates/Extbase/Configuration/TCA/tableName.phpt b/Resources/Private/CodeTemplates/Extbase/Configuration/TCA/tableName.phpt
index dc9ab8332..d718609f5 100644
--- a/Resources/Private/CodeTemplates/Extbase/Configuration/TCA/tableName.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Configuration/TCA/tableName.phpt
@@ -4,8 +4,7 @@ return [
'title' => 'LLL:EXT:{extension.extensionKey}/Resources/Private/Language/locallang_db.xlf:{domainObject.databaseTableName}',
'label' => '{domainObject.listModuleValueLabel}',
'tstamp' => 'tstamp',
- 'crdate' => 'crdate',
- 'cruser_id' => 'cruser_id',
+ 'crdate' => 'crdate',
'sortby' => 'sorting',
'versioningWS' => true,
'languageField' => 'sys_language_uid',
@@ -18,7 +17,10 @@ return [
'endtime' => 'endtime',
],
'searchFields' => '{property.fieldName}{f:if(condition: it.isLast, else: ',')}',
- 'iconfile' => 'EXT:{domainObject.extension.extensionKey}/Resources/Public/Icons/{domainObject.databaseTableName}.gif'
+ 'iconfile' => 'EXT:{domainObject.extension.extensionKey}/Resources/Public/Icons/{domainObject.databaseTableName}.gif',
+ 'security' => [
+ 'ignorePageTypeRestriction' => true,
+ ],
],
'types' => [
'{domainObject.recordType}''1' => ['showitem' => '{property.fieldName}{f:if(condition: i.isLast, else: ', ')}, --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language, sys_language_uid, l10n_parent, l10n_diffsource, --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access, hidden, starttime, endtime'],
@@ -39,7 +41,7 @@ return [
'renderType' => 'selectSingle',
'default' => 0,
'items' => [
- ['', 0],
+ ['label' => '', 'value' => 0],
],
'foreign_table' => '{domainObject.databaseTableName}',
'foreign_table_where' => 'AND #{domainObject.databaseTableName}.#pid=###CURRENT_PID### AND #{domainObject.databaseTableName}.#sys_language_uid IN (-1,0)',
@@ -58,8 +60,7 @@ return [
'renderType' => 'checkboxToggle',
'items' => [
[
- 0 => '',
- 1 => '',
+ 'label' => '',
'invertStateDisplay' => true
]
],
@@ -69,9 +70,8 @@ return [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.starttime',
'config' => [
- 'type' => 'input',
- 'renderType' => 'inputDateTime',
- 'eval' => 'datetime,int',
+ 'type' => 'datetime',
+ 'format' => 'datetime',
'default' => 0,
'behaviour' => [
'allowLanguageSynchronization' => true
@@ -82,9 +82,8 @@ return [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.endtime',
'config' => [
- 'type' => 'input',
- 'renderType' => 'inputDateTime',
- 'eval' => 'datetime,int',
+ 'type' => 'datetime',
+ 'format' => 'datetime',
'default' => 0,
'range' => [
'upper' => mktime(0, 0, 0, 1, 1, 2038)
diff --git a/Resources/Private/CodeTemplates/Extbase/Configuration/TypoScript/setup.typoscriptt b/Resources/Private/CodeTemplates/Extbase/Configuration/TypoScript/setup.typoscriptt
index a36e5710e..28bed017e 100644
--- a/Resources/Private/CodeTemplates/Extbase/Configuration/TypoScript/setup.typoscriptt
+++ b/Resources/Private/CodeTemplates/Extbase/Configuration/TypoScript/setup.typoscriptt
@@ -22,45 +22,9 @@
}
-
-# these classes are only used in auto-generated templates
-plugin.{extension.shortExtensionKey}._CSS_DEFAULT_STYLE (
- textarea.f3-form-error {
- background-color: #FF9F9F;
- border: 1px #FF0000 solid;
- }
-
- input.f3-form-error {
- background-color: #FF9F9F;
- border: 1px #FF0000 solid;
- }
-
- .{extension.cssClassName} table {
- border-collapse: separate;
- border-spacing: 10px;
- }
-
- .{extension.cssClassName} table th {
- font-weight: bold;
- }
-
- .{extension.cssClassName} table td {
- vertical-align: top;
- }
-
- .typo3-messages .message-error {
- color: red;
- }
-
- .typo3-messages .message-ok {
- color: green;
- }
-)
-
-
# Module configuration
-module.{extension.shortExtensionKey}_{backendModule.mainModule}_{extension.unprefixedShortExtensionKey}{backendModule.key} {
+module.{extension.shortExtensionKey}_{backendModule.key} {
persistence {
storagePid = $module.{extension.shortExtensionKey}_{backendModule.key}.persistence.storagePid
}
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/BooleanProperty.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/BooleanProperty.htmlt
index 3f28f91c7..89cdc81c2 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/BooleanProperty.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/BooleanProperty.htmlt
@@ -1 +1 @@
-f:form.checkbox property="{property.name}" id="{property.name}" value="1"
\ No newline at end of file
+f:form.checkbox property="{property.propertyName}" id="{property.propertyName}" class="form-check-input" value="1"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/ColorPickerProperty.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/ColorPickerProperty.htmlt
index eb4a681f8..00d682cd6 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/ColorPickerProperty.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/ColorPickerProperty.htmlt
@@ -1 +1 @@
-f:form.textfield type="color" property="{property.name}" id="{property.name}"
\ No newline at end of file
+f:form.textfield type="color" property="{property.propertyName}" id="{property.propertyName}" class="form-control"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/DateProperty.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/DateProperty.htmlt
index 6a1d693bc..3425983ad 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/DateProperty.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/DateProperty.htmlt
@@ -1 +1 @@
-{namespace k=EBT\ExtensionBuilder\ViewHelpers}f:form.textfield property="{property.name}" id="{property.name}" value="{domainObject.name-> k:format.lowercaseFirst()}.{property.name}->f:format.date()"
\ No newline at end of file
+{namespace k=EBT\ExtensionBuilder\ViewHelpers}f:form.textfield property="{property.propertyName}" id="{property.propertyName}" class="form-control" value="{domainObject.name-> k:format.lowercaseFirst()}.{property.propertyName}->f:format.date()"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/DateTimeProperty.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/DateTimeProperty.htmlt
index 6a1d693bc..3425983ad 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/DateTimeProperty.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/DateTimeProperty.htmlt
@@ -1 +1 @@
-{namespace k=EBT\ExtensionBuilder\ViewHelpers}f:form.textfield property="{property.name}" id="{property.name}" value="{domainObject.name-> k:format.lowercaseFirst()}.{property.name}->f:format.date()"
\ No newline at end of file
+{namespace k=EBT\ExtensionBuilder\ViewHelpers}f:form.textfield property="{property.propertyName}" id="{property.propertyName}" class="form-control" value="{domainObject.name-> k:format.lowercaseFirst()}.{property.propertyName}->f:format.date()"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/EmailProperty.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/EmailProperty.htmlt
index 4496f1d40..1ca923d2f 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/EmailProperty.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/EmailProperty.htmlt
@@ -1 +1 @@
-f:form.textfield type="email" property="{property.name}" id="{property.name}"
\ No newline at end of file
+f:form.textfield type="email" property="{property.propertyName}" id="{property.propertyName}" class="form-control"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/FloatProperty.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/FloatProperty.htmlt
index e845fbebf..4f4465e14 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/FloatProperty.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/FloatProperty.htmlt
@@ -1 +1 @@
-f:form.textfield property="{property.name}" id="{property.name}"
\ No newline at end of file
+f:form.textfield property="{property.propertyName}" id="{property.propertyName}" class="form-control"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/InputLinkProperty.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/InputLinkProperty.htmlt
index e845fbebf..2f13497eb 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/InputLinkProperty.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/InputLinkProperty.htmlt
@@ -1 +1 @@
-f:form.textfield property="{property.name}" id="{property.name}"
\ No newline at end of file
+f:form.textfield property="{property.propertyName}" id="{property.propertyName}"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/IntegerProperty.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/IntegerProperty.htmlt
index e845fbebf..4f4465e14 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/IntegerProperty.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/IntegerProperty.htmlt
@@ -1 +1 @@
-f:form.textfield property="{property.name}" id="{property.name}"
\ No newline at end of file
+f:form.textfield property="{property.propertyName}" id="{property.propertyName}" class="form-control"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/NativeDateProperty.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/NativeDateProperty.htmlt
index 306cba4cb..623e56b20 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/NativeDateProperty.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/NativeDateProperty.htmlt
@@ -1 +1 @@
-{namespace k=EBT\ExtensionBuilder\ViewHelpers}f:form.textfield property="{property.name}" id="{property.name}" value="{domainObject.name-> k:format.lowercaseFirst()}.{property.name}->f:format.date()"
\ No newline at end of file
+{namespace k=EBT\ExtensionBuilder\ViewHelpers}f:form.textfield property="{property.propertyName}" id="{property.propertyName}" class="form-control" value="{domainObject.name-> k:format.lowercaseFirst()}.{property.propertyName}->f:format.date()"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/NativeDateTimeProperty.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/NativeDateTimeProperty.htmlt
index 306cba4cb..623e56b20 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/NativeDateTimeProperty.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/NativeDateTimeProperty.htmlt
@@ -1 +1 @@
-{namespace k=EBT\ExtensionBuilder\ViewHelpers}f:form.textfield property="{property.name}" id="{property.name}" value="{domainObject.name-> k:format.lowercaseFirst()}.{property.name}->f:format.date()"
\ No newline at end of file
+{namespace k=EBT\ExtensionBuilder\ViewHelpers}f:form.textfield property="{property.propertyName}" id="{property.propertyName}" class="form-control" value="{domainObject.name-> k:format.lowercaseFirst()}.{property.propertyName}->f:format.date()"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/NativeTimeProperty.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/NativeTimeProperty.htmlt
index 066977a59..76107d85c 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/NativeTimeProperty.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/NativeTimeProperty.htmlt
@@ -1 +1 @@
-{namespace k=EBT\ExtensionBuilder\ViewHelpers}f:form.textfield property="{property.name}" value="{domainObject.name-> k:format.lowercaseFirst()}.{property.name}->f:format.date()"
\ No newline at end of file
+{namespace k=EBT\ExtensionBuilder\ViewHelpers}f:form.textfield property="{property.propertyName}" class="form-control" value="{domainObject.name-> k:format.lowercaseFirst()}.{property.propertyName}->f:format.date()"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/NoneProperty.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/NoneProperty.htmlt
index c999a7712..b2d4ac8ec 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/NoneProperty.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/NoneProperty.htmlt
@@ -1 +1 @@
-f:form.textfield property="{property.name}" id="{property.name}" readonly="1"
\ No newline at end of file
+f:form.textfield property="{property.propertyName}" id="{property.propertyName}" readonly="1"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/PasswordProperty.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/PasswordProperty.htmlt
index 43a26c011..3f5069cac 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/PasswordProperty.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/PasswordProperty.htmlt
@@ -1 +1 @@
-f:form.password property="{property.name}" id="{property.name}"
\ No newline at end of file
+f:form.password property="{property.propertyName}" id="{property.propertyName}" class="form-control"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/Relation_ManyToManyRelation.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/Relation_ManyToManyRelation.htmlt
index e845fbebf..2f13497eb 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/Relation_ManyToManyRelation.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/Relation_ManyToManyRelation.htmlt
@@ -1 +1 @@
-f:form.textfield property="{property.name}" id="{property.name}"
\ No newline at end of file
+f:form.textfield property="{property.propertyName}" id="{property.propertyName}"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/Relation_ZeroToManyRelation.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/Relation_ZeroToManyRelation.htmlt
index e845fbebf..2f13497eb 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/Relation_ZeroToManyRelation.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/Relation_ZeroToManyRelation.htmlt
@@ -1 +1 @@
-f:form.textfield property="{property.name}" id="{property.name}"
\ No newline at end of file
+f:form.textfield property="{property.propertyName}" id="{property.propertyName}"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/Relation_ZeroToOneRelation.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/Relation_ZeroToOneRelation.htmlt
index e845fbebf..2f13497eb 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/Relation_ZeroToOneRelation.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/Relation_ZeroToOneRelation.htmlt
@@ -1 +1 @@
-f:form.textfield property="{property.name}" id="{property.name}"
\ No newline at end of file
+f:form.textfield property="{property.propertyName}" id="{property.propertyName}"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/RichTextProperty.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/RichTextProperty.htmlt
index 46b407102..f6311fc36 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/RichTextProperty.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/RichTextProperty.htmlt
@@ -1 +1 @@
-f:form.textarea property="{property.name}" id="{property.name}" cols="40" rows="15"
\ No newline at end of file
+f:form.textarea property="{property.propertyName}" id="{property.propertyName}" cols="40" rows="15" class="form-control"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/SelectProperty.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/SelectProperty.htmlt
index e845fbebf..76b0761c1 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/SelectProperty.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/SelectProperty.htmlt
@@ -1 +1 @@
-f:form.textfield property="{property.name}" id="{property.name}"
\ No newline at end of file
+f:form.textfield property="{property.propertyName}" id="{property.propertyName}" class="form-select"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/SlugProperty.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/SlugProperty.htmlt
index e845fbebf..4f4465e14 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/SlugProperty.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/SlugProperty.htmlt
@@ -1 +1 @@
-f:form.textfield property="{property.name}" id="{property.name}"
\ No newline at end of file
+f:form.textfield property="{property.propertyName}" id="{property.propertyName}" class="form-control"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/StringProperty.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/StringProperty.htmlt
index e845fbebf..4f4465e14 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/StringProperty.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/StringProperty.htmlt
@@ -1 +1 @@
-f:form.textfield property="{property.name}" id="{property.name}"
\ No newline at end of file
+f:form.textfield property="{property.propertyName}" id="{property.propertyName}" class="form-control"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/TextProperty.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/TextProperty.htmlt
index 46b407102..029f09dc7 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/TextProperty.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/TextProperty.htmlt
@@ -1 +1 @@
-f:form.textarea property="{property.name}" id="{property.name}" cols="40" rows="15"
\ No newline at end of file
+f:form.textarea property="{property.propertyName}" id="{property.propertyName}" class="form-control" cols="40" rows="15"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/TimeProperty.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/TimeProperty.htmlt
index 6a1d693bc..3425983ad 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/TimeProperty.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/TimeProperty.htmlt
@@ -1 +1 @@
-{namespace k=EBT\ExtensionBuilder\ViewHelpers}f:form.textfield property="{property.name}" id="{property.name}" value="{domainObject.name-> k:format.lowercaseFirst()}.{property.name}->f:format.date()"
\ No newline at end of file
+{namespace k=EBT\ExtensionBuilder\ViewHelpers}f:form.textfield property="{property.propertyName}" id="{property.propertyName}" class="form-control" value="{domainObject.name-> k:format.lowercaseFirst()}.{property.propertyName}->f:format.date()"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Form/TimeSecProperty.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Form/TimeSecProperty.htmlt
index 6a1d693bc..3425983ad 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Form/TimeSecProperty.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Form/TimeSecProperty.htmlt
@@ -1 +1 @@
-{namespace k=EBT\ExtensionBuilder\ViewHelpers}f:form.textfield property="{property.name}" id="{property.name}" value="{domainObject.name-> k:format.lowercaseFirst()}.{property.name}->f:format.date()"
\ No newline at end of file
+{namespace k=EBT\ExtensionBuilder\ViewHelpers}f:form.textfield property="{property.propertyName}" id="{property.propertyName}" class="form-control" value="{domainObject.name-> k:format.lowercaseFirst()}.{property.propertyName}->f:format.date()"
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/Property.htmlt b/Resources/Private/CodeTemplates/Extbase/Partials/Property.htmlt
index 156ea0342..43bd96e7f 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/Property.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/Property.htmlt
@@ -1,27 +1,27 @@
-{namespace k=EBT\ExtensionBuilder\ViewHelpers}{escaping off}
+{namespace k=EBT\ExtensionBuilder\ViewHelpers}{escaping off}
- f:for each="{domainObject.name -> k:format.lowercaseFirst()}.{property.name}" as="image"
+ f:for each="{domainObject.name -> k:format.lowercaseFirst()}.{property.propertyName}" as="image" f:image src="image.originalResource.publicUrl" width="200"//f:for
- f:image src="{domainObject.name -> k:format.lowercaseFirst()}.{property.name}.originalResource.publicUrl" width="200"/
+ f:image src="{domainObject.name -> k:format.lowercaseFirst()}.{property.propertyName}.originalResource.publicUrl" width="200"/
- f:for each="{domainObject.name -> k:format.lowercaseFirst()}.{property.name}" as="file"
+ f:for each="{domainObject.name -> k:format.lowercaseFirst()}.{property.propertyName}" as="file" file.originalResource.name/f:for
-
- {domainObject.name -> k:format.lowercaseFirst()}.{property.name}.originalResource.name
+
+ {domainObject.name -> k:format.lowercaseFirst()}.{property.propertyName}.originalResource.name
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/BooleanProperty.phpt b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/BooleanProperty.phpt
index 7270c85d0..4db277fde 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/BooleanProperty.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/BooleanProperty.phpt
@@ -1,11 +1,8 @@
[
- 'type' => 'check',
- 'renderType' => 'checkboxToggle',
- 'items' => [
- [
- 0 => '',
- 1 => '',
- ]
- ],
+ 'type' => 'check',
+ 'renderType' => '{property.renderTypeBoolean}',
+ 'items' => [
+ ['label' => '{value}'],
+ ],
'default' => 0,
]
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/ColorPickerProperty.phpt b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/ColorPickerProperty.phpt
index 57f473e73..3eb3f9eed 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/ColorPickerProperty.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/ColorPickerProperty.phpt
@@ -1,7 +1,12 @@
[
- 'type' => 'input',
- 'size' => 10,
- 'renderType' => 'colorpicker',
- 'eval' => 'required',
- 'default' => ''
+ 'type' => 'color',
+ 'size' => 30,
+ 'required' => true,
+ 'nullable' => true,
+ 'default' => '',
+ 'valuePicker' => [
+ 'items' => [
+ ['{label}', '{value}'],
+ ],
+ ],
]
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/DateProperty.phpt b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/DateProperty.phpt
index 40e242ae6..74c1fc182 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/DateProperty.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/DateProperty.phpt
@@ -1,7 +1,7 @@
[
'type' => 'input',
'renderType' => 'inputDateTime',
- 'size' => 7,
+ 'size' => 30,
'eval' => 'date,required,null',
'default' => nulltime()
],
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/DateTimeProperty.phpt b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/DateTimeProperty.phpt
index 8ba11982f..79e5ba821 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/DateTimeProperty.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/DateTimeProperty.phpt
@@ -1,7 +1,8 @@
[
- 'type' => 'input',
- 'renderType' => 'inputDateTime',
- 'size' => 10,
- 'eval' => 'datetime,required,null',
+ 'type' => 'datetime',
+ 'format' => '{property.formatDateTime}',
+ 'size' => 20,
+ 'required' => true,
+ 'nullable' => true,
'default' => nulltime()
],
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/EmailProperty.phpt b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/EmailProperty.phpt
index 6187833d1..602bb3df4 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/EmailProperty.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/EmailProperty.phpt
@@ -1,6 +1,6 @@
[
- 'type' => 'input',
- 'size' => 30,
- 'eval' => 'nospace,email,required,null',
+ 'type' => 'email',
+ 'required' => true,
+ 'nullable' => true,
'default' => null''
]
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/FileProperty.phpt b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/FileProperty.phpt
index d3f72280e..151028f1d 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/FileProperty.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/FileProperty.phpt
@@ -1,50 +1,7 @@
-\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig(
- '{property.fieldName}',
- [
- 'appearance' => [
- 'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:media.addFileReference'
- ],
- 'overrideChildTca' => [
- 'types' => [
- '0' => [
- 'showitem' => '
- --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
- --palette--;;filePalette'
- ],
- \TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => [
- 'showitem' => '
- --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
- --palette--;;filePalette'
- ],
- \TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [
- 'showitem' => '
- --palette--;;imageoverlayPalette,
- --palette--;;filePalette',
- ],
- \TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => [
- 'showitem' => '
- --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
- --palette--;;filePalette'
- ],
- \TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => [
- 'showitem' => '
- --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
- --palette--;;filePalette'
- ],
- \TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => [
- 'showitem' => '
- --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
- --palette--;;filePalette'
- ]
- ],
- ],
- 'foreign_match_fields' => [
- 'fieldname' => '{property.fieldName}',
- 'tablenames' => '{property.domainObject.databaseTableName}',
- 'table_local' => 'sys_file',
- ],
- 'maxitems' => {property.maxItems},
- 'minitems' => 1
- ],
- '{property.allowedFileTypes}'
-),
+[
+ 'type' => 'file',
+ 'allowed' => '{property.allowedFileTypes}',
+ 'allowed' => 'common-image-types',
+ 'minitems' => {property.minItems},
+ 'maxitems' => {property.maxItems},
+],
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/FloatProperty.phpt b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/FloatProperty.phpt
index f2decc7e8..ad4a8ad2c 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/FloatProperty.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/FloatProperty.phpt
@@ -1,5 +1,15 @@
[
- 'type' => 'input',
- 'size' => 30,
- 'eval' => 'double2,required,null'
+ 'type' => 'number',
+ 'format' => 'decimal',
+ 'size' => 30,
+ 'required' => true,
+ 'nullable' => true,
+ 'slider' => [
+ 'step' => {property.steps}
+ ],
+ 'range' => [
+ 'lower' => {property.lowerRange},
+ 'upper' => {property.upperRange}
+ ],
+ 'default' => null0
]
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/InputLinkProperty.phpt b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/InputLinkProperty.phpt
index 614029d64..03800fee2 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/InputLinkProperty.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/InputLinkProperty.phpt
@@ -1,4 +1,3 @@
[
- 'type' => 'input',
- 'renderType' => 'inputLink',
+ 'type' => 'link',
]
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/IntegerProperty.phpt b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/IntegerProperty.phpt
index aebbfaba2..54b7eda81 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/IntegerProperty.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/IntegerProperty.phpt
@@ -1,6 +1,14 @@
[
- 'type' => 'input',
- 'size' => 4,
- 'eval' => 'int,required,null',
+ 'type' => 'number',
+ 'size' => 30,
+ 'required' => true,
+ 'nullable' => true,
+ 'slider' => [
+ 'step' => {property.steps}
+ ],
+ 'range' => [
+ 'lower' => {property.lowerRange},
+ 'upper' => {property.upperRange}
+ ],
'default' => null0
]
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/NativeDateProperty.phpt b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/NativeDateProperty.phpt
index 1a31396e6..261643404 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/NativeDateProperty.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/NativeDateProperty.phpt
@@ -2,7 +2,7 @@
'dbType' => 'date',
'type' => 'input',
'renderType' => 'inputDateTime',
- 'size' => 7,
+ 'size' => 30,
'eval' => 'date,required,null',
'default' => null,
],
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/NativeDateTimeProperty.phpt b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/NativeDateTimeProperty.phpt
index ab6ee756a..8a257658b 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/NativeDateTimeProperty.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/NativeDateTimeProperty.phpt
@@ -2,7 +2,7 @@
'dbType' => 'datetime',
'type' => 'input',
'renderType' => 'inputDateTime',
- 'size' => 12,
+ 'size' => 30,
'eval' => 'datetime,required,null',
'default' => null,
],
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/NativeTimeProperty.phpt b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/NativeTimeProperty.phpt
index 2e14e6719..b678de9dd 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/NativeTimeProperty.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/NativeTimeProperty.phpt
@@ -2,7 +2,7 @@
'type' => 'input',
'renderType' => 'inputDateTime',
'dbType' => 'time',
- 'size' => 4,
+ 'size' => 30,
'eval' => 'time,required,null',
'default' => null
]
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/PasswordProperty.phpt b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/PasswordProperty.phpt
index bc7996c9e..f73326ab0 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/PasswordProperty.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/PasswordProperty.phpt
@@ -1,6 +1,12 @@
[
- 'type' => 'input',
- 'size' => 30,
- 'eval' => 'nospace,password,required,null',
+ 'type' => 'password',
+ 'required' => true,
+ 'nullable' => true,
+ 'hashed' => true,
+ 'fieldControl' => [
+ 'passwordGenerator' => [
+ 'renderType' => 'passwordGenerator',
+ ],
+ ],
'default' => null''
]
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/PropertiesDefinition.phpt b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/PropertiesDefinition.phpt
index 257f93b1f..560a41605 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/PropertiesDefinition.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/PropertiesDefinition.phpt
@@ -2,7 +2,7 @@
{escaping off}
'{property.fieldName}' => [
- 'exclude' => truefalse,
+ 'exclude' => truefalse,
'l10n_mode' => 'exclude',
'label' => 'LLL:EXT:{domainObject.extension.extensionKey}/Resources/Private/Language/locallang_db.xlf:{property.labelNamespace}',
'description' => 'LLL:EXT:{domainObject.extension.extensionKey}/Resources/Private/Language/locallang_db.xlf:{property.descriptionNamespace}',
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/SelectProperty.phpt b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/SelectProperty.phpt
index 9144c3440..5168fb3b6 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/SelectProperty.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/SelectProperty.phpt
@@ -1,10 +1,16 @@
[
- 'type' => 'select',
- 'renderType' => 'selectSingle',
+ 'type' => 'select',
+ 'renderType' => '{property.renderType}',
+ 'renderType' => 'selectSingle',
'items' => [
- ['-- Label --', 0],
- ],
- 'size' => 1,
- 'maxitems' => 1,
- 'eval' => 'required'
+ ['Default', 0],
+ ['{label}', '{value}'],
+ ],
+ 'foreign_table' => '{property.foreignTable}',
+ 'foreign_table_where' => '{property.whereClause}',
+ 'size' => {property.size},
+ 'size' => 5,
+ 'minitems' => {property.minitems},
+ 'maxitems' => {property.maxitems},
+ 'required' => true
],
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/StringProperty.phpt b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/StringProperty.phpt
index 4e982c9cf..e4b8a96fb 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/StringProperty.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/StringProperty.phpt
@@ -1,6 +1,7 @@
[
- 'type' => 'input',
- 'size' => 30,
- 'eval' => 'trim,required,null',
+ 'type' => 'input',
+ 'size' => {property.size},
+ 'eval' => 'trim,null',
+ 'required' => true,
'default' => null''
],
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/TextProperty.phpt b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/TextProperty.phpt
index 4cff54d95..f5ae3c1aa 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/TextProperty.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/TextProperty.phpt
@@ -1,7 +1,8 @@
[
- 'type' => 'text',
- 'cols' => 40,
- 'rows' => 15,
- 'eval' => 'trim,required,null',
+ 'type' => 'text',
+ 'enableRichtext' => 'true',
+ 'rows' => {property.rows},
+ 'eval' => 'trim,null',
+ 'required' => true,
'default' => null''
]
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/TimeProperty.phpt b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/TimeProperty.phpt
index d7f21e89b..9255387fb 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/TimeProperty.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/TimeProperty.phpt
@@ -1,7 +1,7 @@
[
'type' => 'input',
'renderType' => 'inputDateTime',
- 'size' => 4,
+ 'size' => 30,
'eval' => 'time,required,null',
'default' => time()
]
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/TimeSecProperty.phpt b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/TimeSecProperty.phpt
index 977b2fe1f..896352f7b 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/TimeSecProperty.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/TimeSecProperty.phpt
@@ -1,7 +1,7 @@
[
'type' => 'input',
'renderType' => 'inputDateTime',
- 'size' => 6,
+ 'size' => 30,
'eval' => 'timesec,required,null',
'default' => nulltime()
]
\ No newline at end of file
diff --git a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/ZeroToManyRelation.phpt b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/ZeroToManyRelation.phpt
index 65c7c142a..6c4e37af2 100644
--- a/Resources/Private/CodeTemplates/Extbase/Partials/TCA/ZeroToManyRelation.phpt
+++ b/Resources/Private/CodeTemplates/Extbase/Partials/TCA/ZeroToManyRelation.phpt
@@ -1,6 +1,6 @@
-
+For files or images
-
+[
'type' => 'select',
'renderType' => '{property.renderType}',
diff --git a/Resources/Private/CodeTemplates/Extbase/Resources/Private/Backend/Layouts/default.htmlt b/Resources/Private/CodeTemplates/Extbase/Resources/Private/Backend/Layouts/default.htmlt
index 48c6d900c..cb96974e1 100644
--- a/Resources/Private/CodeTemplates/Extbase/Resources/Private/Backend/Layouts/default.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Resources/Private/Backend/Layouts/default.htmlt
@@ -2,24 +2,5 @@
xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
xmlns:be="http://typo3.org/ns/TYPO3/CMS/Backend/ViewHelpers"
data-namespace-typo3-fluid="true"
-
-be:moduleLayout
- f:be.pageRenderer /
-
- be:moduleLayout.menu identifier="ModuleMenu"
-
-
- be:moduleLayout.menuItem label="Overview" uri="f:uri.action(controller: '{domainObject.name}', action: 'list')" /
-
- be:moduleLayout.menuItem label="Create new {domainObject.name}" uri="f:uri.action(controller: '{domainObject.name}', action: 'new')" /
-
-
-
- /be:moduleLayout.menu
-
- f:render section="Buttons" /
- be:moduleLayout.button.shortcutButton displayName="Shortcut" /
-
f:render section="Content" /
-/be:moduleLayout/html
diff --git a/Resources/Private/CodeTemplates/Extbase/Resources/Private/Backend/Partials/formFields.htmlt b/Resources/Private/CodeTemplates/Extbase/Resources/Private/Backend/Partials/formFields.htmlt
index 8aedc84a1..d639c0ab3 100644
--- a/Resources/Private/CodeTemplates/Extbase/Resources/Private/Backend/Partials/formFields.htmlt
+++ b/Resources/Private/CodeTemplates/Extbase/Resources/Private/Backend/Partials/formFields.htmlt
@@ -2,7 +2,7 @@
-