Skip to content

Commit 10bc8cb

Browse files
committed
[FEATURE] Extendable component data object
1 parent 60da7c6 commit 10bc8cb

File tree

10 files changed

+291
-93
lines changed

10 files changed

+291
-93
lines changed

Classes/Domain/Model/Component.php

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SMS\FluidComponents\Domain\Model;
6+
7+
class Component
8+
{
9+
protected string $namespace;
10+
protected string $package;
11+
protected string $name;
12+
protected string $file;
13+
14+
protected array $data = [];
15+
protected ?string $class = null;
16+
protected ?string $prefix = null;
17+
18+
public function __construct(
19+
string $fullNamespace,
20+
string $package,
21+
string $name,
22+
string $file
23+
) {
24+
$this->namespace = $fullNamespace;
25+
$this->package = $package;
26+
$this->name = $name;
27+
$this->file = $file;
28+
}
29+
30+
public function getNamespace(): string
31+
{
32+
return $this->namespace;
33+
}
34+
35+
public function getPackage(): string
36+
{
37+
return $this->package;
38+
}
39+
40+
public function getName(): string
41+
{
42+
return $this->name;
43+
}
44+
45+
public function getPath(): string
46+
{
47+
return dirname($this->file);
48+
}
49+
50+
public function getFile(): string
51+
{
52+
return $this->file;
53+
}
54+
55+
public function getData(): array
56+
{
57+
return $this->data;
58+
}
59+
60+
public function setData(array $data): void
61+
{
62+
$this->data = $data;
63+
}
64+
65+
public function getClass(): ?string
66+
{
67+
return $this->class;
68+
}
69+
70+
public function setClass(string $class): void
71+
{
72+
$this->class = $class;
73+
}
74+
75+
public function getPrefix(): ?string
76+
{
77+
return $this->prefix;
78+
}
79+
80+
public function setPrefix(string $prefix): void
81+
{
82+
$this->prefix = $prefix;
83+
}
84+
85+
public function __toString(): string
86+
{
87+
return $this->file;
88+
}
89+
}

Classes/Fluid/ViewHelper/ComponentRenderer.php

+28-89
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
namespace SMS\FluidComponents\Fluid\ViewHelper;
44

55
use Psr\Container\ContainerInterface;
6+
use SMS\FluidComponents\Domain\Model\Component;
67
use SMS\FluidComponents\Domain\Model\Slot;
78
use SMS\FluidComponents\Interfaces\ComponentAware;
89
use SMS\FluidComponents\Interfaces\EscapedParameter;
910
use SMS\FluidComponents\Interfaces\RenderingContextAware;
1011
use SMS\FluidComponents\Utility\ComponentArgumentConverter;
12+
use SMS\FluidComponents\Service\ComponentDataLoader;
1113
use SMS\FluidComponents\Utility\ComponentLoader;
12-
use SMS\FluidComponents\Utility\ComponentPrefixer\ComponentPrefixerInterface;
13-
use SMS\FluidComponents\Utility\ComponentPrefixer\GenericComponentPrefixer;
1414
use SMS\FluidComponents\Utility\ComponentSettings;
1515
use SMS\FluidComponents\ViewHelpers\ComponentViewHelper;
1616
use SMS\FluidComponents\ViewHelpers\ParamViewHelper;
@@ -45,6 +45,13 @@ class ComponentRenderer extends AbstractViewHelper
4545
*/
4646
protected $componentNamespace;
4747

48+
/**
49+
* Object containing information about the current component
50+
*
51+
* @var Component
52+
*/
53+
protected Component $component;
54+
4855
/**
4956
* Cache for component template instance used for rendering
5057
*
@@ -62,13 +69,6 @@ class ComponentRenderer extends AbstractViewHelper
6269
*/
6370
protected static $componentArgumentDefinitionCache = [];
6471

65-
/**
66-
* Cache of component prefixer objects
67-
*
68-
* @var array
69-
*/
70-
protected static $componentPrefixerCache = [];
71-
7272
/**
7373
* Components are HTML markup which should not be escaped
7474
*
@@ -93,6 +93,11 @@ class ComponentRenderer extends AbstractViewHelper
9393
*/
9494
protected ComponentSettings $componentSettings;
9595

