6 Commits

Author SHA1 Message Date
jbcr
f17322bdd8 cascade remove (#7) 2019-10-17 16:33:53 +02:00
jbcr
90855562ca fix the branch alias for master (#5) 2019-10-15 16:33:19 +02:00
jbcr
776323118a add the required dependencie seld/signal-handler (#4)
* add the requied dependencie seld/signal-handler

* downgrade to 1.0 from 1.2
2019-10-15 15:30:48 +02:00
jbcr
8371e2d1a6 fix command name (#3) 2019-10-15 15:16:03 +02:00
jeremycr
426c7b4324 Added more examples and other improvements in the doc (#2)
* Added more examples and other improvements in the doc

* Fix typo

* Updated README

* Updated README

* Typos
2019-10-11 09:06:24 +02:00
Arnaud Lafon
567a70aa84 Travis and coveralls setup (#1)
* Initial Travis setup

* Downgraded to phpunit 7 because phpunit 8 does not support php 7.1

* Fixed multiple constraint error message issue

* phpcsfixer required in dev & first fix run

* Add coveralls support
2019-10-10 14:37:16 +02:00
11 changed files with 197 additions and 50 deletions

3
.coveralls.yml Normal file
View 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
View 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;

View File

@@ -3,6 +3,10 @@
DataflowBundle is a bundle for Symfony 3.4+
providing an easy way to create import / export dataflow.
[![Build Status](https://travis-ci.org/code-rhapsodie/dataflow-bundle.svg?branch=master)](https://travis-ci.org/code-rhapsodie/dataflow-bundle)
[![Coverage Status](https://coveralls.io/repos/github/code-rhapsodie/dataflow-bundle/badge.svg)](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

View File

@@ -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);

View File

@@ -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"
}
}
}

View File

@@ -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>

View File

@@ -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)
{

View File

@@ -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
*/

View File

@@ -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
*/

View File

@@ -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';
}

View File

@@ -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()
;