Compare commits

...

115 commits

Author SHA1 Message Date
5e6f56552d update structure of composer.json and update dependencies
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/functional-tests/1 Pipeline was successful
ci/woodpecker/tag/code-style 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
ci/woodpecker/tag/functional-tests/1 Pipeline was successful
ci/woodpecker/tag/functional-tests/2 Pipeline was successful
ci/woodpecker/tag/functional-tests/3 Pipeline was successful
ci/woodpecker/tag/functional-tests/4 Pipeline was successful
2024-10-11 14:30:34 +02:00
6e7d100d51 Adding Build-Badge
All checks were successful
ci/woodpecker/manual/code-style Pipeline was successful
ci/woodpecker/manual/functional-tests Pipeline was successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/functional-tests Pipeline was successful
2023-02-18 21:32:19 +01:00
3741781455 Merge tag '4.0.1' into develop
Tagging 4.0.1
2023-02-18 21:30:37 +01:00
019bdcc9c7 Merge branch 'release/4.0.1'
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/functional-tests Pipeline was successful
2023-02-18 21:30:33 +01:00
fb9263ec68 Removing empty changelog 2023-02-18 21:29:59 +01:00
cdded1c1e2 Merge branch 'feature/flow-8.2' into develop 2023-02-18 21:20:44 +01:00
f9629557e4 Test only flow 7.3 with PHP 7 and 8
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/functional-tests Pipeline was successful
2023-02-18 21:15:17 +01:00
69a860109e Fixing code-style check
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/functional-tests Pipeline was successful
2023-02-18 21:13:58 +01:00
59229d8f3b Allowing recent Flow versions
Some checks failed
ci/woodpecker/push/code-style Pipeline failed
ci/woodpecker/push/functional-tests Pipeline was successful
2023-02-18 21:12:34 +01:00
7c8f8ff75a Fixing README.md 2023-02-18 21:10:01 +01:00
Robin Krahnen
81c93c2b06 Merge branch 'release/4.0.0'
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2022-05-04 23:41:15 +02:00
Robin Krahnen
dba037df7f Merge tag '4.0.0' into develop
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
4.0.0
2022-05-04 23:41:15 +02:00
Robin Krahnen
1360b1b7bd Merge branch 'feature/revision' into develop
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2022-05-04 23:40:40 +02:00
Robin Krahnen
e9ff06a553 optimized versions in composer.json
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2022-05-04 19:01:16 +02:00
a4cddb619d Removing Flow 5.3 building (not longer supported)
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2022-05-02 10:17:04 +02:00
Robin Krahnen
5d7f705828 add "declare(strict_types=1);"
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2022-05-02 09:56:14 +02:00
c4621db5a7 Merge branch 'develop' into feature/revision
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2022-04-30 21:51:20 +02:00
b1e639af57 Merge branch 'version/2.x-dev' into develop
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2022-04-30 21:51:12 +02:00
55898c3f8f Do not check Resources/Private (not exists)
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2022-04-30 21:51:03 +02:00
b0980124e0 Merge branch 'develop' into feature/revision
Some checks failed
ci/woodpecker/push/code-style Pipeline failed
ci/woodpecker/push/test Pipeline was successful
2022-04-30 21:49:29 +02:00
c74da756a6 Adjusting tests to work with flow 5.3 and 6.3
Some checks failed
ci/woodpecker/push/code-style Pipeline failed
ci/woodpecker/push/test Pipeline was successful
2022-04-30 21:48:56 +02:00
968904e448 Merge branch 'version/2.x-dev' into develop 2022-04-30 21:46:59 +02:00
8492f2f926 Adding testing and code-style pipelines
Some checks failed
ci/woodpecker/push/code-style Pipeline failed
ci/woodpecker/push/test Pipeline was successful
2022-04-30 21:45:57 +02:00
ba62e2bc33 Merge branch 'version/2.x-dev' into develop 2022-04-30 21:40:21 +02:00
ab6ef4ba48 RUN phpcbf 2022-04-30 21:38:36 +02:00
Robin Krahnen
e839d216ad revised code 2022-04-20 17:36:31 +02:00
Robin Krahnen
8396fa0db7 code style 2022-04-04 22:42:58 +02:00
Robin Krahnen
b0dd57f693 change dependency to neos/flow 2022-04-04 22:41:28 +02:00
Robin Krahnen
24016dd060 optimized php requirement 2022-03-03 13:30:53 +01:00
Robin Krahnen
9263cf0596 optimized line breaks README.md 2022-02-10 15:57:40 +01:00
Robin Krahnen
586d603650 removed duplicated blank line 2022-02-10 15:57:07 +01:00
Robin Krahnen
f324e8c0ca remove unnecessary slash after %FLOW_PATH_*% 2021-10-11 12:23:44 +02:00
Robin Krahnen
3fc0ddce1f add empty line at end of composer.json (was removed by flow core migrations...) 2021-09-23 16:52:53 +02:00
Robin Krahnen
a34f5eb20b TASK: Apply migration Neos.Flow-20190515215000
Adjust "Settings.yaml" to new PSR-3 logging settings (see
https://github.com/neos/flow-development-collection/pull/1574)

Note: This migration did not produce any changes, so the commit simply
marks the migration as applied. This makes sure it will not be applied
again.
2021-09-23 16:14:01 +02:00
Robin Krahnen
03672e05c5 TASK: Apply migration Neos.Flow-20190425144900
Adjusts code to FlashMessageContainer renaming from "\Neos\Flow\Mvc" to
"\Neos\Flow\Mvc\FlashMessage".

Note: This migration did not produce any changes, so the commit simply
marks the migration as applied. This makes sure it will not be applied
again.
2021-09-23 16:14:00 +02:00
Robin Krahnen
d46c2ca7ff add missing return type hints 2021-09-23 08:55:03 +02:00
Robin Krahnen
71748c0d75 add empty line at end of License.txt 2021-09-22 15:00:26 +02:00
Robin Krahnen
19b58b9c26 reformat @ORM\Table 2021-09-22 14:26:09 +02:00
Robin Krahnen
ced940247c revised code 2021-09-22 11:34:34 +02:00
Robin Krahnen
722111191f fixes with code inspection 2021-09-21 10:39:03 +02:00
Robin Krahnen
2b15d25ebe optimized use statements 2021-09-20 18:12:51 +02:00
Robin Krahnen
aab466ac17 renamed $systemLogger to $logger 2021-09-17 11:22:44 +02:00
Robin Krahnen
4164640182 replace empty function 2021-09-16 16:34:00 +02:00
Robin Krahnen
8da32c3969 run phpcbf 2021-09-16 15:30:22 +02:00
Robin Krahnen
7767091426 fixed indentation 2021-09-16 15:00:42 +02:00
Robin Krahnen
fcebb74344 remove .gitignore 2021-09-10 12:39:26 +02:00
Robin Krahnen
83839a1582 optimized README.md 2021-09-10 12:37:11 +02:00
Robin Krahnen
d5f8b671d5 added CHANGELOG.md 2021-09-10 12:09:20 +02:00
Robin Krahnen
258a754788 update migrations 2021-09-08 16:42:05 +02:00
Robin Krahnen
24135e0982 update composer.json 2021-09-03 10:15:46 +02:00
Robin Krahnen
103d6fc007 update composer.json 2021-09-02 17:50:16 +02:00
13d517645a Merge tag '3.0.0' into develop
Tagging 3.0.0
2021-08-26 10:53:33 +02:00
891da480a9 Merge branch 'release/3.0.0' 2021-08-26 10:53:26 +02:00
273789e187 Merge branch 'feature/flow-6.3' into develop 2021-08-26 10:53:04 +02:00
d97849a4e2 Adding branch alias vor 2.x 2021-08-26 10:52:22 +02:00
75528b78b2 PHPCBF run 2021-08-26 10:50:00 +02:00
c9ce9a90fd Added a command to clean up old and obsolete sequence entries 2021-06-29 14:23:25 +02:00
8d2c150141 Better type handling and exception annotations 2021-06-01 18:46:16 +02:00
7c60f2f55e TASK: Adding PHP 7.4 type hints everywhere 2021-04-20 01:45:51 +02:00
e8b75b33dd FIX: Adjusting to Flow 6.3 (Logger and EntityManager) 2020-10-15 21:14:03 +02:00
c180a50731 TASK: Allow Neos Flow 6.3 2020-10-15 14:52:58 +02:00
Robin Krahnen
3ee24e5381 empty line between opening php tag and namespace 2020-03-16 15:44:37 +01:00
Robin Krahnen
39a98c4814 removed empty lines between @param and @return/@throws 2020-03-12 14:21:32 +01:00
Robin Krahnen
583b1f9d48 optimized migrations 2020-03-11 17:24:48 +01:00
Robin Krahnen
3fcffcd1f3 removed trailing spaces 2020-03-11 12:09:37 +01:00
Robin Krahnen
cabf69c595 replaces tabs with spaces 2020-03-11 12:00:42 +01:00
Robin Krahnen
2e10a9450f Merge branch 'develop' 2020-03-10 14:53:38 +01:00
Robin Krahnen
9b7f051307 PSR-12 for tests 2020-03-10 14:48:58 +01:00
Robin Krahnen
028429ae2f added blank space before namespace line (PSR-12) 2020-03-10 11:13:12 +01:00
Robin Krahnen
7fbca6d65c Merge branch 'develop' 2019-12-04 12:52:50 +01:00
Robin Krahnen
a0b5b74b36 optimized code to fit our coding guideline; made some small optimizations if possible 2019-12-04 12:48:02 +01:00
Christian Krause
7e33de3131 Merge branch 'release/2.1.0' 2019-11-12 12:34:03 +01:00
Christian Krause
72d86162c8 Merge tag '2.1.0' into develop
2.1.0
2019-11-12 12:34:03 +01:00
Christian Krause
2b4ad3b09b Merge branch 'feature/flow-5.3' into develop 2019-11-12 12:33:46 +01:00
Robin Krahnen
97245832bf Merge branch 'develop' into feature/flow-5.3 2019-10-28 10:41:12 +01:00
Robin Krahnen
410ce5de97 added @deprecated to unused properties 2019-10-28 10:31:11 +01:00
Robin Krahnen
a409a00a3a removed 'ENGINE = InnoDB' from migrations 2019-08-27 12:41:11 +02:00
Robin Krahnen
d501426770 TASK: Apply migration Neos.Flow-20180415105700
Add scalar type hint to CacheAwareInterface implementations.

Note: This migration did not produce any changes, so the commit simply
marks the migration as applied. This makes sure it will not be applied
again.
2019-08-27 11:30:13 +02:00
Robin Krahnen
be1efbf3b9 allow neos/flow ~5.3 2019-08-27 09:44:48 +02:00
Robin Krahnen
672528f45a Merge branch 'develop' 2019-08-20 15:13:11 +02:00
Robin Krahnen
b81bb5bc3d remove unnecessary @Flow\Scope("prototype") 2019-07-30 11:02:25 +02:00
Robin Krahnen
44ee3cde99 optimized spaces in readme 2019-06-07 09:02:40 +02:00
a94cb0d5f6 Merge tag '2.0.1' into develop
Tagging 2.0.1
2018-05-14 15:04:05 +02:00
cc1e159614 Merge branch 'release/2.0.1' 2018-05-14 15:04:01 +02:00
Robin Krahnen
2856fa764b replaced doctype annotation in methods with comment 2018-04-05 09:02:16 +02:00
Robin Krahnen
da9d014c9d optimized query for getLastNumberFor function 2018-04-04 23:50:19 +02:00
Robin Krahnen
8fa1e1089e use entity manager to resolve class table name 2018-04-04 23:48:06 +02:00
Robin Krahnen
5465b39332 do not save value into variable if it's only returned afterwards 2018-04-04 23:39:03 +02:00
Robin Krahnen
1124d3626e removed useless brackets 2018-04-04 22:48:18 +02:00
Robin Krahnen
029d599577 reordered inline @var-doctypes 2018-04-04 09:26:23 +02:00
Christian Krause
27b3bd9af1 TASK: Apply migration DigiComp.SettingValidator-20170603120900
Restructures Validation.yamls to new format

Note: This migration did not produce any changes, so the commit simply
marks the migration as applied. This makes sure it will not be applied
again.
2018-04-03 13:50:46 +02:00
Robin Krahnen
026a3d786a just some code and annotation cleanup 2018-04-03 10:23:53 +02:00
653badb31b TASK: fixing composer.json 2017-09-04 15:37:21 +02:00
4e05e51d4f TASK: Fixing branch alias 2017-09-04 15:31:12 +02:00
Merten Koch
4ecdd6272c Merge branch 'release/3.0.0' 2017-08-28 16:46:06 +02:00
Merten Koch
33ec7a241c Merge branch 'feature/neos-flow4' into develop 2017-08-28 16:45:45 +02:00
6a851fac61 TASK: PSR4 only 2017-08-23 10:36:28 +02:00
Daniel Siepmann
cda0def335
TASK: Raise flow version constraint 2017-05-24 14:02:27 +02:00
Daniel Siepmann
71cf52d80e TASK: Apply migration Neos.Flow-20170127183102
Migrate bootstep names.

Note: This migration did not produce any changes, so the commit simply
marks the migration as applied. This makes sure it will not be applied
again.
2017-03-15 09:06:44 +01:00
Daniel Siepmann
dae7f83338 TASK: Apply migration Neos.Flow-20170125103800
Migrate usages of the path [TYPO3][Flow][Security][Authentication] to
[Neos][Flow][Security][Authentication]

Note: This migration did not produce any changes, so the commit simply
marks the migration as applied. This makes sure it will not be applied
again.
2017-03-15 09:06:44 +01:00
Daniel Siepmann
bb8d35a132 TASK: Apply migration Neos.Media-20161219094126
Migrate name for the media image size cache

Note: This migration did not produce any changes, so the commit simply
marks the migration as applied. This makes sure it will not be applied
again.
2017-03-15 09:06:44 +01:00
Daniel Siepmann
464380e18d TASK: Apply migration TYPO3.FluidAdaptor-20161130112935
Adjusts code to package renaming from "TYPO3.Fluid" to
"Neos.FluidAdaptor".

Note: This migration did not produce any changes, so the commit simply
marks the migration as applied. This makes sure it will not be applied
again.
2017-03-15 09:06:44 +01:00
Daniel Siepmann
f3be919a57 TASK: Apply migration Neos.SwiftMailer-20161130105617
Adjusts code to package renaming from "TYPO3.SwiftMailer" to
"Neos.SwiftMailer".

Note: This migration did not produce any changes, so the commit simply
marks the migration as applied. This makes sure it will not be applied
again.
2017-03-15 09:06:44 +01:00
Daniel Siepmann
9da615e46c TASK: Apply migration Neos.Flow-20161125124112
Adjusts code to Neos\Flow\Utility\Unicode adjustment

Note: This migration did not produce any changes, so the commit simply
marks the migration as applied. This makes sure it will not be applied
again.
2017-03-15 09:06:44 +01:00
Daniel Siepmann
33a2f4e880 TASK: Apply migration Neos.Media-20161124233100
Adjusts code to package renaming from "TYPO3.Media" to "Neos.Media"

Note: This migration did not produce any changes, so the commit simply
marks the migration as applied. This makes sure it will not be applied
again.
2017-03-15 09:06:44 +01:00
Daniel Siepmann
aa0508f9d0 TASK: Apply migration Neos.Imagine-20161124231742
Adjusts code to Imagine Renaming

Note: This migration did not produce any changes, so the commit simply
marks the migration as applied. This makes sure it will not be applied
again.
2017-03-15 09:06:44 +01:00
Daniel Siepmann
f4c36abc69 TASK: Apply migration Neos.Eel-20161124230101
Adjusts code to Eel Renaming

Note: This migration did not produce any changes, so the commit simply
marks the migration as applied. This makes sure it will not be applied
again.
2017-03-15 09:06:44 +01:00
Daniel Siepmann
777920d40f TASK: Apply migration Neos.Flow-20161124224015
Adjusts code to cache extraction

Note: This migration did not produce any changes, so the commit simply
marks the migration as applied. This makes sure it will not be applied
again.
2017-03-15 09:06:44 +01:00
Daniel Siepmann
b84620b6c3 TASK: Apply migration Neos.Flow-20161124204701
Adjusts code to package renaming from "Neos.Flow.Utility.Files" to
"Neos.Utility.Files" and other extractions of the "Utility" packages.

Note: This migration did not produce any changes, so the commit simply
marks the migration as applied. This makes sure it will not be applied
again.
2017-03-15 09:06:44 +01:00
Daniel Siepmann
8364b273cf TASK: Apply migration Neos.Flow-20161124204700
Adjusts code to package renaming from "TYPO3.Flow" to "Neos.Flow"

Note: This migration did not produce any changes, so the commit simply
marks the migration as applied. This makes sure it will not be applied
again.
2017-03-15 09:06:44 +01:00
Daniel Siepmann
73cabc5672 TASK: Apply migration TYPO3.Flow-20161115140430
Adjust to the renaming of the Object namespace in Flow 4.0

Note: This migration did not produce any changes, so the commit simply
marks the migration as applied. This makes sure it will not be applied
again.
2017-03-15 09:06:44 +01:00
Daniel Siepmann
44c984e2fa TASK: Apply migration TYPO3.Flow-20161115140400
Adjust to the renaming of the Resource namespace and class in Flow 4.0

Note: This migration did not produce any changes, so the commit simply
marks the migration as applied. This makes sure it will not be applied
again.
2017-03-15 09:06:44 +01:00
Daniel Siepmann
0c912176bf TASK: Apply migration TYPO3.Flow-20151113161300
Adjust "Settings.yaml" to new "requestPattern" and "firewall" syntax
(see FLOW-412)

Note: This migration did not produce any changes, so the commit simply
marks the migration as applied. This makes sure it will not be applied
again.
2017-03-15 09:06:44 +01:00
Robin Krahnen
37d3856a3b update project; fit neos/flow 4 2017-03-13 16:59:04 +01:00
Robin Krahnen
9b92e22589 edit composer.json for feature/neos-flow4 2017-02-16 22:00:51 +01:00
20 changed files with 527 additions and 400 deletions

1
.gitignore vendored
View file

@ -1 +0,0 @@
.svn

View file

@ -0,0 +1,8 @@
pipeline:
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/

View file

@ -0,0 +1,32 @@
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
pipeline:
functional-tests:
image: "thecodingmachine/php:${PHP_VERSION}-v4-cli"
environment:
# Enable the PDO_SQLITE extension
- "PHP_EXTENSION_PDO_SQLITE=1"
- "FLOW_VERSION=${FLOW_VERSION}"
- "NEOS_BUILD_DIR=/woodpecker/Build-${FLOW_VERSION}"
commands:
- "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 remove --dev --no-update neos/behat || composer remove --no-update neos/behat"
- "composer require digicomp/sequence:@dev"
- "bin/phpunit --configuration Build/BuildEssentials/PhpUnit/FunctionalTests.xml Packages/Application/DigiComp.Sequence/Tests/Functional"

View file

@ -0,0 +1,82 @@
<?php
declare(strict_types=1);
namespace DigiComp\Sequence\Command;
use DigiComp\Sequence\Domain\Model\SequenceEntry;
use DigiComp\Sequence\Service\Exception\InvalidSourceException;
use DigiComp\Sequence\Service\SequenceGenerator;
use Doctrine\DBAL\Driver\Exception as DoctrineDBALDriverException;
use Doctrine\DBAL\Exception as DoctrineDBALException;
use Doctrine\ORM\EntityManagerInterface;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Cli\CommandController;
/**
* @Flow\Scope("singleton")
*/
class SequenceCommandController extends CommandController
{
/**
* @Flow\Inject
* @var SequenceGenerator
*/
protected $sequenceGenerator;
/**
* @Flow\Inject
* @var EntityManagerInterface
*/
protected $entityManager;
/**
* Set last number for sequence generator.
*
* @param string $type
* @param int $number
* @throws DoctrineDBALDriverException
* @throws DoctrineDBALException
* @throws InvalidSourceException
*/
public function setLastNumberForCommand(string $type, int $number): void
{
if ($this->sequenceGenerator->setLastNumberFor($type, $number)) {
$this->outputLine('Last number successfully set.');
} else {
$this->outputLine('Failed to set last number.');
}
}
/**
* Clean up sequence table.
*
* @param string[] $types
* @throws DoctrineDBALDriverException
* @throws DoctrineDBALException
* @throws InvalidSourceException
*/
public function cleanUpCommand(array $types = []): void
{
if ($types === []) {
foreach (
$this
->entityManager
->createQuery('SELECT DISTINCT(se.type) type FROM ' . SequenceEntry::class . ' se')
->execute()
as $result
) {
$types[] = $result['type'];
}
}
foreach ($types as $type) {
$rowCount = $this
->entityManager
->createQuery('DELETE FROM ' . SequenceEntry::class . ' se WHERE se.type = ?0 AND se.number < ?1')
->execute([$type, $this->sequenceGenerator->getLastNumberFor($type)]);
$this->outputLine('Deleted ' . $rowCount . ' row(s) for type "' . $type . '".');
}
}
}

View file

@ -1,38 +0,0 @@
<?php
namespace DigiComp\Sequence\Command;
/* *
* This script belongs to the FLOW3 package "DigiComp.Sequence". *
* *
* */
use TYPO3\Flow\Annotations as Flow;
use TYPO3\Flow\Cli\CommandController;
/**
* A database agnostic SequenceNumber generator
*
* @Flow\Scope("singleton")
*/
class SequenceCommandController extends CommandController
{
/**
* @var \DigiComp\Sequence\Service\SequenceGenerator
* @Flow\Inject
*/
protected $sequenceGenerator;
/**
* Sets minimum number for sequence generator
*
* @param int $to
* @param string $type
*/
public function advanceCommand($to, $type)
{
$this->sequenceGenerator->advanceTo($to, $type);
}
//TODO: make clean up job to delete all but the biggest number to save resources
}

View file

@ -1,81 +0,0 @@
<?php
namespace DigiComp\Sequence\Domain\Model;
/* *
* This script belongs to the FLOW3 package "DigiComp.Sequence". *
* *
* */
use TYPO3\Flow\Annotations as Flow;
use Doctrine\ORM\Mapping as ORM;
/**
* SequenceInsert
*
* @author fcool
* @Flow\Scope("prototype")
* @Flow\Entity
* @ORM\Table(indexes={@ORM\Index(name="type_idx", columns={"type"})})
*/
class Insert
{
/**
* @var int
* @ORM\Id
* @Flow\Identity
*/
protected $number;
/**
* @var string
* @ORM\Id
* @Flow\Identity
*/
protected $type;
/**
* @param int $number
* @param string|object $type
*/
public function __construct($number, $type)
{
$this->setType($type);
$this->setNumber($number);
}
/**
* @param int $number
*/
public function setNumber($number)
{
$this->number = $number;
}
/**
* @return int
*/
public function getNumber()
{
return $this->number;
}
/**
* @param string|object $type
*/
public function setType($type)
{
if (is_object($type)) {
$type = get_class($type);
}
$this->type = $type;
}
/**
* @return string
*/
public function getType()
{
return $this->type;
}
}

View file

@ -1,17 +0,0 @@
<?php
namespace DigiComp\Sequence\Service;
/* *
* This script belongs to the FLOW3 package "DigiComp.Sequence". *
* *
* */
use TYPO3\Flow\Annotations as Flow;
/**
* SequenceException
*/
class Exception extends \Exception
{
}

View file

@ -1,126 +0,0 @@
<?php
namespace DigiComp\Sequence\Service;
/* *
* This script belongs to the FLOW3 package "DigiComp.Sequence". *
* *
* */
use Doctrine\DBAL\DBALException;
use TYPO3\Flow\Annotations as Flow;
/**
* A SequenceNumber generator working for transactional databases
*
*
* Thoughts: We could make the step-range configurable, and if > 1 we could return new keys immediately for this
* request, as we "reserved" the space between.
*
* @Flow\Scope("singleton")
*/
class SequenceGenerator
{
/**
* @var \Doctrine\Common\Persistence\ObjectManager
* @Flow\Inject
*/
protected $entityManager;
/**
* @var \TYPO3\Flow\Reflection\ReflectionService
* @Flow\Inject
*/
protected $reflectionService;
/**
* @var \TYPO3\Flow\Log\SystemLoggerInterface
* @Flow\Inject
*/
protected $systemLogger;
/**
* @param string|object $type
*
* @throws \DigiComp\Sequence\Service\Exception
* @return int
*/
public function getNextNumberFor($type)
{
$type = $this->inferTypeFromSource($type);
$count = $this->getLastNumberFor($type);
//TODO: Check for maximal tries, or similar
//TODO: Let increment be configurable per type
do {
$count = $count + 1;
} while (!$this->validateFreeNumber($count, $type));
return $count;
}
protected function validateFreeNumber($count, $type)
{
$em = $this->entityManager;
/** @var $em \Doctrine\ORM\EntityManager */
try {
$em->getConnection()->insert(
'digicomp_sequence_domain_model_insert',
['number' => $count, 'type' => $type]
);
return true;
} catch (\PDOException $e) {
return false;
} catch (DBALException $e) {
if ($e->getPrevious() && $e->getPrevious() instanceof \PDOException) {
// Do nothing, new Doctrine handling hides the above error
} else {
$this->systemLogger->logException($e);
}
} catch (\Exception $e) {
$this->systemLogger->logException($e);
}
return false;
}
public function advanceTo($to, $type)
{
$type = $this->inferTypeFromSource($type);
return ($this->validateFreeNumber($to, $type));
}
/**
* @param string|object $type
*
* @return int
*/
public function getLastNumberFor($type)
{
$type = $this->inferTypeFromSource($type);
/** @var $em \Doctrine\ORM\EntityManager */
$em = $this->entityManager;
$result = $em->getConnection()->executeQuery(
'SELECT MAX(number) AS count FROM digicomp_sequence_domain_model_insert WHERE type=:type',
['type' => $type]
);
$count = $result->fetchAll();
$count = $count[0]['count'];
return $count;
}
/**
* @param string|object $stringOrObject
*
* @throws Exception
* @return string
*/
protected function inferTypeFromSource($stringOrObject) {
if (is_object($stringOrObject)) {
$stringOrObject = $this->reflectionService->getClassNameByObject($stringOrObject);
}
if (!$stringOrObject) {
throw new Exception('No Type given');
}
return $stringOrObject;
}
}

View file

@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace DigiComp\Sequence\Domain\Model;
use Doctrine\ORM\Mapping as ORM;
use Neos\Flow\Annotations as Flow;
/**
* This class is only here to set up the table. We never create an instance of this class.
*
* @Flow\Entity
*/
class SequenceEntry
{
/**
* @ORM\Id
* @var string
*/
protected string $type;
/**
* @ORM\Id
* @var int
*/
protected int $number;
}

11
Classes/Exception.php Normal file
View file

@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace DigiComp\Sequence;
use Neos\Flow\Exception as NeosFlowException;
class Exception extends NeosFlowException
{
}

View file

@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace DigiComp\Sequence\Service\Exception;
use DigiComp\Sequence\Exception;
class InvalidSourceException extends Exception
{
}

View file

@ -0,0 +1,137 @@
<?php
declare(strict_types=1);
namespace DigiComp\Sequence\Service;
use DigiComp\Sequence\Domain\Model\SequenceEntry;
use DigiComp\Sequence\Service\Exception\InvalidSourceException;
use Doctrine\DBAL\Driver\Exception as DoctrineDBALDriverException;
use Doctrine\DBAL\Exception as DoctrineDBALException;
use Doctrine\ORM\EntityManagerInterface;
use Neos\Flow\Annotations as Flow;
use Neos\Utility\TypeHandling;
use Psr\Log\LoggerInterface;
/**
* A sequence number generator working for transactional databases.
*
* Thoughts: We could make the step-range configurable, and if > 1 we could return new keys immediately for this
* request, as we "reserved" the space between.
*
* @Flow\Scope("singleton")
*/
class SequenceGenerator
{
/**
* @Flow\Inject
* @var EntityManagerInterface
*/
protected $entityManager;
/**
* @Flow\Inject
* @var LoggerInterface
*/
protected $logger;
/**
* @param string|object $source
* @return int
* @throws DoctrineDBALDriverException
* @throws DoctrineDBALException
* @throws InvalidSourceException
*/
public function getNextNumberFor($source): int
{
$type = $this->inferTypeFromSource($source);
$number = $this->getLastNumberFor($type);
// TODO: Check for maximal tries, or similar?
// TODO: Let increment be configurable per type?
do {
$number++;
} while (!$this->insertFor($type, $number));
return $number;
}
/**
* @param string $type
* @param int $number
* @return bool
*/
protected function insertFor(string $type, int $number): bool
{
try {
$this->entityManager->getConnection()->insert(
$this->entityManager->getClassMetadata(SequenceEntry::class)->getTableName(),
['type' => $type, 'number' => $number]
);
return true;
} catch (\PDOException $exception) {
} catch (DoctrineDBALException $exception) {
if (!$exception->getPrevious() instanceof \PDOException) {
$this->logger->critical('Exception occurred: ' . $exception->getMessage());
}
} catch (\Exception $exception) {
$this->logger->critical('Exception occurred: ' . $exception->getMessage());
}
return false;
}
/**
* @param string|object $source
* @param int $number
* @return bool
* @throws DoctrineDBALDriverException
* @throws DoctrineDBALException
* @throws InvalidSourceException
*/
public function setLastNumberFor($source, int $number): bool
{
$type = $this->inferTypeFromSource($source);
if ($this->getLastNumberFor($type) >= $number) {
return false;
}
return $this->insertFor($type, $number);
}
/**
* @param string|object $source
* @throws DoctrineDBALDriverException
* @throws DoctrineDBALException
* @throws InvalidSourceException
*/
public function getLastNumberFor($source): int
{
return (int)$this->entityManager->getConnection()->executeQuery(
'SELECT MAX(number) FROM '
. $this->entityManager->getClassMetadata(SequenceEntry::class)->getTableName()
. ' WHERE type = :type',
['type' => $this->inferTypeFromSource($source)]
)->fetchOne();
}
/**
* @param string|object $source
* @return string
* @throws InvalidSourceException
*/
protected function inferTypeFromSource($source): string
{
if (\is_string($source)) {
return $source;
}
if (\is_object($source)) {
return TypeHandling::getTypeForValue($source);
}
throw new InvalidSourceException('Could not infer type from source.', 1632216173);
}
}

View file

@ -1,6 +1,6 @@
TYPO3: Neos:
Flow: Flow:
persistence: persistence:
backendOptions: backendOptions:
driver: 'pdo_sqlite' driver: "pdo_sqlite"
path: %FLOW_PATH_DATA%/Temporary/testing.db path: "%FLOW_PATH_DATA%Temporary/testing.db"

View file

@ -1,40 +1,37 @@
<?php <?php
namespace TYPO3\Flow\Persistence\Doctrine\Migrations;
use Doctrine\DBAL\Migrations\AbstractMigration, declare(strict_types=1);
Doctrine\DBAL\Schema\Schema;
namespace Neos\Flow\Persistence\Doctrine\Migrations;
use Doctrine\DBAL\Exception as DoctrineDBALException;
use Doctrine\DBAL\Migrations\AbortMigrationException;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your need!
*/
class Version20140505093853 extends AbstractMigration class Version20140505093853 extends AbstractMigration
{ {
/** /**
* @param Schema $schema * @param Schema $schema
* * @throws AbortMigrationException
* @return void * @throws DoctrineDBALException
*/ */
public function up(Schema $schema) public function up(Schema $schema): void
{ {
// this up() migration is autogenerated, please modify it to your needs $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on "mysql".');
$this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql");
$this->addSql( $this->addSql('CREATE TABLE digicomp_sequence_domain_model_insert (number INT NOT NULL, type VARCHAR(255) NOT NULL, PRIMARY KEY(number, type))');
"CREATE TABLE digicomp_sequence_domain_model_insert (number INT NOT NULL, type VARCHAR(255) NOT NULL, PRIMARY KEY(number, type)) ENGINE = InnoDB"
);
} }
/** /**
* @param Schema $schema * @param Schema $schema
* * @throws AbortMigrationException
* @return void * @throws DoctrineDBALException
*/ */
public function down(Schema $schema) public function down(Schema $schema): void
{ {
// this down() migration is autogenerated, please modify it to your needs $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on "mysql".');
$this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql");
$this->addSql("DROP TABLE digicomp_sequence_domain_model_insert"); $this->addSql('DROP TABLE digicomp_sequence_domain_model_insert');
} }
} }

View file

@ -1,52 +1,36 @@
<?php <?php
namespace TYPO3\Flow\Persistence\Doctrine\Migrations;
use Doctrine\DBAL\Migrations\AbstractMigration; declare(strict_types=1);
namespace Neos\Flow\Persistence\Doctrine\Migrations;
use Doctrine\DBAL\Exception as DoctrineDBALException;
use Doctrine\DBAL\Migrations\AbortMigrationException;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs! This block will be used as the migration description if
* getDescription() is not used.
*/
class Version20160624203903 extends AbstractMigration class Version20160624203903 extends AbstractMigration
{ {
/**
* @return string
*/
public function getDescription()
{
return '';
}
/** /**
* @param Schema $schema * @param Schema $schema
* * @throws AbortMigrationException
* @return void * @throws DoctrineDBALException
*/ */
public function up(Schema $schema) public function up(Schema $schema): void
{ {
// this up() migration is autogenerated, please modify it to your needs $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on "mysql".');
$this->abortIf(
$this->connection->getDatabasePlatform()->getName() != 'mysql',
'Migration can only be executed safely on "mysql".'
);
$this->addSql('CREATE INDEX type_idx ON digicomp_sequence_domain_model_insert (type)'); $this->addSql('CREATE INDEX type_idx ON digicomp_sequence_domain_model_insert (type)');
} }
/** /**
* @param Schema $schema * @param Schema $schema
* * @throws AbortMigrationException
* @return void * @throws DoctrineDBALException
*/ */
public function down(Schema $schema) public function down(Schema $schema): void
{ {
// this down() migration is autogenerated, please modify it to your needs $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on "mysql".');
$this->abortIf(
$this->connection->getDatabasePlatform()->getName() != 'mysql',
'Migration can only be executed safely on "mysql".'
);
$this->addSql('DROP INDEX type_idx ON digicomp_sequence_domain_model_insert'); $this->addSql('DROP INDEX type_idx ON digicomp_sequence_domain_model_insert');
} }

View file

@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace Neos\Flow\Persistence\Doctrine\Migrations;
use Doctrine\DBAL\Exception as DoctrineDBALException;
use Doctrine\DBAL\Migrations\AbortMigrationException;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
class Version20210922110814 extends AbstractMigration
{
/**
* @param Schema $schema
* @throws AbortMigrationException
* @throws DoctrineDBALException
*/
public function up(Schema $schema): void
{
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on "mysql".');
$this->addSql('CREATE TABLE digicomp_sequence_domain_model_sequenceentry (type VARCHAR(255) NOT NULL, number INT NOT NULL, PRIMARY KEY(type, number))');
$this->addSql('INSERT INTO digicomp_sequence_domain_model_sequenceentry (type, number) SELECT i.type, MAX(i.number) FROM digicomp_sequence_domain_model_insert AS i GROUP BY i.type');
$this->addSql('DROP TABLE digicomp_sequence_domain_model_insert');
}
/**
* @param Schema $schema
* @throws AbortMigrationException
* @throws DoctrineDBALException
*/
public function down(Schema $schema): void
{
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on "mysql".');
$this->addSql('CREATE TABLE digicomp_sequence_domain_model_insert (number INT NOT NULL, type VARCHAR(255) NOT NULL, INDEX type_idx (type), PRIMARY KEY(number, type))');
$this->addSql('INSERT INTO digicomp_sequence_domain_model_insert (number, type) SELECT MAX(se.number), se.type FROM digicomp_sequence_domain_model_sequenceentry AS se GROUP BY se.type');
$this->addSql('DROP TABLE digicomp_sequence_domain_model_sequenceentry');
}
}

View file

@ -1,22 +1,23 @@
DigiComp.Sequence # DigiComp.Sequence
-------------------------
![Build status](https://ci.digital-competence.de/api/badges/Packages/DigiComp.FlowObjectResolving/status.svg)
This is a very simple and stupid tool, helping in generation of gapless sequences. For this task it relies on key This is a very simple tool, helping in generation of gapless sequences. For this task it relies on key integrity of the
integrity of the database of your choice. database of your choice.
Usage is quite simple also: Usage is quite simple also:
/** ```php
* @param \DigiComp\Sequence\Service\SequenceNumberGenerator $sequenceNumberGenerator /**
*/ * @param SequenceGenerator $sequenceGenerator
public function __construct(SequenceNumberGenerator $sequenceNumberGenerator) */
{ public function __construct(SequenceGenerator $sequenceNumberGenerator)
$this->orderId = $sequenceNumberGenerator->getNextNumberFor($this); {
} $this->orderId = $sequenceGenerator->getNextNumberFor($this);
}
```
``getNextNumberFor`` allows you to give an object which will be resolved to its FQCN or a custom sequence name. `getNextNumberFor` allows you to give an object (which will be resolved to its FQCN) or a custom sequence name.
The CommandController helps you to advance the current sequence number, in case of migrations or similar. The `SequenceCommandController` helps you to set the last sequence number, in case of migrations or similar. See
`./flow help sequence:setlastnumberfor` if interested.
See ``./flow help sequence:advance`` if interested.

View file

@ -1,54 +1,69 @@
<?php <?php
declare(strict_types=1);
namespace DigiComp\Sequence\Tests\Functional; namespace DigiComp\Sequence\Tests\Functional;
use DigiComp\Sequence\Service\Exception\InvalidSourceException;
use DigiComp\Sequence\Service\SequenceGenerator; use DigiComp\Sequence\Service\SequenceGenerator;
use TYPO3\Flow\Tests\FunctionalTestCase; use Doctrine\DBAL\Driver\Exception as DoctrineDBALDriverException;
use Doctrine\DBAL\Exception as DoctrineDBALException;
use Neos\Flow\Tests\FunctionalTestCase;
class SequenceTest extends FunctionalTestCase class SequenceTest extends FunctionalTestCase
{ {
/**
* @inheritDoc
*/
protected static $testablePersistenceEnabled = true; protected static $testablePersistenceEnabled = true;
/** /**
* @test * @test
* @throws DoctrineDBALDriverException
* @throws DoctrineDBALException
* @throws InvalidSourceException
*/ */
public function sequenceTest() public function sequenceTest(): void
{ {
$sequenceGenerator = $this->objectManager->get(SequenceGenerator::class); $sequenceGenerator = $this->objectManager->get(SequenceGenerator::class);
$number = $sequenceGenerator->getLastNumberFor($sequenceGenerator); self::assertEquals(0, $sequenceGenerator->getLastNumberFor($sequenceGenerator));
$this->assertEquals(0, $number); self::assertEquals(1, $sequenceGenerator->getNextNumberFor($sequenceGenerator));
$this->assertEquals(1, $sequenceGenerator->getNextNumberFor($sequenceGenerator));
$pids = []; $pIds = [];
for ($i = 0; $i < 10; $i++) { for ($i = 0; $i < 10; $i++) {
$pid = pcntl_fork(); $pId = \pcntl_fork();
if ($pid) { if ($pId > 0) {
$pids[] = $pid; $pIds[] = $pId;
} else { } else {
for ($j = 0; $j < 10; $j++) { for ($j = 0; $j < 10; $j++) {
$sequenceGenerator->getNextNumberFor($sequenceGenerator); $sequenceGenerator->getNextNumberFor($sequenceGenerator);
} }
//making a hard exit to avoid phpunit having the tables cleaned up again // making a hard exit to avoid phpunit having the tables cleaned up again
exit; exit;
} }
} }
foreach ($pids as $pid) {
foreach ($pIds as $pId) {
$status = 0; $status = 0;
pcntl_waitpid($pid, $status); \pcntl_waitpid($pId, $status);
} }
$this->assertEquals(101, $sequenceGenerator->getLastNumberFor($sequenceGenerator));
self::assertEquals(101, $sequenceGenerator->getLastNumberFor($sequenceGenerator));
} }
/** /**
* @test * @test
* @throws DoctrineDBALDriverException
* @throws DoctrineDBALException
* @throws InvalidSourceException
*/ */
public function advanceTest() public function setLastNumberForTest(): void
{ {
$sequenceGenerator = $this->objectManager->get(SequenceGenerator::class); $sequenceGenerator = $this->objectManager->get(SequenceGenerator::class);
$sequenceGenerator->setLastNumberFor($sequenceGenerator, 100);
$sequenceGenerator->advanceTo(100, $sequenceGenerator); self::assertEquals(100, $sequenceGenerator->getLastNumberFor($sequenceGenerator));
$this->assertEquals(100, $sequenceGenerator->getLastNumberFor($sequenceGenerator)); self::assertEquals(0, $sequenceGenerator->getLastNumberFor('otherSequence'));
$this->assertEquals(0, $sequenceGenerator->getLastNumberFor('strangeOtherSequence'));
} }
} }

View file

@ -1,50 +1,93 @@
{ {
"name": "digicomp/sequence", "name": "digicomp/sequence",
"type": "typo3-flow-package", "description": "Sequence is a very simple database agnostic but database based sequence generator",
"description": "Sequence is a very simple database agnostic but database based sequence generator", "type": "neos-package",
"keywords": ["flow", "neos", "doctrine", "sequence"], "keywords": [
"authors": [ "Neos",
{ "Flow",
"name": "Ferdinand Kuhl", "doctrine",
"email": "f.kuhl@digital-competence.de", "sequence"
"homepage": "http://www.digital-competence.de", ],
"role": "Developer" "homepage": "https://github.com/digital-competence/DigiComp.Sequence",
} "license": "MIT",
], "authors": [
"license": "MIT", {
"homepage": "https://github.com/digicomp/DigiComp.Sequence", "name": "Ferdinand Kuhl",
"require": { "email": "f.kuhl@digital-competence.de",
"typo3/flow": "~2.0|~3.0" "homepage": "https://www.digital-competence.de",
}, "role": "Developer"
"require-dev": { }
"phpunit/phpunit": "3.7.*", ],
"ext-pcntl": "*" "require": {
}, "php": ">=7.4.0",
"autoload": { "ext-pdo": "*",
"psr-0": { "neos/flow": "^6.3.5 || ^7.0 || ^8.0"
"DigiComp\\Sequence": "Classes"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}, },
"applied-flow-migrations": [ "require-dev": {
"Inwebs.Basket-201409170938", "ext-pcntl": "*",
"TYPO3.FLOW3-201201261636", "mikey179/vfsstream": "^1.6.1",
"TYPO3.Fluid-201205031303", "neos/buildessentials": "^7.0.0",
"TYPO3.FLOW3-201205292145", "phpunit/phpunit": "~8.5",
"TYPO3.FLOW3-201206271128", "vimeo/psalm": "~4.22.0"
"TYPO3.FLOW3-201209201112", },
"TYPO3.Flow-201209251426", "autoload": {
"TYPO3.Flow-201211151101", "psr-4": {
"TYPO3.Flow-201212051340", "DigiComp\\Sequence\\": "Classes/"
"TYPO3.Flow-201310031523", }
"TYPO3.Flow-201405111147", },
"TYPO3.Fluid-20141113120800", "autoload-dev": {
"TYPO3.Flow-20141113121400", "psr-4": {
"TYPO3.Fluid-20141121091700", "DigiComp\\Sequence\\Tests\\": "Tests/"
"TYPO3.Fluid-20150214130800" }
] },
} "config": {
"sort-packages": true,
"platform-check": true
},
"extra": {
"branch-alias": {
"dev-develop": "4.0.x-dev",
"dev-version/2.x-dev": "2.1.x-dev",
"dev-version/1.x-dev": "1.1.x-dev"
},
"neos": {
"package-key": "DigiComp.Sequence"
},
"applied-flow-migrations": [
"Inwebs.Basket-201409170938",
"TYPO3.FLOW3-201201261636",
"TYPO3.Fluid-201205031303",
"TYPO3.FLOW3-201205292145",
"TYPO3.FLOW3-201206271128",
"TYPO3.FLOW3-201209201112",
"TYPO3.Flow-201209251426",
"TYPO3.Flow-201211151101",
"TYPO3.Flow-201212051340",
"TYPO3.Flow-201310031523",
"TYPO3.Flow-201405111147",
"TYPO3.Fluid-20141113120800",
"TYPO3.Flow-20141113121400",
"TYPO3.Fluid-20141121091700",
"TYPO3.Fluid-20150214130800",
"TYPO3.Flow-20151113161300",
"TYPO3.Flow-20161115140400",
"TYPO3.Flow-20161115140430",
"Neos.Flow-20161124204700",
"Neos.Flow-20161124204701",
"Neos.Flow-20161124224015",
"Neos.Eel-20161124230101",
"Neos.Imagine-20161124231742",
"Neos.Media-20161124233100",
"Neos.Flow-20161125124112",
"Neos.SwiftMailer-20161130105617",
"TYPO3.FluidAdaptor-20161130112935",
"Neos.Media-20161219094126",
"Neos.Flow-20170125103800",
"Neos.Flow-20170127183102",
"DigiComp.SettingValidator-20170603120900",
"Neos.Flow-20180415105700",
"Neos.Flow-20190425144900",
"Neos.Flow-20190515215000"
]
}
} }