Compare commits

..

8 commits

Author SHA1 Message Date
ed7d6ae002 License.txt => LICENSE 2024-06-04 23:41:59 +02:00
dae60670a4 updating ci pipelines with own images
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/functional-tests/1 Pipeline was successful
ci/woodpecker/push/functional-tests/2 Pipeline was successful
ci/woodpecker/push/functional-tests/3 Pipeline was successful
ci/woodpecker/push/functional-tests/4 Pipeline was successful
2024-06-04 21:57:05 +02:00
098d5c09a6 adding augmentations for select and textfield ViewHelpers 2024-06-02 18:23:21 +02:00
050e6e119f storing the render function in ViewHelperVariableContainer
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/functional-tests/1 Pipeline was successful
ci/woodpecker/push/functional-tests/2 Pipeline was successful
ci/woodpecker/push/functional-tests/3 Pipeline was successful
ci/woodpecker/push/functional-tests/4 Pipeline was successful
2024-06-02 04:04:48 +02:00
9f3488f84e try to create forward compatibility with Flow 7.x forwards
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/functional-tests/1 Pipeline was successful
ci/woodpecker/push/functional-tests/3 Pipeline was successful
ci/woodpecker/push/functional-tests/2 Pipeline was successful
ci/woodpecker/push/functional-tests/4 Pipeline was successful
2024-06-01 23:48:56 +02:00
713941b688 replacing test entities from DataTablesAdapter with entities from FluidAdaptor
Some checks failed
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/functional-tests/1 Pipeline was successful
ci/woodpecker/push/functional-tests/2 Pipeline failed
ci/woodpecker/push/functional-tests/3 Pipeline failed
ci/woodpecker/push/functional-tests/4 Pipeline failed
2024-06-01 23:25:49 +02:00
d9a71f8aa7 fixing description and adding depency to fluid-adaptor 2024-06-01 23:20:41 +02:00
0de901d45c First working version
Some checks failed
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/functional-tests/1 Pipeline failed
ci/woodpecker/push/functional-tests/2 Pipeline failed
ci/woodpecker/push/functional-tests/3 Pipeline failed
ci/woodpecker/push/functional-tests/4 Pipeline failed
2024-06-01 23:15:35 +02:00
24 changed files with 751 additions and 0 deletions

View file

@ -0,0 +1,7 @@
steps:
code-style:
image: git.digital-competence.de/woodpecker-ci/plugin-phpcs
settings:
args: Classes/ Tests/
when:
- event: [push, pull_request, manual]

View file

@ -0,0 +1,22 @@
workspace:
base: /woodpecker
path: package
matrix:
include:
- FLOW_VERSION: 6.3
PHP_VERSION: 7.4
- FLOW_VERSION: 7.3
PHP_VERSION: 7.4
- FLOW_VERSION: 7.3
PHP_VERSION: 8.2
- FLOW_VERSION: 8.2
PHP_VERSION: 8.2
steps:
functional-tests:
image: git.digital-competence.de/woodpecker-ci/plugin-phpunit-flow:${PHP_VERSION}
settings:
flow_version: ${FLOW_VERSION}
when:
- event: [ push, pull_request, manual ]

View file

