Compare commits

...

66 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
18 changed files with 367 additions and 266 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

@ -1,34 +1,82 @@
<?php <?php
declare(strict_types=1);
namespace DigiComp\Sequence\Command; namespace DigiComp\Sequence\Command;
use DigiComp\Sequence\Domain\Model\SequenceEntry;
use DigiComp\Sequence\Service\Exception\InvalidSourceException;
use DigiComp\Sequence\Service\SequenceGenerator; 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\Annotations as Flow;
use Neos\Flow\Cli\CommandController; use Neos\Flow\Cli\CommandController;
/** /**
* A database agnostic SequenceNumber generator
*
* @Flow\Scope("singleton") * @Flow\Scope("singleton")
*/ */
class SequenceCommandController extends CommandController class SequenceCommandController extends CommandController
{ {
/** /**
* @var SequenceGenerator
* @Flow\Inject * @Flow\Inject
* @var SequenceGenerator
*/ */
protected $sequenceGenerator; protected $sequenceGenerator;
/** /**
* Sets minimum number for sequence generator * @Flow\Inject
* * @var EntityManagerInterface
* @param int $to
* @param string $type
*/ */
public function advanceCommand($to, $type) 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
{ {
$this->sequenceGenerator->advanceTo($to, $type); if ($this->sequenceGenerator->setLastNumberFor($type, $number)) {
$this->outputLine('Last number successfully set.');
} else {
$this->outputLine('Failed to set last number.');
}
} }
// TODO: make clean up job to delete all but the biggest number to save resources /**
* 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,76 +0,0 @@
<?php
namespace DigiComp\Sequence\Domain\Model;
use Doctrine\ORM\Mapping as ORM;
use Neos\Flow\Annotations as Flow;
/**
* SequenceInsert
*
* @Flow\Entity
* @ORM\Table(indexes={
* @ORM\Index(name="type_idx", columns={"type"})
* })
*/
class Insert
{
/**
* @var int
* @Flow\Identity
* @ORM\Id
*/
protected $number;
/**
* @var string
* @Flow\Identity
* @ORM\Id
*/
protected $type;
/**
* @param int $number
* @param string|object $type
*/
public function __construct($number, $type)
{
$this->setNumber($number);
$this->setType($type);
}
/**
* @return int
*/
public function getNumber()
{
return $this->number;
}
/**
* @param int $number
*/
public function setNumber($number)
{
$this->number = $number;
}
/**
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* @param string|object $type
*/
public function setType($type)
{
if (is_object($type)) {
$type = get_class($type);
}
$this->type = $type;
}
}

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

@ -1,10 +0,0 @@
<?php
namespace DigiComp\Sequence\Service;
/**
* SequenceException
*/
class Exception extends \Exception
{
}

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

@ -1,18 +1,20 @@
<?php <?php
declare(strict_types=1);
namespace DigiComp\Sequence\Service; namespace DigiComp\Sequence\Service;
use DigiComp\Sequence\Domain\Model\Insert; use DigiComp\Sequence\Domain\Model\SequenceEntry;
use Doctrine\Common\Persistence\ObjectManager; use DigiComp\Sequence\Service\Exception\InvalidSourceException;
use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\Exception as DoctrineDBALDriverException;
use Doctrine\ORM\EntityManager; use Doctrine\DBAL\Exception as DoctrineDBALException;
use Doctrine\ORM\EntityManagerInterface;
use Neos\Flow\Annotations as Flow; use Neos\Flow\Annotations as Flow;
use Neos\Flow\Log\SystemLoggerInterface;
use Neos\Flow\Reflection\ReflectionService;
use Neos\Utility\TypeHandling; use Neos\Utility\TypeHandling;
use Psr\Log\LoggerInterface;
/** /**
* A SequenceNumber generator working for transactional databases * 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 * 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. * request, as we "reserved" the space between.
@ -22,116 +24,114 @@ use Neos\Utility\TypeHandling;
class SequenceGenerator class SequenceGenerator
{ {
/** /**
* @var ObjectManager
* @Flow\Inject * @Flow\Inject
* @var EntityManagerInterface
*/ */
protected $entityManager; protected $entityManager;
/** /**
* @var ReflectionService
* @Flow\Inject * @Flow\Inject
* @deprecated * @var LoggerInterface
*/ */
protected $reflectionService; protected $logger;
/** /**
* @var SystemLoggerInterface * @param string|object $source
* @Flow\Inject
*/
protected $systemLogger;
/**
* @param string|object $type
*
* @return int * @return int
* @throws DoctrineDBALDriverException
* @throws DoctrineDBALException
* @throws InvalidSourceException
*/ */
public function getNextNumberFor($type) public function getNextNumberFor($source): int
{ {
$type = $this->inferTypeFromSource($type); $type = $this->inferTypeFromSource($source);
$count = $this->getLastNumberFor($type); $number = $this->getLastNumberFor($type);
// TODO: Check for maximal tries, or similar // TODO: Check for maximal tries, or similar?
// TODO: Let increment be configurable per type // TODO: Let increment be configurable per type?
do { do {
$count++; $number++;
} while (! $this->validateFreeNumber($count, $type)); } while (!$this->insertFor($type, $number));
return $count; return $number;
} }
/** /**
* @param int $count * @param string $type
* @param string|object $type * @param int $number
*
* @return bool * @return bool
*/ */
protected function validateFreeNumber($count, $type) protected function insertFor(string $type, int $number): bool
{ {
/* @var EntityManager $em */
$em = $this->entityManager;
try { try {
$em->getConnection()->insert( $this->entityManager->getConnection()->insert(
$em->getClassMetadata(Insert::class)->getTableName(), $this->entityManager->getClassMetadata(SequenceEntry::class)->getTableName(),
['number' => $count, 'type' => $type] ['type' => $type, 'number' => $number]
); );
return true; return true;
} catch (\PDOException $e) { } catch (\PDOException $exception) {
return false; } catch (DoctrineDBALException $exception) {
} catch (DBALException $e) { if (!$exception->getPrevious() instanceof \PDOException) {
if (! $e->getPrevious() instanceof \PDOException) { $this->logger->critical('Exception occurred: ' . $exception->getMessage());
$this->systemLogger->logException($e);
} }
} catch (\Exception $e) { } catch (\Exception $exception) {
$this->systemLogger->logException($e); $this->logger->critical('Exception occurred: ' . $exception->getMessage());
} }
return false; return false;
} }
/** /**
* @param int $to * @param string|object $source
* @param string|object $type * @param int $number
*
* @return bool * @return bool
* @throws DoctrineDBALDriverException
* @throws DoctrineDBALException
* @throws InvalidSourceException
*/ */
public function advanceTo($to, $type) public function setLastNumberFor($source, int $number): bool
{ {
$type = $this->inferTypeFromSource($type); $type = $this->inferTypeFromSource($source);
return $this->validateFreeNumber($to, $type); if ($this->getLastNumberFor($type) >= $number) {
return false;
}
return $this->insertFor($type, $number);
} }
/** /**
* @param string|object $type * @param string|object $source
* * @throws DoctrineDBALDriverException
* @return int * @throws DoctrineDBALException
* @throws InvalidSourceException
*/ */
public function getLastNumberFor($type) public function getLastNumberFor($source): int
{ {
/* @var EntityManager $em */ return (int)$this->entityManager->getConnection()->executeQuery(
$em = $this->entityManager; 'SELECT MAX(number) FROM '
. $this->entityManager->getClassMetadata(SequenceEntry::class)->getTableName()
return $em->getConnection()->executeQuery( . ' WHERE type = :type',
'SELECT MAX(number) FROM ' . $em->getClassMetadata(Insert::class)->getTableName() . ' WHERE type = :type', ['type' => $this->inferTypeFromSource($source)]
['type' => $this->inferTypeFromSource($type)] )->fetchOne();
)->fetchAll(\PDO::FETCH_COLUMN)[0];
} }
/** /**
* @param string|object $stringOrObject * @param string|object $source
*
* @return string * @return string
* @throws Exception * @throws InvalidSourceException
*/ */
protected function inferTypeFromSource($stringOrObject) protected function inferTypeFromSource($source): string
{ {
if (is_object($stringOrObject)) { if (\is_string($source)) {
$stringOrObject = TypeHandling::getTypeForValue($stringOrObject); return $source;
}
if (! $stringOrObject) {
throw new Exception('No Type given');
} }
return $stringOrObject; if (\is_object($source)) {
return TypeHandling::getTypeForValue($source);
}
throw new InvalidSourceException('Could not infer type from source.', 1632216173);
} }
} }

