Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Latest

### Changes
* [#10](https://github.com/cleverage/archive-process-bundle/issues/10) Update quality stack: use Rector `withComposerBased()` sets (removed `SYMFONY_64` / `PHPUNIT_100` sets), declare used Symfony packages and PHPUnit range in composer.json, apply quality tools fixes
* [#12](https://github.com/cleverage/archive-process-bundle/issues/12) Add missing documentations: complete reference pages for every Task, complete index and cookbooks. Harmonize and fix existing documentation.

v2.0
------
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
CleverAge/UiProcessBundle
=======================
CleverAge/ArchiveProcessBundle
==============================

This bundle is a part of the [CleverAge/ProcessBundle](https://github.com/cleverage/process-bundle) project.
It provides Archive integration on Process bundle.
Expand All @@ -12,7 +12,7 @@ For usage documentation, see:

## Support & Contribution

For general support and questions, please use [Github](https://github.com/cleverage/ui-process-bundle/issues).
For general support and questions, please use [Github](https://github.com/cleverage/archive-process-bundle/issues).
If you think you found a bug or you have a feature idea to propose, feel free to open an issue after looking at the [contributing](CONTRIBUTING.md) guide.

## License
Expand Down
112 changes: 112 additions & 0 deletions docs/cookbooks/export_archive_upload.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
Export, archive and upload a file
=================================

This recipe describes a typical export flow: read data from a database, write it to a CSV file, zip this file, then
upload the archive to a remote storage (e.g. an SFTP server of a partner).

It requires, besides this bundle, the
[DoctrineProcessBundle](https://github.com/cleverage/doctrine-process-bundle) and the
[FlysystemProcessBundle](https://github.com/cleverage/flysystem-process-bundle), with two Flysystem storages:

```yaml
# config/packages/flysystem.yaml
flysystem:
storages:
local.storage:
adapter: 'local'
options:
directory: '%kernel.project_dir%/var/storage/local'
remote.storage:
adapter: 'sftp'
options:
host: '%env(string:SFTP_HOST)%'
port: 22
username: '%env(string:SFTP_USERNAME)%'
password: '%env(string:SFTP_PASSWORD)%'
root: '%env(string:SFTP_ROOT)%'
```

```yaml
clever_age_process:
configurations:
app.export_archive_upload:
description: 'Export the books, zip the file and upload it to the partner SFTP'
help: 'bin/console cleverage:process:execute app.export_archive_upload'
tasks:
read:
service: '@CleverAge\DoctrineProcessBundle\Task\Database\DatabaseReaderTask'
options:
table: 'book'
sql: 'SELECT b.id, b.title FROM book b ORDER BY b.id'
outputs: [write]

write:
service: '@CleverAge\ProcessBundle\Task\File\Csv\CsvWriterTask'
options:
file_path: '%kernel.project_dir%/var/exports/books_{date}.csv'
headers: [id, title]
outputs: [to_zip_input]

to_zip_input:
service: '@CleverAge\ProcessBundle\Task\TransformerTask'
options:
transformers:
wrapper:
wrapper_key: files # '/.../books_20260930.csv' => { files: '/.../books_20260930.csv' }
outputs: [zip]

zip:
service: '@CleverAge\ArchiveProcessBundle\Task\ZipTask'
options:
filename: '%kernel.project_dir%/var/storage/local/books.zip' # Inside the local.storage root
files_base_path: '%kernel.project_dir%/var/exports' # The archive entry is 'books_20260930.csv'
outputs: [to_storage_path]

to_storage_path:
service: '@CleverAge\ProcessBundle\Task\TransformerTask'
options:
transformers:
callback:
callback: basename # Path relative to the local.storage root: 'books.zip'
outputs: [upload]

upload:
service: '@CleverAge\FlysystemProcessBundle\Task\FileFetchTask'
options:
source_filesystem: 'local.storage'
destination_filesystem: 'remote.storage'
remove_source: true
outputs: [log_upload]

log_upload:
service: '@CleverAge\ProcessBundle\Task\Reporting\LoggerTask'
options:
level: info
message: 'Archive uploaded'
context: [input]
```

How it works:
- [DatabaseReaderTask](https://github.com/cleverage/doctrine-process-bundle/blob/main/docs/reference/tasks/database_reader_task.md)
is iterable: each row of the query goes to the next task.
- [CsvWriterTask](https://github.com/cleverage/process-bundle/blob/main/docs/reference/tasks/csv_writer_task.md) is
blocking: it writes every row, then outputs the path of the CSV file once all rows have been received.
- As the [ZipTask](../reference/tasks/zip_task.md) only accepts an array input, the
[TransformerTask](https://github.com/cleverage/process-bundle/blob/main/docs/reference/tasks/transformer_task.md)
wraps this path under the `files` key with the
[wrapper](https://github.com/cleverage/process-bundle/blob/main/docs/reference/transformers/wrapper_transformer.md)
transformer.
- The [ZipTask](../reference/tasks/zip_task.md) merges this input with its options and creates the archive. As
`files_base_path` is removed from the file path, the CSV file is stored at the root of the archive. The task outputs
the absolute path of the archive.
- The [callback](https://github.com/cleverage/process-bundle/blob/main/docs/reference/transformers/callback_transformer.md)
transformer turns this absolute path into a path relative to the `local.storage` root, as expected by the
[FileFetchTask](https://github.com/cleverage/flysystem-process-bundle/blob/main/docs/reference/tasks/01-FileFetchTask.md),
which copies the archive to `remote.storage` and removes the local one (`remove_source: true`).
- The [LoggerTask](https://github.com/cleverage/process-bundle/blob/main/docs/reference/tasks/logger_task.md) logs the
uploaded file name.

Note that the exported CSV file is kept in `var/exports`. To delete it once archived, add a
[FileRemoverTask](https://github.com/cleverage/process-bundle/blob/main/docs/reference/tasks/file_remover_task.md)
as a second output of the CsvWriterTask (`outputs: [to_zip_input, remove_csv]`): outputs are processed in order, so the
file is removed after the archive has been created.
86 changes: 86 additions & 0 deletions docs/cookbooks/import_archive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
Import the CSV files of an uploaded archive
==========================================

This recipe describes how to import data delivered as a zip archive: the archive path is given as the process input
(from the command line or uploaded through the [UI](https://github.com/cleverage/ui-process-bundle)), it is extracted,
then every CSV file it contains is read line by line.

```yaml
clever_age_process:
configurations:
app.import_archive:
description: 'Import the CSV files of a zip archive'
help: 'bin/console cleverage:process:execute app.import_archive --input=/path/to/archive.zip'
entry_point: prepare # Required to receive the process input
options:
ui:
ui_launch_mode: form
entrypoint_type: file # The uploaded file path is used as input
constraints:
- Collection:
fields:
input:
- File:
mimeTypes: [application/zip]
context: ~
tasks:
prepare:
service: '@CleverAge\ProcessBundle\Task\TransformerTask'
options:
transformers:
wrapper:
wrapper_key: filename # '/path/to/archive.zip' => { filename: '/path/to/archive.zip' }
outputs: [unzip]

unzip:
service: '@CleverAge\ArchiveProcessBundle\Task\UnzipTask'
options:
destination: '%kernel.project_dir%/var/imports/archive'
outputs: [browse]

browse:
service: '@CleverAge\ProcessBundle\Task\File\InputFolderBrowserTask'
options:
name_pattern: '*.csv'
outputs: [read]

read:
service: '@CleverAge\ProcessBundle\Task\File\Csv\InputCsvReaderTask'
options:
delimiter: ';'
outputs: [count_rows, log_row]

count_rows:
service: '@CleverAge\ProcessBundle\Task\Reporting\StatCounterTask'

log_row:
service: '@CleverAge\ProcessBundle\Task\Reporting\LoggerTask'
options:
level: info
message: 'Imported line' # Replace this task by your own transformation / loading tasks
context: [input]
```

How it works:
- The process input is the path of the archive (`--input` option, or the uploaded file when launched from the UI with
`entrypoint_type: file`). As the [UnzipTask](../reference/tasks/unzip_task.md) only accepts an array input, the
[TransformerTask](https://github.com/cleverage/process-bundle/blob/main/docs/reference/tasks/transformer_task.md)
wraps it under the `filename` key with the
[wrapper](https://github.com/cleverage/process-bundle/blob/main/docs/reference/transformers/wrapper_transformer.md)
transformer.
- The [UnzipTask](../reference/tasks/unzip_task.md) merges this input with its options (`destination`), extracts the
archive and outputs the destination directory.
- [InputFolderBrowserTask](https://github.com/cleverage/process-bundle/blob/main/docs/reference/tasks/input_folder_browser_task.md)
is iterable: it outputs, one by one, the path of each CSV file found in the extracted directory (recursively).
- [InputCsvReaderTask](https://github.com/cleverage/process-bundle/blob/main/docs/reference/tasks/input_csv_reader_task.md)
is iterable too: each line of the current file goes through the following tasks before the next one is read.
- [StatCounterTask](https://github.com/cleverage/process-bundle/blob/main/docs/reference/tasks/stat_counter_task.md)
logs the total count of imported lines at the end of the process, and the
[LoggerTask](https://github.com/cleverage/process-bundle/blob/main/docs/reference/tasks/logger_task.md) stands for
your own import tasks.

Note that the extraction directory is not emptied before extracting: files of a previous archive are browsed again if
they are still present. Use a dedicated directory per execution (e.g. with a
[contextual option](https://github.com/cleverage/process-bundle/blob/main/docs/reference/02-task_definition.md)
`destination: '%kernel.project_dir%/var/imports/{{ import_id }}'` and `-c import_id:"'...'"`), or clean it after the
import.
33 changes: 27 additions & 6 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
CleverAge/ArchiveProcessBundle
==============================

This bundle provides tasks to create and extract zip archives in
[CleverAge/ProcessBundle](https://github.com/cleverage/process-bundle) processes.

## Prerequisite

CleverAge/ProcessBundle must be [installed](https://github.com/cleverage/process-bundle/blob/main/docs/01-quick_start.md#installation.
CleverAge/ProcessBundle must be [installed](https://github.com/cleverage/process-bundle/blob/main/docs/01-quick_start.md#installation).

The PHP [zip extension](https://www.php.net/manual/en/book.zip.php) (`ext-zip`) is required.

## Installation

Expand All @@ -13,14 +21,27 @@ Open a command console, enter your project directory and install it using compos
composer require cleverage/archive-process-bundle
```

Remember to add the following line to config/bundles.php (not required if Symfony Flex is used)
Remember to add the following line to `config/bundles.php` (not required if Symfony Flex is used):

```php
CleverAge\ArchiveProcessBundle\CleverAgeArchiveProcessBundle::class => ['all' => true],
```

## Reference
## Configuration

This bundle has no configuration: its tasks are registered as services (public, non-shared) and can be used directly
in your processes by referencing their class name, e.g. `service: '@CleverAge\ArchiveProcessBundle\Task\ZipTask'`.

Both tasks accept their options either from the task configuration or from their input (an array merged with the
options), which allows computing paths in a previous task.

## Documentation

- Tasks
- [UnzipTask](reference/tasks/unzip_task.md)
- [ZipTask](reference/tasks/zip_task.md)
- Cookbooks
- [Import the CSV files of an uploaded archive](cookbooks/import_archive.md)
- [Export, archive and upload a file](cookbooks/export_archive_upload.md)
- Reference
- Tasks
- [UnzipTask](reference/tasks/unzip_task.md)
- [ZipTask](reference/tasks/zip_task.md)
- [ProcessBundle documentation](https://github.com/cleverage/process-bundle/blob/main/docs/index.md)
33 changes: 18 additions & 15 deletions docs/reference/tasks/_template.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,47 @@
TaskName
========

_Describe main goal an use cases of the task_
_Describe the main goal and use cases of the task._

Task reference
--------------

* **Service**: `ClassName`
* **Service**: `Fully\Qualified\ClassName`
* **Iterable task** _(only if it implements `IterableTaskInterface`)_
* **Blocking task** _(only if it implements `BlockingTaskInterface`)_
* **Flushable task** _(only if it implements `FlushableTaskInterface`)_

Accepted inputs
---------------

_Description of allowed types_
_Description of allowed types, or "Input is ignored"._

Possible outputs
----------------

_Description of possible types_
_Description of possible types._

Options
-------

| Code | Type | Required | Default | Description |
| ---- | ---- | :------: | ------- | ----------- |
| `code` | `type` | **X** _or nothing_ | `default value` _if available_ | _description_ |
| Code | Type | Required | Default | Description |
|--------|--------|:--------:|-----------------|---------------|
| `code` | `type` | **X** | `default value` | _description_ |

_If the task has no option, replace the table with "This task has no option."._

Examples
--------

_YAML samples and explanations_

* Example 1
- details
- details


```yaml
# Task configuration level
code:
service: '@service_ref'
options:
a: 1
b: 2
service: '@Fully\Qualified\ClassName'
options:
a: 1
b: 2
outputs: [next_task]
```
Loading
Loading