@ -0,0 +1,69 @@
<?php
declare(strict_types=1);
namespace DigiComp\FluidRenderFunctions\FormExtensions;
use DigiComp\FluidRenderFunctions\InvokeRenderFunctionInterface;
use DigiComp\FluidRenderFunctions\Utils\GeneratorClosureIterator;
use DigiComp\FluidRenderFunctions\Utils\RenderableProxy;
use DigiComp\FluidRenderFunctions\ViewHelpers\RegisterRenderFunctionViewHelper;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Aop\JoinPointInterface;
use Neos\FluidAdaptor\ViewHelpers\Form\SelectViewHelper;
/**
* @Flow\Aspect
*/
class SelectAspect extends SelectViewHelper
{
/**
* @Flow\After("setting(DigiComp.FluidRenderFunctions.enableAspects.select) && method(Neos\FluidAdaptor\ViewHelpers\Form\SelectViewHelper->initializeArguments())")
*/
public function introduceRenderFuncArgument(JoinPointInterface $joinPoint): void
{
$proxy = $joinPoint->getProxy();
if (!($proxy instanceof SelectViewHelper)) {
return;
}
$proxy->registerArgument('renderFunction', 'string', 'callabe to use to render single object');
}
/**
* @Flow\After("setting(DigiComp.FluidRenderFunctions.enableAspects.select) && method(Neos\FluidAdaptor\ViewHelpers\Form\SelectViewHelper->validateArguments())")
*/
public function validateRenderFunction(JoinPointInterface $joinPoint): void
{
$proxy = $joinPoint->getProxy();
if (!($proxy instanceof SelectViewHelper)) {
return;
}
if (!isset($proxy->arguments['renderFunction'])) {
return;
}
$renderFunction = $proxy->viewHelperVariableContainer->get(
RegisterRenderFunctionViewHelper::class,
$proxy->arguments['renderFunction']
);
if (!($renderFunction instanceof InvokeRenderFunctionInterface)) {
throw new \InvalidArgumentException(
'render function with name "' . $proxy->arguments['renderFunction'] . '" has not been registered.',
1717293038
);
}
$proxy->arguments['renderFunction'] = $renderFunction;
$originalOptions = $proxy->arguments['options'];
if (!\is_iterable($originalOptions)) {
// Validation is left to the original view helper
return;
}
$proxy->arguments['options'] = new GeneratorClosureIterator(
static function () use ($originalOptions, $renderFunction) {
foreach ($originalOptions as $option) {
yield new RenderableProxy($renderFunction, $option);
}
}
);
}
}

View file

@ -0,0 +1,59 @@
<?php
declare(strict_types=1);
namespace DigiComp\FluidRenderFunctions\FormExtensions;
use DigiComp\FluidRenderFunctions\InvokeRenderFunctionInterface;
use DigiComp\FluidRenderFunctions\Utils\RenderableProxy;
use DigiComp\FluidRenderFunctions\ViewHelpers\RegisterRenderFunctionViewHelper;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Aop\JoinPointInterface;
use Neos\FluidAdaptor\ViewHelpers\Form\TextfieldViewHelper;
/**
* @Flow\Aspect
*/
class TextfieldAspect extends TextfieldViewHelper
{
/**
* @Flow\After("setting(DigiComp.FluidRenderFunctions.enableAspects.textfield) && method(Neos\FluidAdaptor\ViewHelpers\Form\TextfieldViewHelper->initializeArguments())")
*/
public function introduceRenderFuncArgument(JoinPointInterface $joinPoint): void
{
$proxy = $joinPoint->getProxy();
if (!($proxy instanceof TextfieldViewHelper)) {
return;
}
$proxy->registerArgument('renderFunction', 'string', 'callabe to use to render single object');
}
/**
* @Flow\Around("setting(DigiComp.FluidRenderFunctions.enableAspects.textfield) && method(Neos\FluidAdaptor\ViewHelpers\Form\TextfieldViewHelper->getValueAttribute())")
*/
public function applyRenderFunctionToValue(JoinPointInterface $joinPoint)
{
$proxy = $joinPoint->getProxy();
if (!($proxy instanceof TextfieldViewHelper)) {
return;
}
if (!isset($proxy->arguments['renderFunction'])) {
return $joinPoint->getAdviceChain()->proceed($joinPoint);
}
$renderFunction = $proxy->viewHelperVariableContainer->get(
RegisterRenderFunctionViewHelper::class,
$proxy->arguments['renderFunction']
);
if (!($renderFunction instanceof InvokeRenderFunctionInterface)) {
throw new \InvalidArgumentException(
'render function with name "' . $proxy->arguments['renderFunction'] . '" has not been registered.',
1717293038
);
}
$originalObject = $joinPoint->getAdviceChain()->proceed($joinPoint);
if (\is_object($originalObject)) {
return new RenderableProxy($renderFunction, $originalObject);
}
return $originalObject;
}
}

View file

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace DigiComp\FluidRenderFunctions;
interface InvokeRenderFunctionInterface
{
public function __invoke($object): string;
}

View file

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DigiComp\FluidRenderFunctions\Utils;
use TYPO3Fluid\Fluid\View\ViewInterface;
// @deprecated: drop this class, as soon as Flow 6.3 support drops
class DummyView implements ViewInterface
{
public function assign($key, $value)
{
}
public function assignMultiple(array $values)
{
}
public function render()
{
}
public function renderSection($sectionName, array $variables = [], $ignoreUnknown = false)
{
}
public function renderPartial($partialName, $sectionName, array $variables, $ignoreUnknown = false)
{
}
}