View file

@ -2,5 +2,5 @@ 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,46 +1,37 @@
<?php <?php
declare(strict_types=1);
namespace Neos\Flow\Persistence\Doctrine\Migrations; namespace Neos\Flow\Persistence\Doctrine\Migrations;
use Doctrine\DBAL\Migrations\AbstractMigration; 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 Version20140505093853 extends AbstractMigration class Version20140505093853 extends AbstractMigration
{ {
/** /**
* @return string * @param Schema $schema
* @throws AbortMigrationException
* @throws DoctrineDBALException
*/ */
public function getDescription() public function up(Schema $schema): void
{ {
return ''; $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, PRIMARY KEY(number, type))');
} }
/** /**
* @param Schema $schema * @param Schema $schema
* @return void * @throws AbortMigrationException
* @throws DoctrineDBALException
*/ */
public function up(Schema $schema) public function down(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('DROP TABLE digicomp_sequence_domain_model_insert');
"CREATE TABLE digicomp_sequence_domain_model_insert (number INT NOT NULL, type VARCHAR(255) NOT NULL, PRIMARY KEY(number, type))"
);
}
/**
* @param Schema $schema
* @return void
*/
public function down(Schema $schema)
{
// this down() migration is autogenerated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql");
$this->addSql("DROP TABLE digicomp_sequence_domain_model_insert");
} }
} }

