Skip to content

Commit 0780b29

Browse files
Release v2.0.0 for TYPO3 14
Release 2.0.0
1 parent 6358a59 commit 0780b29

81 files changed

Lines changed: 2366 additions & 1464 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/Documentation export-ignore
2+
/.* export-ignore

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
*.swp
44
.DS_Store
55
*.vscode
6+
.idea/
7+
.claude/
68
.Build/
79
composer.lock
810
Documentation-GENERATED-temp/
@@ -15,4 +17,3 @@ Documentation-GENERATED-temp/
1517
/Documentation-GENERATED-temp/*
1618
.php_cs.cache
1719
.php-cs-fixer.cache
18-
composer.lock
Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
11
<?php
22

3-
declare(strict_types=1);
4-
53
/*
64
* This file is part of the "lia_form" Extension for TYPO3 CMS.
75
*
86
* For the full copyright and license information, please read the
97
* LICENSE.txt file that was distributed with this source code.
108
*/
119

10+
declare(strict_types=1);
11+
1212
namespace LIA\LiaForm\Domain\Factory;
1313

1414
use LIA\LiaForm\Event\BeforeFormDefinitionCreatesEvent;
15-
use LIA\LiaForm\Services\ServerRequestService;
1615
use Psr\Http\Message\ServerRequestInterface;
17-
use TYPO3\CMS\Core\EventDispatcher\EventDispatcher;
1816
use TYPO3\CMS\Form\Domain\Exception\RenderingException;
1917
use TYPO3\CMS\Form\Domain\Factory\ArrayFormFactory;
2018
use TYPO3\CMS\Form\Domain\Model\FormDefinition;
2119