View file

@ -0,0 +1,21 @@
<?php
namespace DigiComp\FluidRenderFunctions\Utils;
class GeneratorClosureIterator implements \IteratorAggregate
{
private \Closure $closure;
/**
* @param \Closure $closure
*/
public function __construct(\Closure $closure)
{
$this->closure = $closure;
}
public function getIterator(): \Generator
{
return ($this->closure)();
}
}

View file

@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
namespace DigiComp\FluidRenderFunctions\Utils;
use DigiComp\FluidRenderFunctions\InvokeRenderFunctionInterface;
use Neos\Flow\ObjectManagement\Proxy\ProxyInterface;
use Neos\FluidAdaptor\Core\Rendering\RenderingContext;
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\NodeInterface;
class NodeRenderTransfer implements InvokeRenderFunctionInterface
{
/**
* @var NodeInterface
*/
protected NodeInterface $node;
/**
* @var string
*/
protected string $subjectName;
public function __construct(NodeInterface $node, string $subjectName = 'object')
{
$this->node = $node;
$this->subjectName = $subjectName;
}
public function __invoke($object): string
{
// @deprecated: drop the condition, if compatibility to Flow 6.3 can be dropped
$reflector = new \ReflectionClass(RenderingContext::class);
if ($reflector->implementsInterface(ProxyInterface::class)) {
try {
$reflector = new \ReflectionClass($reflector->getParentClass()->getName());
} catch (\Exception $e) {
// nothing, go with the first one
}
}
$constructor = $reflector->getConstructor();
if ($constructor->getNumberOfRequiredParameters() > 0) {
$context = new RenderingContext(new DummyView());
} else {
$context = new RenderingContext();
}
$context->getVariableProvider()->add($this->subjectName, $object);
return \trim($this->node->evaluate($context));
}
}

View file

@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace DigiComp\FluidRenderFunctions\Utils;
use DigiComp\FluidRenderFunctions\InvokeRenderFunctionInterface;
use Neos\Utility\Exception\PropertyNotAccessibleException;
use Neos\Utility\ObjectAccess;
/**
* The RenderableProxy wraps original objects and provides a __toString() function
*
* Because of that, you could use it, to wrap your objects in it and pass the wrapped objects to SelectViewHelper
*/
class RenderableProxy
{
protected InvokeRenderFunctionInterface $renderFunction;
protected $object;
public ?string $Persistence_Object_Identifier = null;
public function __construct(InvokeRenderFunctionInterface $renderFunction, $object)
{
$this->renderFunction = $renderFunction;
$this->object = $object;
try {
$this->Persistence_Object_Identifier =
ObjectAccess::getProperty($object, 'Persistence_Object_Identifier', true);
} catch (PropertyNotAccessibleException $e) {
// ok. fine
}
}
public function __toString(): string
{
$render = $this->renderFunction;
return $render($this->object);
}
}

View file

@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace DigiComp\FluidRenderFunctions\ViewHelpers;
use DigiComp\FluidRenderFunctions\InvokeRenderFunctionInterface;
use DigiComp\FluidRenderFunctions\Utils\GeneratorClosureIterator;
use DigiComp\FluidRenderFunctions\Utils\RenderableProxy;
use DigiComp\FluidRenderFunctions\ViewHelpers\Traits\ValidateRenderFunctionTrait;
use Neos\FluidAdaptor\Core\ViewHelper\AbstractViewHelper;
class ApplyRenderFunctionViewHelper extends AbstractViewHelper
{
use ValidateRenderFunctionTrait;
public function initializeArguments(): void
{
parent::initializeArguments();
$this->registerArgument('in', 'mixed', 'subject to apply the render function to');
$this->registerArgument('function', 'string', 'render function to use', true);
$this->registerArgument(
'force',
'bool',
'if set, it will be applied to the provided in, if not, it will be applied to each item for '
. 'iterables instead',
false,
false
);
}
public function validateArguments()
{
parent::validateArguments();
$this->validateRenderFunctionArgument('function');
}
public function render()
{
$in = $this->arguments['in'];
if ($in === null) {
$in = $this->renderChildren();
}
if (\is_iterable($in) && $this->arguments['force'] === false) {
return new GeneratorClosureIterator(fn () => $this->getProxyGenerator($this->arguments['function'], $in));
} else {
return new RenderableProxy($this->arguments['function'], $in);
}
}
protected function getProxyGenerator(InvokeRenderFunctionInterface $function, iterable $objects): \Generator
{
foreach ($objects as $object) {
yield new RenderableProxy($function, $object);
}
}
}

