mirror of
https://github.com/code-rhapsodie/dataflow-bundle.git
synced 2026-03-24 14:52:21 +01:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f17322bdd8 | ||
|
|
90855562ca | ||
|
|
776323118a | ||
|
|
8371e2d1a6 | ||
|
|
426c7b4324 | ||
|
|
567a70aa84 |
3
.coveralls.yml
Normal file
3
.coveralls.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
service_name : travis-ci
|
||||
coverage_clover: var/build/clover.xml
|
||||
json_path : var/build/upload.json
|
||||
111
.travis.yml
Normal file
111
.travis.yml
Normal file
@@ -0,0 +1,111 @@
|
||||
language: php
|
||||
|
||||
sudo: false
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- /^\d+\.\d+$/
|
||||
- travis-setup
|
||||
|
||||
env:
|
||||
global:
|
||||
- SYMFONY_DEPRECATIONS_HELPER="max[self]=0"
|
||||
- PHPUNIT_FLAGS="-v"
|
||||
- PHPUNIT_ENABLED="true"
|
||||
- STABILITY=stable
|
||||
- COVERALLS_ENABLED="false"
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- php: '7.1'
|
||||
- php: '7.2'
|
||||
- php: '7.3'
|
||||
|
||||
# Enable code coverage with the latest supported PHP version
|
||||
- php: '7.3'
|
||||
env:
|
||||
- COVERALLS_ENABLED="true"
|
||||
- PHPUNIT_FLAGS="-v --coverage-text --coverage-clover var/build/clover.xml"
|
||||
|
||||
# Minimum supported dependencies with the latest and oldest supported PHP versions
|
||||
- php: '7.1'
|
||||
env:
|
||||
- COMPOSER_FLAGS="--prefer-lowest"
|
||||
- php: '7.3'
|
||||
env:
|
||||
- COMPOSER_FLAGS="--prefer-lowest"
|
||||
|
||||
# Test each supported Symfony version with lowest supported PHP version
|
||||
- php: '7.1'
|
||||
env:
|
||||
- SYMFONY_VERSION=3.4.*
|
||||
- php: '7.1'
|
||||
env:
|
||||
- SYMFONY_VERSION=4.2.*
|
||||
- php: '7.1'
|
||||
env:
|
||||
- SYMFONY_VERSION=4.3.*
|
||||
|
||||
# Test unsupported versions of Symfony
|
||||
- php: '7.1'
|
||||
env:
|
||||
- SYMFONY_VERSION=4.0.*
|
||||
- php: '7.1'
|
||||
env:
|
||||
- SYMFONY_VERSION=4.1.*
|
||||
|
||||
|
||||
# Test upcoming Symfony versions with lowest supported PHP version and dev dependencies
|
||||
- php: '7.1'
|
||||
env:
|
||||
- STABILITY=dev
|
||||
- SYMFONY_VERSION=4.4.*
|
||||
|
||||
# Test upcoming PHP versions with dev dependencies
|
||||
- php: '7.4snapshot'
|
||||
env:
|
||||
- STABILITY=dev
|
||||
- COMPOSER_FLAGS="--ignore-platform-reqs --prefer-stable"
|
||||
|
||||
allow_failures:
|
||||
- env:
|
||||
- SYMFONY_VERSION=4.0.*
|
||||
- env:
|
||||
- SYMFONY_VERSION=4.1.*
|
||||
- env:
|
||||
- STABILITY=dev
|
||||
- COMPOSER_FLAGS="--ignore-platform-reqs --prefer-stable"
|
||||
- env:
|
||||
- STABILITY=dev
|
||||
- SYMFONY_VERSION=4.4.*
|
||||
|
||||
before_install:
|
||||
- if [[ "$SYMFONY_VERSION" != "" ]]; then
|
||||
travis_retry composer global require "symfony/flex:^1.4";
|
||||
composer config extra.symfony.require $SYMFONY_VERSION;
|
||||
fi
|
||||
- if [[ "$STABILITY" != "stable" ]]; then
|
||||
travis_retry composer config minimum-stability $STABILITY;
|
||||
fi
|
||||
- if [[ "$COVERALLS_ENABLED" != "true" ]]; then
|
||||
phpenv config-rm xdebug.ini || true;
|
||||
fi
|
||||
- if [[ "$COVERALLS_ENABLED" == "true" ]]; then
|
||||
travis_retry composer require --dev satooshi/php-coveralls:^2.0 --no-update $COMPOSER_FLAGS;
|
||||
fi
|
||||
|
||||
install:
|
||||
- travis_retry composer update --prefer-dist --no-interaction --no-suggest --no-progress --ansi $COMPOSER_FLAGS
|
||||
|
||||
script: ./vendor/bin/phpunit $PHPUNIT_FLAGS
|
||||
|
||||
after_success:
|
||||
- if [[ "$PHPUNIT_ENABLED" == "true" && "$COVERALLS_ENABLED" == "true" ]]; then
|
||||
./vendor/bin/php-coveralls -vvv --config .coveralls.yml;
|
||||
fi;
|
||||
75
README.md
75
README.md
@@ -3,6 +3,10 @@
|
||||
DataflowBundle is a bundle for Symfony 3.4+
|
||||
providing an easy way to create import / export dataflow.
|
||||
|
||||
[](https://travis-ci.org/code-rhapsodie/dataflow-bundle)
|
||||
|
||||
[](https://coveralls.io/github/code-rhapsodie/dataflow-bundle)
|
||||
|
||||
# Features
|
||||
|
||||
* Define and configure a Dataflow
|
||||
@@ -80,12 +84,12 @@ public function registerBundles()
|
||||
|
||||
### Update the database
|
||||
|
||||
This bundle use Dotrine ORM for drive the database table for store Dataflow schedule (`cr_dataflow_scheduled`)
|
||||
This bundle uses Doctrine ORM for drive the database table for store Dataflow schedule (`cr_dataflow_scheduled`)
|
||||
and jobs (`cr_dataflow_job`).
|
||||
|
||||
#### Doctrine migration
|
||||
|
||||
Execute the command for generate the migration for your database:
|
||||
Execute the command to generate the migration for your database:
|
||||
|
||||
```shell script
|
||||
$ bin/console doctrine:migration:diff
|
||||
@@ -93,7 +97,7 @@ $ bin/console doctrine:migration:diff
|
||||
|
||||
#### Other migration tools
|
||||
|
||||
If you use [Phinx](https://phinx.org/) or [Kaliop Migration Bundle](https://github.com/kaliop-uk/ezmigrationbundle) or whatever,
|
||||
If you use [Phinx](https://phinx.org/) or [Kaliop Migration Bundle](https://github.com/kaliop-uk/ezmigrationbundle) or whatever,
|
||||
you can add a new migration with the generated SQL query from this command:
|
||||
|
||||
```shell script
|
||||
@@ -105,17 +109,17 @@ $ bin/console doctrine:schema:update --dump-sql
|
||||
|
||||
This bundle uses a fixed and simple workflow structure in order to let you focus on the data processing logic part of your dataflow.
|
||||
|
||||
A dataflow type defines the different parts of your dataflow. A dataflow is comprised of:
|
||||
A dataflow type defines the different parts of your dataflow. A dataflow is made of:
|
||||
- exactly one *Reader*
|
||||
- any number of *Steps*
|
||||
- one or more *Writers*
|
||||
|
||||
Dataflow types can be configured with options.
|
||||
|
||||
A dataflow type must implements `CodeRhapsodie\DataflowBundle\DataflowType\DataflowTypeInterface`.
|
||||
A dataflow type must implement `CodeRhapsodie\DataflowBundle\DataflowType\DataflowTypeInterface`.
|
||||
|
||||
To help with creating your workflow types, an abstract class `CodeRhapsodie\DataflowBundle\DataflowType\AbstractDataflowType`
|
||||
is provided, allowing you to define your dataflow through an handy builder `CodeRhapsodie\DataflowBundle\DataflowType\DataflowBuilder`.
|
||||
To help with creating your dataflow types, an abstract class `CodeRhapsodie\DataflowBundle\DataflowType\AbstractDataflowType`
|
||||
is provided, allowing you to define your dataflow through a handy builder `CodeRhapsodie\DataflowBundle\DataflowType\DataflowBuilder`.
|
||||
|
||||
This is an example to define one class DataflowType:
|
||||
|
||||
@@ -176,8 +180,11 @@ class MyFirstDataflowType extends AbstractDataflowType
|
||||
|
||||
```
|
||||
|
||||
The `DataflowTypeInterface` is used by Symfony for auto-configuration our custom datafow type only if the folder is correctly configured (see the `services` configuration file in your projet).
|
||||
If you don't use the auto-configuration, you must add this tag `coderhapsodie.dataflow.type` in your dataflow type service configuration:
|
||||
Dataflow types must be tagged with `coderhapsodie.dataflow.type`.
|
||||
|
||||
If you're using Symfony auto-configuration for your services, this tag will be automatically added to all services implementing `DataflowTypeInterface`.
|
||||
|
||||
Otherwise, manually add the tag `coderhapsodie.dataflow.type` in your dataflow type service configuration:
|
||||
|
||||
```yaml
|
||||
CodeRhapsodie\DataflowExemple\DataflowType\MyFirstDataflowType:
|
||||
@@ -185,9 +192,9 @@ If you don't use the auto-configuration, you must add this tag `coderhapsodie.da
|
||||
- { name: coderhapsodie.dataflow.type }
|
||||
```
|
||||
|
||||
### Use the options for your dataflow type
|
||||
### Use options for your dataflow type
|
||||
|
||||
The `AbstractDataflowType` can help you define the options of your Datataflow type.
|
||||
The `AbstractDataflowType` can help you define options for your Dataflow type.
|
||||
|
||||
Add this method in your DataflowType class:
|
||||
|
||||
@@ -213,7 +220,6 @@ class MyFirstDataflowType extends AbstractDataflowType
|
||||
|
||||
With this configuration, the option `fileName` is required. For an advanced usage of the option resolver, read the [Symfony documentation](https://symfony.com/doc/current/components/options_resolver.html).
|
||||
|
||||
|
||||
### Check if your DataflowType is ready
|
||||
|
||||
Execute this command to check if your DataflowType is correctly registered:
|
||||
@@ -239,9 +245,9 @@ Symfony Container Public and Private Services Tagged with "coderhapsodie.dataflo
|
||||
|
||||
### Readers
|
||||
|
||||
*Readers* provide the workflow with elements to import / export. Usually, elements are read from an external resource (file, database, webservice, etc).
|
||||
*Readers* provide the dataflow with elements to import / export. Usually, elements are read from an external resource (file, database, webservice, etc).
|
||||
|
||||
A *Reader* must implements `Port\Reader` or return a `iterable` if you use the `Port\Reader\IteratorReader`.
|
||||
A *Reader* can be any `iterable`.
|
||||
|
||||
The only constraint on the returned elements typing is that they cannot be `false`.
|
||||
|
||||
@@ -280,10 +286,10 @@ class FileReader
|
||||
}
|
||||
```
|
||||
|
||||
To setup your reader in the dataflow builder, you must use `Port\Reader\IteratorReader` like this
|
||||
You can set up this reader as follows:
|
||||
|
||||
```php
|
||||
$builder->setReader(new \Port\Reader\IteratorReader($this->myReader))
|
||||
$builder->setReader(($this->myReader)())
|
||||
```
|
||||
|
||||
|
||||
@@ -291,18 +297,37 @@ $builder->setReader(new \Port\Reader\IteratorReader($this->myReader))
|
||||
|
||||
*Steps* are operations performed on the elements before they are handled by the *Writers*. Usually, steps are either:
|
||||
- converters, that alter the element
|
||||
- filters, that conditionally prevents further operations on the element
|
||||
- filters, that conditionally prevent further operations on the element
|
||||
|
||||
A *Step* can be any callable, taking the element as its argument, and returning either:
|
||||
- the element, possibly altered
|
||||
- `false`, if no further operations should be performed on this element
|
||||
|
||||
A few examples:
|
||||
|
||||
```php
|
||||
$builder->addStep(function($item) {
|
||||
// Titles are changed to all caps before export
|
||||
$item['title'] = strtoupper($item['title']);
|
||||
|
||||
return $item;
|
||||
});
|
||||
|
||||
$builder->addStep(function($item) {
|
||||
// Private items are not exported
|
||||
if ($item['private']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $item;
|
||||
});
|
||||
```
|
||||
|
||||
### Writers
|
||||
|
||||
*Writers* performs the actual import / export operations.
|
||||
*Writers* perform the actual import / export operations.
|
||||
|
||||
A *Writer* must implements `CodeRhapsodie\DataflowBundle\DataflowType\Writer\WriterInterface`.
|
||||
A *Writer* must implement `CodeRhapsodie\DataflowBundle\DataflowType\Writer\WriterInterface`.
|
||||
As this interface is not compatible with `Port\Writer`, the adapter `CodeRhapsodie\DataflowBundle\DataflowType\Writer\PortWriterAdapter` is provided.
|
||||
|
||||
This example show how to use the predefined PhpPort Writer :
|
||||
@@ -311,7 +336,7 @@ This example show how to use the predefined PhpPort Writer :
|
||||
$builder->addWriter(new PortWriterAdapter(new \Port\FileWriter()));
|
||||
```
|
||||
|
||||
Or you own Writer:
|
||||
Or your own Writer:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@@ -347,17 +372,17 @@ class FileWriter implements WriterInterface
|
||||
|
||||
All pending dataflow job processes are stored in a queue into the database.
|
||||
|
||||
Add this command into your crontab for execute all queued job:
|
||||
Add this command into your crontab for execute all queued jobs:
|
||||
|
||||
```shell script
|
||||
$ SYMFONY_ENV=prod php bin/console code-rhapsodie:dataflow:job:run-pending
|
||||
$ SYMFONY_ENV=prod php bin/console code-rhapsodie:dataflow:run-pending
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
Many commands are provided.
|
||||
Several commands are provided to manage schedules and run jobs.
|
||||
|
||||
`code-rhapsodie:dataflow:job:run-pending` Executes job in the queue according to their schedule.
|
||||
`code-rhapsodie:dataflow:run-pending` Executes job in the queue according to their schedule.
|
||||
|
||||
`code-rhapsodie:dataflow:schedule:list` Display the list of dataflows scheduled.
|
||||
|
||||
@@ -367,7 +392,7 @@ Many commands are provided.
|
||||
|
||||
`code-rhapsodie:dataflow:job:show` Display the last result of a job.
|
||||
|
||||
`code-rhapsodie:dataflow:execute` Lets you execute one dataflow job.
|
||||
`code-rhapsodie:dataflow:execute` Let you execute one dataflow job.
|
||||
|
||||
|
||||
# Issues and feature requests
|
||||
|
||||
@@ -36,7 +36,7 @@ class FrequencyValidatorTest extends ConstraintValidatorTestCase
|
||||
public function testInvalidValue()
|
||||
{
|
||||
$constraint = new Frequency([
|
||||
'invalidMessage' => 'testMessage',
|
||||
'message' => 'testMessage',
|
||||
]);
|
||||
|
||||
$this->validator->validate('wrong value', $constraint);
|
||||
@@ -53,7 +53,7 @@ class FrequencyValidatorTest extends ConstraintValidatorTestCase
|
||||
public function testNegativeIntervals($value)
|
||||
{
|
||||
$constraint = new Frequency([
|
||||
'negativeIntervalMessage' => 'testMessage',
|
||||
'message' => 'testMessage',
|
||||
]);
|
||||
|
||||
$this->validator->validate($value, $constraint);
|
||||
|
||||
@@ -37,21 +37,31 @@
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1",
|
||||
"symfony/dependency-injection": "^3.4||^4.0",
|
||||
"symfony/http-kernel": "^3.4||^4.0",
|
||||
"doctrine/orm": "^2.4.5",
|
||||
"seld/signal-handler": "^1.0",
|
||||
"symfony/config": "^3.4||^4.0",
|
||||
"symfony/yaml": "^3.4||^4.0",
|
||||
"symfony/console": "^3.4||^4.0",
|
||||
"symfony/lock": "^3.4||^4.0",
|
||||
"symfony/dependency-injection": "^3.4||^4.0",
|
||||
"symfony/event-dispatcher": "^3.4||^4.0",
|
||||
"symfony/validator": "^3.4||^4.0",
|
||||
"symfony/http-kernel": "^3.4||^4.0",
|
||||
"symfony/lock": "^3.4||^4.0",
|
||||
"symfony/options-resolver": "^3.4||^4.0",
|
||||
"doctrine/orm": "^2.4.5"
|
||||
"symfony/validator": "^3.4||^4.0",
|
||||
"symfony/yaml": "^3.4||^4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^8.1"
|
||||
"friendsofphp/php-cs-fixer": "^2.15",
|
||||
"phpunit/phpunit": "^7||^8"
|
||||
},
|
||||
"suggest": {
|
||||
"portphp/portphp": "Provides generic readers, steps and writers for your dataflows."
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<ini name="error_reporting" value="-1" />
|
||||
</php>
|
||||
<testsuites>
|
||||
<testsuite name="Port tests suite">
|
||||
<testsuite name="Dataflow tests suite">
|
||||
<directory suffix="Test.php">./Tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
@@ -25,7 +25,7 @@ class Dataflow implements DataflowInterface
|
||||
|
||||
/**
|
||||
* @param iterable $reader
|
||||
* @param null|string $name
|
||||
* @param string|null $name
|
||||
*/
|
||||
public function __construct(iterable $reader, ?string $name)
|
||||
{
|
||||
|
||||
@@ -144,7 +144,7 @@ class Job
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string
|
||||
* @return string|null
|
||||
*/
|
||||
public function getLabel(): ?string
|
||||
{
|
||||
@@ -152,7 +152,7 @@ class Job
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|string $label
|
||||
* @param string|null $label
|
||||
*
|
||||
* @return Job
|
||||
*/
|
||||
@@ -164,7 +164,7 @@ class Job
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string
|
||||
* @return string|null
|
||||
*/
|
||||
public function getDataflowType(): ?string
|
||||
{
|
||||
@@ -172,7 +172,7 @@ class Job
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|string $dataflowType
|
||||
* @param string|null $dataflowType
|
||||
*
|
||||
* @return Job
|
||||
*/
|
||||
|
||||
@@ -78,7 +78,7 @@ class ScheduledDataflow
|
||||
/**
|
||||
* @var Job[]
|
||||
*
|
||||
* @ORM\OneToMany(targetEntity="Job", mappedBy="scheduledDataflow", cascade={"persist"})
|
||||
* @ORM\OneToMany(targetEntity="Job", mappedBy="scheduledDataflow", cascade={"persist", "remove"})
|
||||
* @ORM\OrderBy({"startTime" = "DESC"})
|
||||
*/
|
||||
private $jobs;
|
||||
@@ -92,7 +92,7 @@ class ScheduledDataflow
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string
|
||||
* @return string|null
|
||||
*/
|
||||
public function getLabel(): ?string
|
||||
{
|
||||
@@ -100,7 +100,7 @@ class ScheduledDataflow
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|string $label
|
||||
* @param string|null $label
|
||||
*
|
||||
* @return ScheduledDataflow
|
||||
*/
|
||||
@@ -112,7 +112,7 @@ class ScheduledDataflow
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string
|
||||
* @return string|null
|
||||
*/
|
||||
public function getDataflowType(): ?string
|
||||
{
|
||||
@@ -120,7 +120,7 @@ class ScheduledDataflow
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|string $dataflowType
|
||||
* @param string|null $dataflowType
|
||||
*
|
||||
* @return ScheduledDataflow
|
||||
*/
|
||||
|
||||
@@ -11,7 +11,5 @@ use Symfony\Component\Validator\Constraint;
|
||||
*/
|
||||
class Frequency extends Constraint
|
||||
{
|
||||
public $invalidMessage = 'The provided frequency "{{ string }}" must be a valid parameter for DateInterval::createFromDateString()';
|
||||
|
||||
public $negativeIntervalMessage = 'The provided frequency "{{ string }}" mustn\'t represent a negative interval';
|
||||
public $message = 'The provided frequency "{{ string }}" must be a valid parameter for DateInterval::createFromDateString() and must not represent a negative value';
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ class FrequencyValidator extends ConstraintValidator
|
||||
|
||||
$interval = @\DateInterval::createFromDateString($value);
|
||||
if (!$interval) {
|
||||
$this->context->buildViolation($constraint->invalidMessage)
|
||||
$this->context->buildViolation($constraint->message)
|
||||
->setParameter('{{ string }}', $value)
|
||||
->addViolation()
|
||||
;
|
||||
@@ -38,7 +38,7 @@ class FrequencyValidator extends ConstraintValidator
|
||||
$dt->add($interval);
|
||||
|
||||
if ($dt <= $now) {
|
||||
$this->context->buildViolation($constraint->negativeIntervalMessage)
|
||||
$this->context->buildViolation($constraint->message)
|
||||
->setParameter('{{ string }}', $value)
|
||||
->addViolation()
|
||||
;
|
||||
|
||||
Reference in New Issue
Block a user