2220
/**
2321
* This Factory build the FormDefinition object and returns it.
2422
* It also dispatch an event to manipulate the form configuration.
23+
*
24+
* Note: EventDispatcher is injected via parent class AbstractFormFactory::injectEventDispatcher().
25+
* This class uses the inherited $this->eventDispatcher property.
2526
*/
2627
class ExtendedArrayFormFactory extends ArrayFormFactory
2728
{
@@ -30,21 +31,35 @@ class ExtendedArrayFormFactory extends ArrayFormFactory
3031
*/
3132
private static int $renderedForms = 0;
3233

33-
public function __construct(private readonly EventDispatcher $eventDispatcher) {}
34-
3534
/**
3635
* Build a form definition by given configuration array.
3736
*
37+
* @param array<string, mixed> $configuration The form configuration
3838
* @throws RenderingException
39+
* @throws \RuntimeException If no request is available
3940
*/
40-
public function build(array $configuration, ?string $prototypeName = null, ?ServerRequestInterface $request = null): FormDefinition
41-
{
41+
public function build(
42+
array $configuration,
43+
?string $prototypeName = null,
44+
?ServerRequestInterface $request = null
45+
): FormDefinition {
4246
self::$renderedForms++;
43-
$eventDispatcher = $this->eventDispatcher;
44-
$event = $eventDispatcher->dispatch(
47+
48+
// Use provided request or fall back to GLOBALS (only in edge cases)
49+
$serverRequest = $request ?? $this->getServerRequestFromGlobals();
50+
51+
if ($this->eventDispatcher === null) {
52+
throw new \RuntimeException(
53+
'EventDispatcher not injected. Ensure DI is configured correctly.',
54+
1709391236
55+
);
56+
}
57+
58+
/** @var BeforeFormDefinitionCreatesEvent $event */
59+
$event = $this->eventDispatcher->dispatch(
4560
new BeforeFormDefinitionCreatesEvent(
4661
$configuration,
47-
ServerRequestService::getServerRequest(),
62+
$serverRequest,
4863
self::$renderedForms
4964
)
5065
);
@@ -53,4 +68,26 @@ public function build(array $configuration, ?string $prototypeName = null, ?Serv
5368

5469
return parent::build($configuration, $prototypeName);
5570
}
71+
72+
/**
73+
* Get server request from GLOBALS as fallback.
74+
*
75+
* This is only used when no request is passed to build().
76+
* In normal TYPO3 frontend rendering, the request is always available.
77+
*
78+
* @throws \RuntimeException If no valid server request is available
79+
*/
80+
private function getServerRequestFromGlobals(): ServerRequestInterface
81+
{
82+
$request = $GLOBALS['TYPO3_REQUEST'] ?? null;
83+
84+
if (!$request instanceof ServerRequestInterface) {
85+
throw new \RuntimeException(
86+
'No valid server request available. ExtendedArrayFormFactory requires a ServerRequestInterface.',
87+
1709391235
88+
);
89+
}
90+
91+
return $request;
92+
}
5693
}
Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
<?php
22

3+
/*
4+
* This file is part of the "LIA Form" Extension for TYPO3 CMS.
5+
*
6+
* For the full copyright and license information, please read the
7+
* LICENSE.txt file that was distributed with this source code.
8+
*/
9+
310
declare(strict_types=1);
411

512
namespace LIA\LiaForm\Domain\Model\FormElements;
@@ -9,20 +16,52 @@
916
use TYPO3\CMS\Core\Utility\GeneralUtility;
1017
use TYPO3\CMS\Form\Domain\Model\FormElements\AbstractFormElement;
1118

19+
/**
20+
* Form element for phone number with area code selection.
21+
*
22+
* Loads area codes from JSON configuration and allows event-based
23+
* customization of the data source.
24+
*
25+
* Note: This class uses GeneralUtility::makeInstance() for EventDispatcher because
26+
* Form Framework form elements are instantiated via the form factory without DI support.
27+
* This is a documented TYPO3 Form Framework limitation.
28+
*
29+
* @author LOUIS INTERNET <devs@louis.info>
30+
*/
1231
class PhoneAndAreaCodeElement extends AbstractFormElement
1332
{
14-
public function initializeFormElement()
33+
/**
34+
* Initialize the form element.
35+
*
36+
* Loads phone area codes from JSON file and sets them as options.
37+
*/
38+
public function initializeFormElement(): void
1539
{
1640
$dispatcher = GeneralUtility::makeInstance(EventDispatcher::class);
17-
$event = new BeforePhoneAreaCodeInitializeEvent('EXT:lia_form/Configuration/Data/PhoneAreaCodeList.json');
41+
$event = new BeforePhoneAreaCodeInitializeEvent(
42+
'EXT:lia_form/Configuration/Data/PhoneAreaCodeList.json'
43+
);
1844
$dispatcher->dispatch($event);
1945
$dataSourcePath = $event->getDataSourcePath();
2046

21-
if (str_starts_with($dataSourcePath, 'EXT')) {
22-
$dataSourcePath = GeneralUtility::getFileAbsFileName($dataSourcePath);
47+
// Security: Only EXT: paths are allowed to prevent path traversal attacks
48+
if (!str_starts_with($dataSourcePath, 'EXT:')) {
49+
throw new \InvalidArgumentException(
50+
'Only EXT: paths are allowed for dataSourcePath to prevent path traversal. Got: ' . $dataSourcePath,
51+
1709391234
52+
);
2353
}
24-
$data = json_decode(file_get_contents($dataSourcePath), true);
2554

26-
$this->setProperty('options', $data);
55+
$dataSourcePath = GeneralUtility::getFileAbsFileName($dataSourcePath);
56+
57+
$jsonContent = file_get_contents($dataSourcePath);
58+
if ($jsonContent === false) {
59+
return;
60+
}
61+
62+
$data = json_decode($jsonContent, true);
63+
if (is_array($data)) {
64+
$this->setProperty('options', $data);
65+
}
2766
}
2867
}

Classes/Event/BeforeFormDefinitionCreatesEvent.php

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
<?php
22

3+
/*
4+
* This file is part of the "LIA Form" Extension for TYPO3 CMS.
5+
*
6+
* For the full copyright and license information, please read the
7+
* LICENSE.txt file that was distributed with this source code.
8+
*/
9+
310
declare(strict_types=1);
411

512
/*
@@ -20,40 +27,52 @@
2027
final class BeforeFormDefinitionCreatesEvent
2128
{
2229
/**
23-
* Event constructor.
30+
* Create event instance.
31+
*
32+
* @param array<string, mixed> $formDefinitionConfigArray The form configuration array
33+
* @param ServerRequestInterface $request The current server request
34+
* @param int $renderedForms Count of forms rendered in this request
2435
*/
2536
public function __construct(
26-
private array $formDefintionConfigArray,
37+
private array $formDefinitionConfigArray,
2738
private readonly ServerRequestInterface $request,
2839
private readonly int $renderedForms
2940
) {}
3041

3142
/**
32-
* Returns the formDefintionConfigArray
43+
* Get the form definition configuration array.
44+
*
45+
* @return array<string, mixed> The form configuration
3346
*/
3447
public function getFormDefinitionConfigArray(): array
3548
{
36-
return $this->formDefintionConfigArray;
49+
return $this->formDefinitionConfigArray;
3750
}
3851

3952
/**
40-
* Set the formDefinitionConfigArray
53+
* Set the form definition configuration array.
54+
*
55+
* @param array<string, mixed> $newFormDefinitionConfigArray The new form configuration
4156
*/
4257
public function setFormDefinitionConfigArray(array $newFormDefinitionConfigArray): void
4358
{
44-
$this->formDefintionConfigArray = $newFormDefinitionConfigArray;
59+
$this->formDefinitionConfigArray = $newFormDefinitionConfigArray;
4560
}
4661

4762
/**
48-
* Return the ServerRequestInterface
63+
* Get the server request interface.
64+
*
65+
* @return ServerRequestInterface The current request
4966
*/
5067
public function getServerRequestInterface(): ServerRequestInterface
5168
{
5269
return $this->request;
5370
}
5471

5572
/**
56-
* Returns the count of the rendered forms.
73+
* Get the count of rendered forms.
74+
*
75+
* @return int Number of forms rendered in this request
5776
*/
5877
public function getRenderedForms(): int
5978
{

Classes/Event/BeforePhoneAreaCodeInitializeEvent.php

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,48 @@
11
<?php
22

3+
/*
4+
* This file is part of the "LIA Form" Extension for TYPO3 CMS.
5+
*
6+
* For the full copyright and license information, please read the
7+
* LICENSE.txt file that was distributed with this source code.
8+
*/
9+
310
declare(strict_types=1);
411

512
namespace LIA\LiaForm\Event;
613

14+
/**
15+
* Event dispatched before phone area code initialization.
16+
*
17+
* Allows customization of the data source path for phone area codes.
18+
*
19+
* @author LOUIS INTERNET <devs@louis.info>
20+
*/
721
final class BeforePhoneAreaCodeInitializeEvent
822
{
923
/**
10-
* Event constructor
24+
* Create event instance.
1125
*
12-
* @param string $dataSourcePath
26+
* @param string $dataSourcePath Path to the area code data source
1327
*/
14-
public function __construct(private string $dataSourcePath) {}
28+
public function __construct(
29+
private string $dataSourcePath
30+
) {}
1531

1632
/**
17-
* Get the value of dataSourcePath
33+
* Get the data source path.
34+
*
35+
* @return string The path to the area code data source
1836
*/
1937
public function getDataSourcePath(): string
2038
{
2139
return $this->dataSourcePath;
2240
}
2341

2442
/**
25-
* Set the value of dataSourcePath
43+
* Set the data source path.
2644
*
27-
* @param string $dataSourcePath
45+
* @param string $dataSourcePath The new path to the area code data source
2846
*/
2947
public function setDataSourcePath(string $dataSourcePath): void
3048
{

0 commit comments

Comments
 (0)