View file

@ -0,0 +1,55 @@
<?php
declare(strict_types=1);
namespace DigiComp\FluidRenderFunctions\ViewHelpers;
use DigiComp\FluidRenderFunctions\Utils\NodeRenderTransfer;
use Neos\FluidAdaptor\Core\ViewHelper\AbstractViewHelper;
use TYPO3Fluid\Fluid\Core\Compiler\TemplateCompiler;
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\RootNode;
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ViewHelperNode;
class RegisterRenderFunctionViewHelper extends AbstractViewHelper
{
/**
* @throws \Neos\FluidAdaptor\Core\ViewHelper\Exception
*/
public function initializeArguments(): void
{
parent::initializeArguments();
$this->registerArgument('as', 'string', 'Name of the registered render function', false, 'renderFunc');
$this->registerArgument(
'subjectName',
'string',
'Name of the argument passed to render function',
false,
'subject'
);
}
public function compile(
$argumentsName,
$closureName,
&$initializationPhpCode,
ViewHelperNode $node,
TemplateCompiler $compiler
) {
// we disable compiling, because we will need access to the AST, which is not available if compiled
// a cool improvement would be to drop the need to the AST and so become compilable
$compiler->disable();
return "''";
}
public function render(): string
{
$transferNode = new RootNode();
foreach ($this->childNodes as $childNode) {
$transferNode->addChildNode($childNode);
}
$renderer = new NodeRenderTransfer($transferNode, $this->arguments['subjectName']);
$this->renderingContext->getViewHelperVariableContainer()
->add(static::class, $this->arguments['as'], $renderer);
return '';
}
}

View file

@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace DigiComp\FluidRenderFunctions\ViewHelpers\Traits;
use DigiComp\FluidRenderFunctions\InvokeRenderFunctionInterface;
use DigiComp\FluidRenderFunctions\ViewHelpers\RegisterRenderFunctionViewHelper;
trait ValidateRenderFunctionTrait
{
public function validateRenderFunctionArgument(string $argumentName)
{
$renderFunction = $this->viewHelperVariableContainer->get(
RegisterRenderFunctionViewHelper::class,
$this->arguments[$argumentName]
);
if (!($renderFunction instanceof InvokeRenderFunctionInterface)) {
throw new \InvalidArgumentException(
'render function with name "' . $this->arguments[$argumentName] . '" has not been registered.',
1717293038
);
}
$this->arguments[$argumentName] = $renderFunction;
}
}

View file

@ -0,0 +1,5 @@
DigiComp:
FluidRenderFunctions:
enableAspects:
select: true
textfield: true

19
LICENSE Normal file
View file

@ -0,0 +1,19 @@
Copyright (c) 2024 Ferdinand Kuhl <f.kuhl@digital-competence.de>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

25
README.md Normal file
View file

@ -0,0 +1,25 @@
# DigiComp.FluidRenderFunctions
## Quickstart
This Package provides you with the possibility to register render functions, created from them, to use them dynamically else where.
Let me show you the idea:
```html
<f:form.select options="{books}" />
```
Assuming you know how the SelectViewHelper works, you know, you can provide an "optionLabelField"-argument to adivce the ViewHelper to use a property of your options.
But, what if you want to use a complete template, to display your books?
FluidRenderFunctions to the rescue:
```html
<rf:registerRenderFunction as="renderBook" subjectName="myBook">
{myBook.name} from {myBook.author.name}
</rf:registerRenderFunction>
<f:form.select options="{books -> rf:applyRenderFunction(function: 'renderBook')}" />
```
To make your live easier, FluidRenderFunctions augments the original `SelectViewHelper` and the `TextfieldViewHelper` with an optional `renderFunction` argument. That way, you can even use the usual Textfield to display formatted Datetime objects. Neat!
## Configuration
If - for whatever reason - you do not want FluidRenderFunctions to augment the original ViewHelpers you can opt out by setting `DigiComp.FluidRenderFunctions.enableAspects.select` or `DigiComp.FluidRenderFunctions.enableAspects.textfield` to `false`.

