Skip to content

Commit f1ef831

Browse files
committed
[FEATURE] Extendable component data object
1 parent 433e7e2 commit f1ef831

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
@@ -4,14 +4,14 @@
44

55
use Psr\Container\ContainerInterface;
66
use SMS\FluidComponents\Domain\Model\RequiredSlotPlaceholder;
7+
use SMS\FluidComponents\Domain\Model\Component;
78
use SMS\FluidComponents\Domain\Model\Slot;
89
use SMS\FluidComponents\Interfaces\ComponentAware;
910
use SMS\FluidComponents\Interfaces\EscapedParameter;
1011
use SMS\FluidComponents\Interfaces\RenderingContextAware;
1112
use SMS\FluidComponents\Utility\ComponentArgumentConverter;
13+
use SMS\FluidComponents\Service\ComponentDataLoader;
1214
use SMS\FluidComponents\Utility\ComponentLoader;
13-
use SMS\FluidComponents\Utility\ComponentPrefixer\ComponentPrefixerInterface;
14-
use SMS\FluidComponents\Utility\ComponentPrefixer\GenericComponentPrefixer;
1515
use SMS\FluidComponents\Utility\ComponentSettings;
1616
use SMS\FluidComponents\ViewHelpers\ComponentViewHelper;
1717
use SMS\FluidComponents\ViewHelpers\ContentViewHelper;
@@ -49,6 +49,13 @@ class ComponentRenderer extends AbstractViewHelper
4949
*/
5050
protected $componentNamespace;
5151

52+
/**
53+
* Object containing information about the current component
54+
*
55+
* @var Component
56+
*/
57+
protected Component $component;
58+
5259
/**
5360
* Cache for component template instance used for rendering
5461
*
@@ -66,13 +73,6 @@ class ComponentRenderer extends AbstractViewHelper
6673
*/
6774
protected static $componentArgumentDefinitionCache = [];
6875

69-
/**
70-
* Cache of component prefixer objects
71-
*
72-
* @var array
73-
*/
74-
protected static $componentPrefixerCache = [];
75-
7676
/**
7777
* Components are HTML markup which should not be escaped
7878
*
@@ -97,6 +97,11 @@ class ComponentRenderer extends AbstractViewHelper
9797
*/
9898
protected ComponentSettings $componentSettings;
9999