View file

@ -1,49 +1,36 @@
<?php <?php
declare(strict_types=1);
namespace Neos\Flow\Persistence\Doctrine\Migrations; namespace Neos\Flow\Persistence\Doctrine\Migrations;
use Doctrine\DBAL\Migrations\AbstractMigration; 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
* @return void * @throws AbortMigrationException
* @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
* @return void * @throws AbortMigrationException
* @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,32 +1,39 @@
<?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 Doctrine\DBAL\Driver\Exception as DoctrineDBALDriverException;
use Doctrine\DBAL\Exception as DoctrineDBALException;
use Neos\Flow\Tests\FunctionalTestCase; use Neos\Flow\Tests\FunctionalTestCase;
class SequenceTest extends FunctionalTestCase class SequenceTest extends FunctionalTestCase
{ {
/** /**
* @var bool * @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++) {
@ -39,21 +46,24 @@ class SequenceTest extends FunctionalTestCase
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,39 +1,57 @@
{ {
"name": "digicomp/sequence", "name": "digicomp/sequence",
"type": "neos-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": [ "keywords": [
"flow", "Neos",
"neos", "Flow",
"doctrine", "doctrine",
"sequence" "sequence"
], ],
"homepage": "https://github.com/digital-competence/DigiComp.Sequence",
"license": "MIT",
"authors": [ "authors": [
{ {
"name": "Ferdinand Kuhl", "name": "Ferdinand Kuhl",
"email": "f.kuhl@digital-competence.de", "email": "f.kuhl@digital-competence.de",
"homepage": "http://www.digital-competence.de", "homepage": "https://www.digital-competence.de",
"role": "Developer" "role": "Developer"
} }
], ],
"license": "MIT",
"homepage": "https://github.com/digicomp/DigiComp.Sequence",
"require": { "require": {
"neos/flow": "~4.1|~5.3" "php": ">=7.4.0",
"ext-pdo": "*",
"neos/flow": "^6.3.5 || ^7.0 || ^8.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "3.7.*", "ext-pcntl": "*",
"ext-pcntl": "*" "mikey179/vfsstream": "^1.6.1",
"neos/buildessentials": "^7.0.0",
"phpunit/phpunit": "~8.5",
"vimeo/psalm": "~4.22.0"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"DigiComp\\Sequence\\": "Classes" "DigiComp\\Sequence\\": "Classes/"
} }
}, },
"autoload-dev": {
"psr-4": {
"DigiComp\\Sequence\\Tests\\": "Tests/"
}
},
"config": {
"sort-packages": true,
"platform-check": true
},
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-version/1.x-dev": "1.1.x-dev", "dev-develop": "4.0.x-dev",
"dev-develop": "2.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": [ "applied-flow-migrations": [
"Inwebs.Basket-201409170938", "Inwebs.Basket-201409170938",
@ -67,7 +85,9 @@
"Neos.Flow-20170125103800", "Neos.Flow-20170125103800",
"Neos.Flow-20170127183102", "Neos.Flow-20170127183102",
"DigiComp.SettingValidator-20170603120900", "DigiComp.SettingValidator-20170603120900",
"Neos.Flow-20180415105700" "Neos.Flow-20180415105700",
"Neos.Flow-20190425144900",
"Neos.Flow-20190515215000"
] ]
} }
} }