View file

@ -0,0 +1 @@
<f:render section="Content" />

View file

@ -0,0 +1,6 @@
{namespace rf=DigiComp\FluidRenderFunctions\ViewHelpers}
<rf:registerRenderFunction as="renderTag">
{subject.name} is cool
</rf:registerRenderFunction>
<f:form.select options="{tags}" renderFunction="renderTag" />

View file

@ -0,0 +1,11 @@
{namespace rf=DigiComp\FluidRenderFunctions\ViewHelpers}
<rf:registerRenderFunction as="renderDate">
{subject -> f:format.date(format: 'd.m.Y')}
</rf:registerRenderFunction>
<f:form action="extendedTextField">
<f:form.textfield value="{now}" renderFunction="renderDate" />
</f:form>
<f:form object="{post}" objectName="post" action="extendedTextfield">
<f:form.textfield property="publishedAt" renderFunction="renderDate" />
</f:form>

View file

@ -0,0 +1,8 @@
<f:layout name="Test" />
{namespace rf=DigiComp\FluidRenderFunctions\ViewHelpers}
<f:section name="Content"><f:spaceless>
<rf:registerRenderFunction as="testFunc">
{subject.name} is cool
</rf:registerRenderFunction>
{test -> rf:applyRenderFunction(function: 'testFunc', force: true)}
</f:spaceless></f:section>

View file

@ -0,0 +1,8 @@
<f:layout name="Test" />
{namespace rf=DigiComp\FluidRenderFunctions\ViewHelpers}
<f:section name="Content"><f:spaceless>
<rf:registerRenderFunction as="testFunc">
{subject.name} is cool
</rf:registerRenderFunction>
<f:form.select options="{testEntities -> rf:applyRenderFunction(function: 'testFunc')}" />
</f:spaceless></f:section>

View file

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace DigiComp\FluidRenderFunctions\Tests\Functional\Fixtures\Controller;
use DigiComp\FluidRenderFunctions\Tests\Functional\Fixtures\Domain\Post;
use Neos\Flow\Mvc\Controller\ActionController;
use Neos\Flow\Persistence\Doctrine\Query;
use Neos\FluidAdaptor\Tests\Functional\Form\Fixtures\Domain\Model\Tag;
class TestController extends ActionController
{
public function indexAction()
{
$this->view->assign('test', ['name' => 'hallo']);
}
public function selectAction()
{
$this->view->assign('testEntities', (new Query(Tag::class))->execute());
}
public function extendedSelectAction()
{
$this->view->assign('tags', (new Query(Tag::class))->execute());
}
public function extendedTextfieldAction()
{
$this->view->assign('now', new \DateTimeImmutable('2024-06-02T15:03:00Z'));
$this->view->assign('post', (new Query(Post::class))->execute()->getFirst());
}
}

View file

@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
namespace DigiComp\FluidRenderFunctions\Tests\Functional\Fixtures\Domain;
use Neos\Flow\Annotations as Flow;
/**
* @Flow\Entity
*/
class Post
{
/**
* @var string|null
*/
protected ?string $title = null;
/**
* @var \DateTimeImmutable|null
*/
protected ?\DateTimeImmutable $publishedAt = null;
/**
* @param string|null $title
* @param \DateTimeImmutable|null $publishedAt
*/
public function __construct(?string $title, ?\DateTimeImmutable $publishedAt)
{
$this->title = $title;
$this->publishedAt = $publishedAt;
}
public function getTitle(): ?string
{
return $this->title;
}
public function getPublishedAt(): ?\DateTimeImmutable
{
return $this->publishedAt;
}
}

View file