100+
/**
101+
* @var ComponentDataLoader
102+
*/
103+
protected ComponentDataLoader $componentDataLoader;
104+
100105
/**
101106
* @var ComponentArgumentConverter
102107
*/
@@ -116,11 +121,13 @@ class ComponentRenderer extends AbstractViewHelper
116121
public function __construct(
117122
ComponentLoader $componentLoader,
118123
ComponentSettings $componentSettings,
124+
ComponentDataLoader $componentDataLoader,
119125
ComponentArgumentConverter $componentArgumentConverter,
120126
ContainerInterface $container
121127
) {
122128
$this->componentLoader = $componentLoader;
123129
$this->componentSettings = $componentSettings;
130+
$this->componentDataLoader = $componentDataLoader;
124131
$this->componentArgumentConverter = $componentArgumentConverter;
125132
$this->container = $container;
126133
}
@@ -134,39 +141,20 @@ public function __construct(
134141
public function setComponentNamespace($componentNamespace)
135142
{
136143
$this->componentNamespace = $componentNamespace;
144+
$this->component = $this->componentLoader->findComponent($this->componentNamespace);
137145
return $this;
138146
}
139147

140148
/**
141149
* Returns the namespace of the component the viewhelper renders
142150
*
143-
* @return void
151+
* @return string
144152
*/
145153
public function getComponentNamespace()
146154
{
147155
return $this->componentNamespace;
148156
}
149157

150-
/**
151-
* Returns the component prefix
152-
*
153-
* @return string
154-
*/
155-
public function getComponentClass()
156-
{
157-
return $this->getComponentPrefixer()->prefix($this->componentNamespace);
158-
}
159-
160-
/**
161-
* Returns the component prefix
162-
*
163-
* @return string
164-
*/
165-
public function getComponentPrefix()
166-
{
167-
return $this->getComponentClass() . $this->getComponentPrefixer()->getSeparator();
168-
}
169-
170158
/**
171159
* Renders the component the viewhelper is responsible for
172160
* TODO this can probably be improved by using renderComponent() directly
@@ -193,12 +181,11 @@ public function render()
193181
}
194182
$variableContainer = $renderingContext->getVariableProvider();
195183

184+
// Load additional data for component
185+
$this->componentDataLoader->loadData($this->component);
186+
196187
// Provide information about component to renderer
197-
$variableContainer->add('component', [
198-
'namespace' => $this->componentNamespace,
199-
'class' => $this->getComponentClass(),
200-
'prefix' => $this->getComponentPrefix(),
201-
]);
188+
$variableContainer->add('component', $this->component);
202189
$variableContainer->add('settings', $this->componentSettings);
203190

204191
// Provide supplied arguments from component call to renderer
@@ -228,12 +215,10 @@ public function render()
228215

229216
// Initialize component rendering template
230217
if (!isset($this->parsedTemplate)) {
231-
$componentFile = $this->componentLoader->findComponent($this->componentNamespace);
232-
233218
$this->parsedTemplate = $renderingContext->getTemplateParser()->getOrParseAndStoreTemplate(
234-
$this->getTemplateIdentifier($componentFile),
235-
function () use ($componentFile) {
236-
return file_get_contents($componentFile);
219+
$this->getTemplateIdentifier($this->component->getFile()),
220+
function () {
221+
return file_get_contents($this->component->getFile());
237222
}
238223
);
239224
}
@@ -459,12 +444,10 @@ protected function initializeComponentParams()
459444
{
460445
$renderingContext = $this->getRenderingContext();
461446

462-
$componentFile = $this->componentLoader->findComponent($this->componentNamespace);
463-
464447
// Parse component template without using the cache
465448
$parsedTemplate = $renderingContext->getTemplateParser()->parse(
466-
file_get_contents($componentFile),
467-
$this->getTemplateIdentifier($componentFile)
449+
file_get_contents($this->component->getFile()),
450+
$this->getTemplateIdentifier($this->component->getFile())
468451
);
469452

470453
// Extract all component viewhelpers
@@ -476,7 +459,7 @@ protected function initializeComponentParams()
476459
if (count($componentNodes) > 1) {
477460
throw new Exception(sprintf(
478461
'Only one component per file allowed in: %s',
479-
$componentFile
462+
$this->component->getFile()
480463
), 1527779393);
481464
}
482465

@@ -607,50 +590,6 @@ protected function getTemplateIdentifier(string $pathAndFilename, string $prefix
607590
);
608591
}
609592

610-
/**
611-
* Returns the prefixer object responsible for the current component namespaces
612-
*
613-
* @return ComponentPrefixerInterface
614-
*/
615-
protected function getComponentPrefixer()
616-
{
617-
if (!isset(self::$componentPrefixerCache[$this->componentNamespace])) {
618-
if (isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['fluid_components']['prefixer']) &&
619-
is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['fluid_components']['prefixer'])
620-
) {
621-
arsort($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['fluid_components']['prefixer']);
622-
foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['fluid_components']['prefixer'] as $namespace => $prefixer) {
623-
$namespace = ltrim($namespace, '\\');
624-
if (strpos($this->componentNamespace, $namespace) === 0) {
625-
$componentPrefixerClass = $prefixer;
626-
break;
627-
}
628-
}
629-
}
630-
631-
if (empty($componentPrefixerClass)) {
632-
$componentPrefixerClass = GenericComponentPrefixer::class;
633-
}
634-
635-
if ($this->container->has($componentPrefixerClass)) {
636-
$componentPrefixer = $this->container->get($componentPrefixerClass);
637-
} else {
638-
$componentPrefixer = GeneralUtility::makeInstance($componentPrefixerClass);
639-
}
640-
641-
if (!($componentPrefixer instanceof ComponentPrefixerInterface)) {
642-
throw new Exception(sprintf(
643-
'Invalid component prefixer: %s',
644-
$componentPrefixerClass
645-
), 1530608357);
646-
}
647-
648-
self::$componentPrefixerCache[$this->componentNamespace] = $componentPrefixer;
649-
}
650-
651-
return self::$componentPrefixerCache[$this->componentNamespace];
652-
}
653-
654593
/**
655594
* @return RenderingContext
656595
*/
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)