first working version in Flow 6.3
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/functional-tests/2 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/4 Pipeline was successful
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/functional-tests/2 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/4 Pipeline was successful
This commit is contained in:
parent
ea517305f7
commit
7585baee36
12 changed files with 460 additions and 0 deletions
10
.woodpecker/code-style.yml
Normal file
10
.woodpecker/code-style.yml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
steps:
|
||||||
|
code-style:
|
||||||
|
image: composer
|
||||||
|
commands:
|
||||||
|
- composer global config repositories.repo-name vcs https://git.digital-competence.de/Packages/php-codesniffer
|
||||||
|
- composer global config --no-plugins allow-plugins.dealerdirect/phpcodesniffer-composer-installer true
|
||||||
|
- composer global require digicomp/php-codesniffer:@dev
|
||||||
|
- composer global exec -- phpcs --runtime-set ignore_warnings_on_exit 1 --standard=DigiComp Classes/ Tests/
|
||||||
|
when:
|
||||||
|
- event: [push, pull_request, manual]
|
42
.woodpecker/functional-tests.yml
Normal file
42
.woodpecker/functional-tests.yml
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
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: "thecodingmachine/php:${PHP_VERSION}-v4-cli"
|
||||||
|
environment:
|
||||||
|
COMPOSER_HOME: /usr/src/app/.composer
|
||||||
|
HOSTKEY_DIGICOMP: digital-competence.de ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNSjVKJ+SO6wqmDSCgcJDk2ljWlD7qajsTxAuvZpTbJBg2++Zu0VxH0S1WzPVTD/D5UUbK6LVy6YSCnGlv6zmc0=
|
||||||
|
REPOKEY:
|
||||||
|
from_secret: deploykey
|
||||||
|
PHP_EXTENSION_PDO_SQLITE: 1
|
||||||
|
NEOS_BUILD_DIR: /woodpecker/Build-${FLOW_VERSION}
|
||||||
|
commands:
|
||||||
|
- export HOME=/home/docker
|
||||||
|
- echo "$REPOKEY" > ~/.ssh/id_rsa
|
||||||
|
- echo "$HOSTKEY_DIGICOMP" > ~/.ssh/known_hosts
|
||||||
|
- chmod 600 ~/.ssh/id_rsa
|
||||||
|
- sudo mkdir $NEOS_BUILD_DIR
|
||||||
|
- sudo chown -R docker:docker $NEOS_BUILD_DIR
|
||||||
|
- cd $NEOS_BUILD_DIR
|
||||||
|
- composer create-project --no-install neos/flow-base-distribution:^$FLOW_VERSION .
|
||||||
|
- composer config repositories.repo-name path /woodpecker/package
|
||||||
|
- composer config repositories.fluid-render-functions vcs ssh://git@digital-competence.de/Packages/DigiComp.FluidRenderFunctions
|
||||||
|
- composer remove --dev --no-update neos/behat || composer remove --no-update neos/behat
|
||||||
|
- composer require digicomp/fluid-render-functions:@dev
|
||||||
|
- composer require digicomp/fluid-json-views:@dev
|
||||||
|
- bin/phpunit --configuration Build/BuildEssentials/PhpUnit/FunctionalTests.xml Packages/Application/DigiComp.FluidJsonViews/Tests/Functional
|
||||||
|
when:
|
||||||
|
- event: [ push, pull_request, manual ]
|
136
Classes/ViewHelpers/Controller/FluidJsonController.php
Normal file
136
Classes/ViewHelpers/Controller/FluidJsonController.php
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DigiComp\FluidJsonViews\ViewHelpers\Controller;
|
||||||
|
|
||||||
|
use DigiComp\FluidRenderFunctions\InvokeRenderFunctionInterface;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Doctrine\ORM\Proxy\Proxy;
|
||||||
|
use Doctrine\ORM\Query\Parameter;
|
||||||
|
use Neos\Flow\Annotations as Flow;
|
||||||
|
use Neos\Flow\Persistence\Doctrine\Query;
|
||||||
|
use Neos\FluidAdaptor\Core\Widget\AbstractWidgetController;
|
||||||
|
use Neos\Utility\TypeHandling;
|
||||||
|
|
||||||
|
class FluidJsonController extends AbstractWidgetController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Flow\Inject
|
||||||
|
* @var EntityManagerInterface
|
||||||
|
*/
|
||||||
|
protected $entityManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
protected $supportedMediaTypes = [
|
||||||
|
'text/html',
|
||||||
|
'application/json',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Query|null
|
||||||
|
*/
|
||||||
|
protected ?Query $query = null;
|
||||||
|
|
||||||
|
protected InvokeRenderFunctionInterface $renderFunction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Flow\InjectConfiguration(package="DigiComp.FluidJsonViews", path="limitConfiguration")
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected array $limitConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected array $searchProperties;
|
||||||
|
|
||||||
|
protected function initializeAction(): void
|
||||||
|
{
|
||||||
|
parent::initializeAction();
|
||||||
|
|
||||||
|
$this->query = clone $this->widgetConfiguration['objects']->getQuery();
|
||||||
|
$this->renderFunction = $this->widgetConfiguration['renderFunction'];
|
||||||
|
$this->searchProperties = $this->widgetConfiguration['searchProperties'];
|
||||||
|
$this->initializeDoctrineSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes count, objectType and doctrine's MetaDataFactory
|
||||||
|
*/
|
||||||
|
protected function initializeDoctrineSource(): void
|
||||||
|
{
|
||||||
|
// As we are working with objects which may be doctrine proxies persisted in session, its metadata have
|
||||||
|
// never been loaded in this request. So let's see these parameters and load their metadata, so the doctrine
|
||||||
|
// framework knows how to go on.
|
||||||
|
if ($this->query instanceof Query) {
|
||||||
|
$parameters = $this->query->getQueryBuilder()->getParameters();
|
||||||
|
foreach ($parameters as $parameter) {
|
||||||
|
if ($parameter instanceof Parameter && $parameter->getValue() instanceof Proxy) {
|
||||||
|
$this->entityManager->getMetadataFactory()->getMetadataFor(
|
||||||
|
TypeHandling::getTypeForValue($parameter->getValue())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function indexAction()
|
||||||
|
{
|
||||||
|
$this->view->assign('entityClassName', $this->query->getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see https://select2.org/data-sources/ajax#request-parameters
|
||||||
|
*/
|
||||||
|
public function dataAction(
|
||||||
|
?int $limit = null,
|
||||||
|
?string $term = null,
|
||||||
|
?int $page = 0
|
||||||
|
) {
|
||||||
|
$query = $this->query;
|
||||||
|
$result['recordsTotal'] = $query->execute()->count();
|
||||||
|
if ($term !== null) {
|
||||||
|
$searchConstraint = $this->getSearchConstraints($term);
|
||||||
|
$query->matching($query->logicalAnd($searchConstraint));
|
||||||
|
}
|
||||||
|
|
||||||
|
$result['recordsFiltered'] = $query->execute()->count();
|
||||||
|
if ($limit === null) {
|
||||||
|
$limit = $this->limitConfiguration['default'];
|
||||||
|
}
|
||||||
|
if ($this->limitConfiguration['max'] !== null) {
|
||||||
|
if ($limit > $this->limitConfiguration['max'] || $limit === null) {
|
||||||
|
$limit = $this->limitConfiguration['max'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($limit !== null) {
|
||||||
|
$data = $query->setLimit($limit)->setOffset($page * $limit)->execute();
|
||||||
|
} else {
|
||||||
|
$data = $query->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
$renderFunc = $this->renderFunction;
|
||||||
|
foreach ($data as $object) {
|
||||||
|
$result['results'][] = [
|
||||||
|
'id' => $this->persistenceManager->getIdentifierByObject($object),
|
||||||
|
'text' => $renderFunc($object),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$this->response->setContentType('application/json');
|
||||||
|
return \json_encode($result, \JSON_THROW_ON_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getSearchConstraints(
|
||||||
|
string $term
|
||||||
|
): object {
|
||||||
|
$searchConstraints = [];
|
||||||
|
foreach ($this->searchProperties as $searchProperty) {
|
||||||
|
$searchConstraints[] = $this->query->like($searchProperty, '%' . $term . '%');
|
||||||
|
}
|
||||||
|
return $this->query->logicalOr($searchConstraints);
|
||||||
|
}
|
||||||
|
}
|
64
Classes/ViewHelpers/FluidJsonViewHelper.php
Normal file
64
Classes/ViewHelpers/FluidJsonViewHelper.php
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DigiComp\FluidJsonViews\ViewHelpers;
|
||||||
|
|
||||||
|
use DigiComp\FluidJsonViews\ViewHelpers\Controller\FluidJsonController;
|
||||||
|
use DigiComp\FluidRenderFunctions\InvokeRenderFunctionInterface;
|
||||||
|
use Neos\Flow\Annotations as Flow;
|
||||||
|
use Neos\Flow\Mvc\Exception\InfiniteLoopException;
|
||||||
|
use Neos\Flow\Mvc\Exception\StopActionException;
|
||||||
|
use Neos\Flow\Persistence\Doctrine\QueryResult;
|
||||||
|
use Neos\FluidAdaptor\Core\Widget\AbstractWidgetViewHelper;
|
||||||
|
use Neos\FluidAdaptor\Core\Widget\Exception\InvalidControllerException;
|
||||||
|
use Neos\FluidAdaptor\Core\Widget\Exception\MissingControllerException;
|
||||||
|
|
||||||
|
class FluidJsonViewHelper extends AbstractWidgetViewHelper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
* @Flow\Inject
|
||||||
|
* @var FluidJsonController
|
||||||
|
*/
|
||||||
|
protected $controller;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
protected $ajaxWidget = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function initializeArguments(): void
|
||||||
|
{
|
||||||
|
parent::initializeArguments();
|
||||||
|
|
||||||
|
$this->registerArgument('objects', QueryResult::class, 'Objects to show in table.', true);
|
||||||
|
$this->registerArgument(
|
||||||
|
'renderFunction',
|
||||||
|
InvokeRenderFunctionInterface::class,
|
||||||
|
'callabe to use to render single object',
|
||||||
|
true
|
||||||
|
);
|
||||||
|
$this->registerArgument(
|
||||||
|
'searchProperties',
|
||||||
|
'array',
|
||||||
|
'an array of pathes, which should be used during search evaluation',
|
||||||
|
false,
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws InfiniteLoopException
|
||||||
|
* @throws InvalidControllerException
|
||||||
|
* @throws MissingControllerException
|
||||||
|
* @throws StopActionException
|
||||||
|
*/
|
||||||
|
public function render(): string
|
||||||
|
{
|
||||||
|
return $this->initiateSubRequest();
|
||||||
|
}
|
||||||
|
}
|
5
Configuration/Settings.yaml
Normal file
5
Configuration/Settings.yaml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
DigiComp:
|
||||||
|
FluidJsonViews:
|
||||||
|
limitConfiguration:
|
||||||
|
default: 1000
|
||||||
|
max: 1000
|
19
License.txt
Normal file
19
License.txt
Normal 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.
|
28
README.md
Normal file
28
README.md
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# DigiComp.FluidJsonViews
|
||||||
|
|
||||||
|
This package builds upon `DigiComp.FluidRenderFunctions` and uses this, to use a such defined render function to create a simple key/value json view from your QueryResult. Where the key will be the persistence identifier and the value the result of your rendered template.
|
||||||
|
|
||||||
|
Let me provide you an example:
|
||||||
|
```html
|
||||||
|
<rf:registerRenderFunction as="renderTag">
|
||||||
|
{subject.name}
|
||||||
|
</rf:registerRenderFunction>
|
||||||
|
<fj:fluidJson objects="{tags}" renderFunction="{renderTag}" searchProperties="{0: 'name'}">
|
||||||
|
<a href="{dataUri}">jsonView</a>
|
||||||
|
</fj:fluidJson>
|
||||||
|
```
|
||||||
|
|
||||||
|
If you fetch the jsonView you will see something like this:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"recordsTotal": 2,
|
||||||
|
"recordsFiltered": 2,
|
||||||
|
"results": [
|
||||||
|
{"id": "a310057f-869e-419e-b6fe-6c3a00fe444a", "text": "hallo 2"},
|
||||||
|
{"id": "a310057f-869e-419e-b6fe-6c3a00fe444b", "text": "hallo"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
The provided link will understand three query parameters: `limit`, `term` and `page` - all optional.
|
||||||
|
If you send a "term" parameter, it will apply an or sql search over all your given search property paths. `limit` and `page` will allow you to paginate the results.
|
||||||
|
For security and performance reasons, you can define a max limit using the provided values in Settings.yaml. There you can change the default limit (used, if not sent), or disable both (not recommended).
|
|
@ -0,0 +1,8 @@
|
||||||
|
{namespace rf=DigiComp\FluidRenderFunctions\ViewHelpers}
|
||||||
|
{namespace fj=DigiComp\FluidJsonViews\ViewHelpers}
|
||||||
|
<rf:registerRenderFunction as="renderTag">
|
||||||
|
{subject.name}
|
||||||
|
</rf:registerRenderFunction>
|
||||||
|
<fj:fluidJson objects="{tags}" renderFunction="{renderTag}" searchProperties="{0: 'name'}">
|
||||||
|
<a href="{dataUri}">jsonView</a>
|
||||||
|
</fj:fluidJson>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<f:renderChildren arguments="{
|
||||||
|
dataUri: '{f:widget.uri(action: \'data\', format: \'json\', ajax: true)}',
|
||||||
|
entityClassName: entityClassName
|
||||||
|
}" />
|
17
Tests/Functional/Fixtures/Controller/TestController.php
Normal file
17
Tests/Functional/Fixtures/Controller/TestController.php
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DigiComp\FluidJsonViews\Tests\Functional\Fixtures\Controller;
|
||||||
|
|
||||||
|
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('tags', (new Query(Tag::class))->execute());
|
||||||
|
}
|
||||||
|
}
|
78
Tests/Functional/FluidJsonTest.php
Normal file
78
Tests/Functional/FluidJsonTest.php
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DigiComp\FluidJsonViews\Tests\Functional;
|
||||||
|
|
||||||
|
use Neos\Flow\Mvc\Routing\Route;
|
||||||
|
use Neos\Flow\Tests\FunctionalTestCase;
|
||||||
|
use Neos\FluidAdaptor\Tests\Functional\Form\Fixtures\Domain\Model\Tag;
|
||||||
|
|
||||||
|
class FluidJsonTest extends FunctionalTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
protected static $testablePersistenceEnabled = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializer
|
||||||
|
*/
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$route = new Route();
|
||||||
|
$route->setUriPattern('test/fluidjsonviews/test(/{@action})');
|
||||||
|
$route->setDefaults([
|
||||||
|
'@package' => 'DigiComp.FluidJsonViews',
|
||||||
|
'@subpackage' => 'Tests\Functional\Fixtures',
|
||||||
|
'@controller' => 'Test',
|
||||||
|
'@action' => 'index',
|
||||||
|
]);
|
||||||
|
$route->setAppendExceedingArguments(true);
|
||||||
|
$this->router->addRoute($route);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function itAllowsFluidToRenderWrappedArray(): 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/fluidjsonviews/test');
|
||||||
|
$link = $this->browser->getCrawler()->selectLink('jsonView')->link()->getUri();
|
||||||
|
$response = $this->browser->request($link);
|
||||||
|
static::assertEquals('application/json', $response->getHeaderLine('Content-Type'));
|
||||||
|
$result = \json_decode((string)$response->getBody(), true);
|
||||||
|
static::assertEquals(2, $result['recordsTotal']);
|
||||||
|
static::assertCount(2, $result['results']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function itFiltersIfTermProvided(): 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/fluidjsonviews/test');
|
||||||
|
$link = $this->browser->getCrawler()->selectLink('jsonView')->link()->getUri();
|
||||||
|
$response = $this->browser->request($link . '&term=2');
|
||||||
|
$result = \json_decode((string)$response->getBody(), true);
|
||||||
|
static::assertEquals('application/json', $response->getHeaderLine('Content-Type'));
|
||||||
|
|
||||||
|
static::assertEquals(2, $result['recordsTotal']);
|
||||||
|
static::assertEquals(1, $result['recordsFiltered']);
|
||||||
|
static::assertCount(1, $result['results']);
|
||||||
|
}
|
||||||
|
}
|
49
composer.json
Normal file
49
composer.json
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
{
|
||||||
|
"name": "digicomp/fluid-json-views",
|
||||||
|
"description": "create simple json views, with remote search from Fluid",
|
||||||
|
"type": "neos-package",
|
||||||
|
"require": {
|
||||||
|
"digicomp/fluid-render-functions": "^1.0.0",
|
||||||
|
"ext-json": "*",
|
||||||
|
"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\\FluidJsonViews\\": "Classes/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"DigiComp\\FluidJsonViews\\Tests\\": "Tests/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"neos": {
|
||||||
|
"package-key": "DigiComp.FluidJsonViews"
|
||||||
|
},
|
||||||
|
"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.FluidJsonViews",
|
||||||
|
"keywords": [
|
||||||
|
"Neos",
|
||||||
|
"Flow",
|
||||||
|
"fluid",
|
||||||
|
"ajax"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in a new issue