@ -0,0 +1,98 @@
<?php
declare(strict_types=1);
namespace DigiComp\FluidRenderFunctions\Tests\Functional;
use DigiComp\FluidRenderFunctions\Tests\Functional\Fixtures\Domain\Post;
use Neos\Flow\Mvc\Routing\Route;
use Neos\Flow\Tests\FunctionalTestCase;
use Neos\FluidAdaptor\Tests\Functional\Form\Fixtures\Domain\Model\Tag;
use Symfony\Component\DomCrawler\Crawler;
class RenderFunctionsTest extends FunctionalTestCase
{
protected static $testablePersistenceEnabled = true;
/**
* Initializer
*/
protected function setUp(): void
{
parent::setUp();
$route = new Route();
$route->setUriPattern('test/fluidrenderfunctions/test(/{@action})');
$route->setDefaults([
'@package' => 'DigiComp.FluidRenderFunctions',
'@subpackage' => 'Tests\Functional\Fixtures',
'@controller' => 'Test',
'@action' => 'index',
]);
$route->setAppendExceedingArguments(true);
$this->router->addRoute($route);
}
/**
* @test
*/
public function itAllowsFluidToRenderWrappedArray(): void
{
$response = $this->browser->request('http://localhost/test/fluidrenderfunctions/test');
static::assertEquals("hallo is cool\n", (string)$response->getBody());
}
/**
* @test
*/
public function itAllowsToRenderTheOptionsArgumentOfSelectNicely(): void
{
$post1 = new Tag('hallo');
$this->persistenceManager->add($post1);
$post2 = new Tag('hallo 2');
$this->persistenceManager->add($post2);
$this->persistenceManager->persistAll();
$this->browser->request('http://localhost/test/fluidrenderfunctions/test/select');
$options = $this->browser->getCrawler()
->filterXPath('//select[1]/option')
->each(fn (Crawler $node) => $node->text());
static::assertEquals(['hallo is cool', 'hallo 2 is cool'], $options);
}
/**
* @test
*/
public function itAllowsRenderFunctionOnStandardSelect(): void
{
$post1 = new Tag('hallo');
$this->persistenceManager->add($post1);
$post2 = new Tag('hallo 2');
$this->persistenceManager->add($post2);
$this->persistenceManager->persistAll();
$this->browser->request('http://localhost/test/fluidrenderfunctions/test/extendedselect');
$options = $this->browser->getCrawler()
->filterXPath('//select[1]/option')
->each(fn (Crawler $node) => $node->text());
static::assertEquals(['hallo is cool', 'hallo 2 is cool'], $options);
}
/**
* @test
*/
public function itAllowsRenderFunctionOnStandardTextField(): void
{
$testDate = new \DateTimeImmutable('2024-06-02T15:03:00Z');
$post1 = new Post('hallo', $testDate);
$this->persistenceManager->add($post1);
$this->persistenceManager->persistAll();
$this->browser->request('http://localhost/test/fluidrenderfunctions/test/extendedtextfield');
$input1 = $this->browser->getCrawler()->filterXPath('//input[@type="text"][1]/@value')->text('input not found');
static::assertEquals('02.06.2024', $input1);
$input2 = $this->browser->getCrawler()->filterXPath('//input[@type="text"][2]/@value')->text('input not found');
static::assertEquals('02.06.2024', $input2);
}
}

46
composer.json Normal file
View file

@ -0,0 +1,46 @@
{
"name": "digicomp/fluid-render-functions",
"description": "define fluid based render functions and use them else where",
"type": "neos-package",
"require": {
"neos/flow": "^6.3.5 | ^7.3 | ^8.3",
"neos/fluid-adaptor": "^6.3.5 | ^7.3 | ^8.3",
"php": ">=7.4"
},
"require-dev": {
"phpunit/phpunit": "~8.5"
},
"autoload": {
"psr-4": {
"DigiComp\\FluidRenderFunctions\\": "Classes/"
}
},
"autoload-dev": {
"psr-4": {
"DigiComp\\FluidRenderFunctions\\Tests\\": "Tests/"
}
},
"extra": {
"neos": {
"package-key": "DigiComp.FluidRenderFunctions"
},
"branch-alias": {
"dev-develop": "1.0.x-dev"
}
},
"authors": [
{
"name": "Ferdinand Kuhl",
"email": "f.kuhl@digital-competence.de",
"homepage": "https://www.digital-competence.de",
"role": "Developer"
}
],
"license": "MIT",
"homepage": "https://git.digital-competence.de/Packages/DigiComp.FluidRenderFunctions",
"keywords": [
"Neos",
"Flow",
"fluid"
]
}