96+
/**
97+
* @var ComponentDataLoader
98+
*/
99+
protected ComponentDataLoader $componentDataLoader;
100+
96101
/**
97102
* @var ComponentArgumentConverter
98103
*/
@@ -112,11 +117,13 @@ class ComponentRenderer extends AbstractViewHelper
112117
public function __construct(
113118
ComponentLoader $componentLoader,
114119
ComponentSettings $componentSettings,
120+
ComponentDataLoader $componentDataLoader,
115121
ComponentArgumentConverter $componentArgumentConverter,
116122
ContainerInterface $container
117123
) {
118124
$this->componentLoader = $componentLoader;
119125
$this->componentSettings = $componentSettings;
126+
$this->componentDataLoader = $componentDataLoader;
120127
$this->componentArgumentConverter = $componentArgumentConverter;
121128
$this->container = $container;
122129
}
@@ -130,39 +137,20 @@ public function __construct(
130137
public function setComponentNamespace($componentNamespace)
131138
{
132139
$this->componentNamespace = $componentNamespace;
140+
$this->component = $this->componentLoader->findComponent($this->componentNamespace);
133141
return $this;
134142
}
135143

136144
/**
137145
* Returns the namespace of the component the viewhelper renders
138146
*
139-
* @return void
147+
* @return string
140148
*/
141149
public function getComponentNamespace()
142150
{
143151
return $this->componentNamespace;
144152
}
145153

146-
/**
147-
* Returns the component prefix
148-
*
149-
* @return string
150-
*/
151-
public function getComponentClass()
152-
{
153-
return $this->getComponentPrefixer()->prefix($this->componentNamespace);
154-
}
155-
156-
/**
157-
* Returns the component prefix
158-
*
159-
* @return string
160-
*/
161-
public function getComponentPrefix()
162-
{
163-
return $this->getComponentClass() . $this->getComponentPrefixer()->getSeparator();
164-
}
165-
166154
/**
167155
* Renders the component the viewhelper is responsible for
168156
* TODO this can probably be improved by using renderComponent() directly
@@ -184,12 +172,11 @@ public function render()
184172
}
185173
$variableContainer = $renderingContext->getVariableProvider();
186174

175+
// Load additional data for component
176+
$this->componentDataLoader->loadData($this->component);
177+
187178
// Provide information about component to renderer
188-
$variableContainer->add('component', [
189-
'namespace' => $this->componentNamespace,
190-
'class' => $this->getComponentClass(),
191-
'prefix' => $this->getComponentPrefix(),
192-
]);
179+
$variableContainer->add('component', $this->component);
193180
$variableContainer->add('settings', $this->componentSettings);
194181

195182
// Provide component content to renderer
@@ -218,12 +205,10 @@ public function render()
218205

219206
// Initialize component rendering template
220207
if (!isset($this->parsedTemplate)) {
221-
$componentFile = $this->componentLoader->findComponent($this->componentNamespace);
222-
223208
$this->parsedTemplate = $renderingContext->getTemplateParser()->getOrParseAndStoreTemplate(
224-
$this->getTemplateIdentifier($componentFile),
225-
function () use ($componentFile) {
226-
return file_get_contents($componentFile);
209+
$this->getTemplateIdentifier($this->component->getFile()),
210+
function () {
211+
return file_get_contents($this->component->getFile());
227212
}
228213
);
229214
}
@@ -392,12 +377,10 @@ protected function initializeComponentParams()
392377
{
393378
$renderingContext = $this->getRenderingContext();
394379

395-
$componentFile = $this->componentLoader->findComponent($this->componentNamespace);
396-
397380
// Parse component template without using the cache
398381
$parsedTemplate = $renderingContext->getTemplateParser()->parse(
399-
file_get_contents($componentFile),
400-
$this->getTemplateIdentifier($componentFile)
382+
file_get_contents($this->component->getFile()),
383+
$this->getTemplateIdentifier($this->component->getFile())
401384
);
402385

403386
// Extract all component viewhelpers
@@ -409,7 +392,7 @@ protected function initializeComponentParams()
409392
if (count($componentNodes) > 1) {
410393
throw new Exception(sprintf(
411394
'Only one component per file allowed in: %s',
412-
$componentFile
395+
$this->component->getFile()
413396
), 1527779393);
414397
}
415398

@@ -510,50 +493,6 @@ protected function getTemplateIdentifier(string $pathAndFilename, string $prefix
510493
);
511494
}
512495

513-
/**
514-
* Returns the prefixer object responsible for the current component namespaces
515-
*
516-
* @return ComponentPrefixerInterface
517-
*/
518-
protected function getComponentPrefixer()
519-
{
520-
if (!isset(self::$componentPrefixerCache[$this->componentNamespace])) {
521-
if (isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['fluid_components']['prefixer']) &&
522-
is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['fluid_components']['prefixer'])
523-
) {
524-
arsort($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['fluid_components']['prefixer']);
525-
foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['fluid_components']['prefixer'] as $namespace => $prefixer) {
526-
$namespace = ltrim($namespace, '\\');
527-
if (strpos($this->componentNamespace, $namespace) === 0) {
528-
$componentPrefixerClass = $prefixer;
529-
break;
530-
}
531-
}
532-
}
533-
534-
if (empty($componentPrefixerClass)) {
535-
$componentPrefixerClass = GenericComponentPrefixer::class;
536-
}
537-
538-
if ($this->container->has($componentPrefixerClass)) {
539-
$componentPrefixer = $this->container->get($componentPrefixerClass);
540-
} else {
541-
$componentPrefixer = GeneralUtility::makeInstance($componentPrefixerClass);
542-
}
543-
544-
if (!($componentPrefixer instanceof ComponentPrefixerInterface)) {
545-
throw new Exception(sprintf(
546-
'Invalid component prefixer: %s',
547-
$componentPrefixerClass
548-
), 1530608357);
549-
}
550-
551-
self::$componentPrefixerCache[$this->componentNamespace] = $componentPrefixer;
552-
}
553-
554-
return self::$componentPrefixerCache[$this->componentNamespace];
555-
}
556-
557496
/**
558497
* @return RenderingContext
559498
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace SMS\FluidComponents\Interfaces;
4+
5+
use SMS\FluidComponents\Domain\Model\Component;
6+
7+
interface ComponentDataProvider
8+
{
9+
public function applyData(Component $component);
10+
}
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SMS\FluidComponents\Service;
6+
7+
use SMS\FluidComponents\Domain\Model\Component;
8+
use TYPO3\CMS\Core\SingletonInterface;
9+
10+
class ComponentDataLoader implements SingletonInterface
11+
{
12+
private array $loadedComponents = [];
13+
private iterable $dataProviders;
14+
15+
public function __construct(iterable $dataProviders)
16+
{
17+
$this->dataProviders = $dataProviders;
18+
}
19+
20+
public function reset(): void
21+
{
22+
$this->loadedComponents = [];
23+
}
24+
25+
public function loadData(Component $component): void
26+
{
27+
if (isset($this->loadedComponents[$component->getNamespace()])) {
28+
return;
29+
}
30+
31+
foreach ($this->dataProviders as $dataProvider) {
32+
$dataProvider->applyData($component);
33+
}
34+
$this->loadedComponents[$component->getNamespace()] = true;
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SMS\FluidComponents\Service\DataProvider;
6+
7+
use SMS\FluidComponents\Domain\Model\Component;
8+
use SMS\FluidComponents\Interfaces\ComponentDataProvider;
9+
10+
class ComponentPrefixer implements ComponentDataProvider
11+
{
12+
public function applyData(Component $component): void
13+
{
14+
if ($component->getPrefix() !== null) {
15+
return;
16+
}
17+
18+
$vendorName = substr($component->getPackage(), 0, strpos($component->getPackage(), '\\'));
19+
$componentName = str_replace('\\', '', $component->getName());
20+
$prefix = strtolower($vendorName) . $componentName;
21+
22+
$component->setClass($prefix);
23+
$component->setPrefix($prefix . '_');
24+
}
25+
}

0 commit comments

Comments
 (0)