diff --git a/docs/cookbooks/01-common_setup.md b/docs/cookbooks/01-common_setup.md index d34c6d77..351cb050 100644 --- a/docs/cookbooks/01-common_setup.md +++ b/docs/cookbooks/01-common_setup.md @@ -45,3 +45,54 @@ monolog: max_files: 10 channels: ['cleverage_process_task', 'cleverage_process_transformer'] ``` + +Example: lightweight file import +-------------------------------- + +To give more context on how configuration ties to the PHP code, here is a minimal file-import workflow built with classes already shipped in `src/Task/File` and `src/Task/Reporting`. + +```yaml +clever_age_process: + configurations: + app.file_import: + default_error_strategy: stop + tasks: + read_csv: + service: '@CleverAge\ProcessBundle\Task\File\InputFileReaderTask' + options: + file_path: '%kernel.project_dir%/data/products.csv' + format: csv + outputs: [split_rows] + + split_rows: + service: '@CleverAge\ProcessBundle\Task/File/Csv/CsvSplitterTask' + options: + delimiter: ';' + outputs: [transform] + + transform: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + options: + transformers: + mapping: + mapping: + id: { code: '[id]' } + slug: + code: + - '[name]' + - '[category]' + transformers: + implode: + separator: '-' + outputs: [write_csv] + + write_csv: + service: '@CleverAge\ProcessBundle\Task\File/Csv/CsvWriterTask' + options: + file_path: '%kernel.project_dir%/var/output/products_prepared.csv' + headers: + - id + - slug +``` + +Each task above maps to the concrete classes such as `InputFileReaderTask`, `CsvSplitterTask` and `CsvWriterTask` found under `src/Task/File`. Mentioning the `default_error_strategy` helps downstream code in `src/Configuration/ProcessConfiguration.php` know how to propagate failures. diff --git a/docs/cookbooks/etl_aggregate_reports.md b/docs/cookbooks/etl_aggregate_reports.md new file mode 100644 index 00000000..82b2ab6a --- /dev/null +++ b/docs/cookbooks/etl_aggregate_reports.md @@ -0,0 +1,52 @@ +ETL report aggregation +====================== + +This example shows an ETL path that reads several JSON log files, aggregates rates per service, and writes a CSV summary that can feed a dashboard. + +```yaml +clever_age_process: + configurations: + app.etl_report_aggregate: + default_error_strategy: stop + tasks: + list_sources: + service: '@CleverAge\ProcessBundle\Task\File\FolderBrowserTask' + options: + folder: '%kernel.project_dir%/data/logs' + filter: '*.json' + outputs: [read_log] + + read_log: + service: '@CleverAge\ProcessBundle\Task\File\JsonStream\JsonStreamReaderTask' + options: + file_path: '[file]' # value injected from FolderBrowserTask + iterator: items + outputs: [map_log] + + map_log: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + options: + transformers: + mapping: + mapping: + service: { code: '[service]' } + duration: { code: '[duration]' } + status: { code: '[status]' } + outputs: [group_reports] + + group_reports: + service: '@CleverAge\ProcessBundle\Task\GroupByAggregateIterableTask' + options: + group_by: service + aggregate: + duration: { type: 'avg' } + outputs: [write_summary] + + write_summary: + service: '@CleverAge\ProcessBundle\Task\File\Csv\CsvWriterTask' + options: + file_path: '%kernel.project_dir%/var/exports/report_summary.csv' + headers: [service, duration] +``` + +The `FolderBrowserTask`, `JsonStreamReaderTask`, `TransformerTask`, and `GroupByAggregateIterableTask` classes live under `src/Task/File` and `src/Task`. They demonstrate a reusable read/transform/aggregate path for any automation workflow. diff --git a/docs/cookbooks/etl_file_sync.md b/docs/cookbooks/etl_file_sync.md new file mode 100644 index 00000000..3648cc66 --- /dev/null +++ b/docs/cookbooks/etl_file_sync.md @@ -0,0 +1,57 @@ +File synchronization ETL +======================= + +This recipe describes a typical ETL flow: read a CSV file, enrich the data with transformations, then write to another file while keeping a statistics log. + +```yaml +clever_age_process: + configurations: + app.etl_file_sync: + default_error_strategy: stop + tasks: + load_source: + service: '@CleverAge\ProcessBundle\Task\File\InputFileReaderTask' + options: + file_path: '%kernel.project_dir%/data/catalog.csv' + format: csv + outputs: [split_rows] + + split_rows: + service: '@CleverAge\ProcessBundle\Task\File\Csv\CsvSplitterTask' + options: + delimiter: ';' + outputs: [normalize] + + normalize: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + options: + transformers: + mapping: + mapping: + sku: { code: '[sku]' } + price: { code: '[price]', transformers: { cast: { type: float } } } + sent_at: + code: 'format_datetime("[updated_at]", "Y-m-d")' + outputs: [deduplicate] + + deduplicate: + service: '@CleverAge\ProcessBundle\Task\FilterTask' + options: + unique_field: sku + outputs: [write_target] + + write_target: + service: '@CleverAge\ProcessBundle\Task\File\Csv\CsvWriterTask' + options: + file_path: '%kernel.project_dir%/var/exports/catalog_normalized.csv' + headers: [sku,price,sent_at] + outputs: [log_stats] + + log_stats: + service: '@CleverAge\ProcessBundle\Task\Reporting\StatCounterTask' + options: + increment: + rows: 1 +``` + +The `FilterTask` in the sequence corresponds to `src/Task/FilterTask.php`, and the CSV tasks come from `src/Task/File/Csv`. The final counter uses `src/Task/Reporting/StatCounterTask.php` to show how to append a simple metric to the logs. diff --git a/docs/cookbooks/memory_usage_graph.md b/docs/cookbooks/memory_usage_graph.md index c72161f9..6388cb6d 100644 --- a/docs/cookbooks/memory_usage_graph.md +++ b/docs/cookbooks/memory_usage_graph.md @@ -38,3 +38,8 @@ To graph the output of this process, use this Gnuplot command in your host envir ```bash $ gnuplot -e 'while(1) {plot "memory.dat" using 0:1 with lines; pause 1; reread}' ``` + +Alternative: log memory per process phase +------------------------------------------- + +If you want more granular analysis, add multiple `TransformerTask` steps that call `memory_get_usage` before and after a critical moment in your process (e.g., before and after the `TransformerTask` in the CSV import flow above). Dump each value to `memory_phase.dat` with a `CsvWriterTask` that adds `phase` and `memory_usage` columns so you can compare how much heap each phase consumes. diff --git a/docs/cookbooks/performances_monitoring.md b/docs/cookbooks/performances_monitoring.md index 8a7e798d..535ac15b 100644 --- a/docs/cookbooks/performances_monitoring.md +++ b/docs/cookbooks/performances_monitoring.md @@ -46,4 +46,15 @@ CPU Time n/a Memory 5.35MB Network n/a n/a n/a SQL n/a n/a -``` +``` + +Example: measuring CSV processing throughput +------------------------------------------------ + +When you run `cleverage:process:execute` you already benefit from the `ProcessLogger` that records task timing stats under `src/Logger`. To highlight actionable Blackfire runs, log the following steps: + +```bash +blackfire run php bin/console --env=prod cleverage:process:execute app.file_import +``` + +After the JSON output, look for the `ProcessLogger` section (e.g., `timing.cleverage_process.task`) and correlate it with the CSV reader/writer tasks you configured in `docs/cookbooks/01-common_setup.md`. Use those duration metrics to decide whether to parallelize `CsvSplitterTask` with `TransformerTask`, or to revisit buffering logic in `CsvWriterTask`. diff --git a/docs/index.md b/docs/index.md index 26d38e0b..9603e2c4 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,6 +6,8 @@ - [Advanced workflow](04-advanced_workflow.md) - Cookbooks - [Common Setup](cookbooks/01-common_setup.md) + - [ETL file synchronization](cookbooks/etl_file_sync.md) + - [ETL report aggregation](cookbooks/etl_aggregate_reports.md) - [Transformations] - [Flow manipulation] - [Dummy tasks] @@ -32,18 +34,18 @@ - Data manipulation and transformations - [DenormalizerTask](reference/tasks/denormalizer_task.md) - [NormalizerTask](reference/tasks/normalizer_task.md) - - [DeserializerTask] - - [SerializerTask] + - [DeserializerTask](reference/tasks/deserializer_task.md) + - [SerializerTask](reference/tasks/serializer_task.md) - [PropertyGetterTask](reference/tasks/property_getter_task.md) - [PropertySetterTask](reference/tasks/property_setter_task.md) - - [ObjectUpdaterTask] - - [SplitJoinLineTask] + - [ObjectUpdaterTask](reference/tasks/object_updater_task.md) + - [SplitJoinLineTask](reference/tasks/split_join_line_task.md) - [TransformerTask](reference/tasks/transformer_task.md) - - [ValidatorTask] + - [ValidatorTask](reference/tasks/validator_task.md) - File/CSV - [CsvReaderTask](reference/tasks/csv_reader_task.md) - [CsvWriterTask](reference/tasks/csv_writer_task.md) - - [CSVSplitterTask] + - [CsvSplitterTask](reference/tasks/csv_splitter_task.md) - [InputCsvReaderTask](reference/tasks/input_csv_reader_task.md) - File/JsonStream - [JsonStreamReaderTask](reference/tasks/json_stream_reader_task.md) @@ -52,14 +54,14 @@ - [XmlReaderTask](reference/tasks/xml_reader_task.md) - [XmlWriterTask](reference/tasks/xml_writer_task.md) - File/Yaml - - [YamlReaderTask] - - [YamlWriterTask] + - [YamlReaderTask](reference/tasks/yaml_reader_task.md) + - [YamlWriterTask](reference/tasks/yaml_writer_task.md) - File - - [FileMoverTask] + - [FileMoverTask](reference/tasks/file_mover_task.md) - [FileReaderTask](reference/tasks/file_reader_task.md) - - [FileRemoverTask] + - [FileRemoverTask](reference/tasks/file_remover_task.md) - [FileSplitterTask](reference/tasks/file_splitter_task.md) - - [FileWriterTask] + - [FileWriterTask](reference/tasks/file_writer_task.md) - [FolderBrowserTask](reference/tasks/folder_browser_task.md) - [InputFileReaderTask](reference/tasks/input_file_reader_task.md) - [InputFolderBrowserTask](reference/tasks/input_folder_browser_task.md) @@ -69,62 +71,62 @@ - [AggregateIterableTask](reference/tasks/aggregate_iterable_task.md) - [InputAggregatorTask](reference/tasks/input_aggregator_task.md) - [InputIteratorTask](reference/tasks/input_iterator_task.md) - - [ArrayMergeTask] - - [ColumnAggregatorTask] - - [RowAggregatorTask] - - [FilterTask] - - [GroupByAggregateIterableTask] - - [SimpleBatchTask] - - [IterableBatchTask] - - [SkipEmptyTask] - - [StopTask] + - [ArrayMergeTask](reference/tasks/array_merge_task.md) + - [ColumnAggregatorTask](reference/tasks/column_aggregator_task.md) + - [RowAggregatorTask](reference/tasks/row_aggregator_task.md) + - [FilterTask](reference/tasks/filter_task.md) + - [GroupByAggregateIterableTask](reference/tasks/group_by_aggregate_iterable_task.md) + - [SimpleBatchTask](reference/tasks/simple_batch_task.md) + - [IterableBatchTask](reference/tasks/iterable_batch_task.md) + - [SkipEmptyTask](reference/tasks/skip_empty_task.md) + - [StopTask](reference/tasks/stop_task.md) - Process - - [CommandRunnerTask] - - [ProcessExecutorTask] - - [ProcessLauncherTask] + - [CommandRunnerTask](reference/tasks/command_runner_task.md) + - [ProcessExecutorTask](reference/tasks/process_executor_task.md) + - [ProcessLauncherTask](reference/tasks/process_launcher_task.md) - Reporting - - [AdvancedStatCounterTask] + - [AdvancedStatCounterTask](reference/tasks/advanced_stat_counter_task.md) - [LoggerTask](reference/tasks/logger_task.md) - - [StatCounterTask] + - [StatCounterTask](reference/tasks/stat_counter_task.md) - Transformers - Basic and debug - - [CachedTransformer] - - [CallbackTransformer] - - [CastTransformer] - - [ConstantTransformer] - - [ConvertValueTransformer] - - [DebugTransformer] - - [DefaultTransformer] + - [CachedTransformer](reference/transformers/cached_transformer.md) + - [CallbackTransformer](reference/transformers/callback_transformer.md) + - [CastTransformer](reference/transformers/cast_transformer.md) + - [ConstantTransformer](reference/transformers/constant_transformer.md) + - [ConvertValueTransformer](reference/transformers/convert_value_transformer.md) + - [DebugTransformer](reference/transformers/debug_transformer.md) + - [DefaultTransformer](reference/transformers/default_transformer.md) - [GenericTransformer] - - [EvaluatorTransformer] - - [ExpressionLanguageMapTransformer] + - [EvaluatorTransformer](reference/transformers/evaluator_transformer.md) + - [ExpressionLanguageMapTransformer](reference/transformers/expression_language_map_transformer.md) - [MappingTransformer](reference/transformers/mapping_transformer.md) - [MultiReplaceTransformer](reference/transformers/multi_replace_transformer.md) - - [PregFilterTransformer] + - [PregFilterTransformer](reference/transformers/preg_filter_transformer.md) - [RulesTransformer](reference/transformers/rules_transformer.md) - - [TypeSetterTransformer] - - [UnsetTransformer] - - [WrapperTransformer] + - [TypeSetterTransformer](reference/transformers/type_setter_transformer.md) + - [UnsetTransformer](reference/transformers/unset_transformer.md) + - [WrapperTransformer](reference/transformers/wrapper_transformer.md) - Array - - [ArrayElementTransformer] + - [ArrayElementTransformer](reference/transformers/array_element_transformer.md) - [ArrayFilterTransformer](reference/transformers/array_filter_transformer.md) - - [ArrayFirstTransformer] - - [ArrayLastTransformer] + - [ArrayFirstTransformer](reference/transformers/array_first_transformer.md) + - [ArrayLastTransformer](reference/transformers/array_last_transformer.md) - [ArrayMapTransformer](reference/transformers/array_map_transformer.md) - - [ArrayUnsetTransformer] + - [ArrayUnsetTransformer](reference/transformers/array_unset_transformer.md) - Date - [DateFormatTransformer](reference/transformers/date_format.md) - [DateParserTransformer](reference/transformers/date_parser.md) - Object - - [InstantiateTransformer] - - [PropertyAccessorTransformer] - - [RecursivePropertySetterTransformer] + - [InstantiateTransformer](reference/transformers/instantiate_transformer.md) + - [PropertyAccessorTransformer](reference/transformers/property_accessor_transformer.md) + - [RecursivePropertySetterTransformer](reference/transformers/recursive_property_setter_transformer.md) - Serialization - - [DenormalizeTransformer] - - [NormalizeTransformer] + - [DenormalizeTransformer](reference/transformers/denormalize_transformer.md) + - [NormalizeTransformer](reference/transformers/normalize_transformer.md) - String - - [ExplodeTransformer] - - [HashTransformer] + - [ExplodeTransformer](reference/transformers/explode_transformer.md) + - [HashTransformer](reference/transformers/hash_transformer.md) - [ImplodeTransformer](reference/transformers/implode_transformer.md) - [PregMatchTransformer](reference/transformers/preg_match_transformer.md) - [SlugifyTransformer](reference/transformers/slugify_transformer.md) diff --git a/docs/reference/tasks/advanced_stat_counter_task.md b/docs/reference/tasks/advanced_stat_counter_task.md new file mode 100644 index 00000000..c0721474 --- /dev/null +++ b/docs/reference/tasks/advanced_stat_counter_task.md @@ -0,0 +1,46 @@ +AdvancedStatCounterTask +======================= + +Log performance statistics at regular intervals during iteration. Displays time between iterations, items per +second rate, total items processed, and total elapsed time. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\Reporting\AdvancedStatCounterTask` + +Accepted inputs +--------------- + +`any`: input is not used, only the iteration count matters + +Possible outputs +---------------- + +No output is set (the task skips most iterations). Statistics are logged via the logger. + +Options +------- + +| Code | Type | Required | Default | Description | +|--------------|-----------|:--------:|---------|-------------------------------------------------------------------| +| `num_items` | `integer` | | `1` | Number of logical items per iteration (multiplier for rate calc) | +| `skip_first` | `integer` | | `0` | Number of initial iterations to skip before tracking | +| `show_every` | `integer` | | `1` | Display statistics every N iterations | + +Example +------- + +```yaml +# Task configuration level +stats: + service: '@CleverAge\ProcessBundle\Task\Reporting\AdvancedStatCounterTask' + options: + show_every: 100 + num_items: 1 +``` + +Output in logs (every 100 iterations): +``` +Last iteration 00:00:12 ago - 1,50 items/s - 500 items processed in 00:05:33 +``` diff --git a/docs/reference/tasks/array_merge_task.md b/docs/reference/tasks/array_merge_task.md new file mode 100644 index 00000000..ecb86a27 --- /dev/null +++ b/docs/reference/tasks/array_merge_task.md @@ -0,0 +1,39 @@ +ArrayMergeTask +============== + +Merge every input array into a single result using a configurable merge function. The result is only produced once +all preceding tasks are resolved. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\ArrayMergeTask` +* **Blocking task** + +Accepted inputs +--------------- + +`array`: each input must be an array + +Possible outputs +---------------- + +`array`: the merged result of all accumulated input arrays + +Options +------- + +| Code | Type | Required | Default | Description | +|------------------|----------|:--------:|----------------|---------------------------------------------------------------------------------------------------------------------| +| `merge_function` | `string` | | `array_merge` | PHP merge function to use. Allowed: `array_merge`, `array_merge_recursive`, `array_replace`, `array_replace_recursive` | + +Example +------- + +```yaml +# Task configuration level +merge: + service: '@CleverAge\ProcessBundle\Task\ArrayMergeTask' + options: + merge_function: array_replace_recursive +``` diff --git a/docs/reference/tasks/column_aggregator_task.md b/docs/reference/tasks/column_aggregator_task.md new file mode 100644 index 00000000..96206993 --- /dev/null +++ b/docs/reference/tasks/column_aggregator_task.md @@ -0,0 +1,47 @@ +ColumnAggregatorTask +==================== + +Aggregate input rows by column. For each configured column, inputs matching a condition are grouped together. The +result is a map of column values, each containing a reference key and an aggregation array with all matching rows. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\ColumnAggregatorTask` +* **Blocking task** + +Accepted inputs +--------------- + +`array`: each input must be an associative array containing (at least) the configured column keys + +Possible outputs +---------------- + +`array`: associative array keyed by column values, each entry containing: +* ``: the column value +* ``: array of all input rows matching this column + +Options +------- + +| Code | Type | Required | Default | Description | +|-------------------|-----------|:--------:|------------|----------------------------------------------------------------------------------| +| `columns` | `array` | **X** | | List of column keys to aggregate on | +| `reference_key` | `string` | | `column` | Key name for the column reference in the output | +| `aggregation_key` | `string` | | `values` | Key name for the aggregated rows array in the output | +| `condition` | `array` | | | Condition (via [ConditionTrait](../traits/condition_trait.md)) to filter inputs | +| `ignore_missing` | `boolean` | | `false` | If `true`, missing columns produce a warning instead of an exception | + +Example +------- + +```yaml +# Task configuration level +aggregate_columns: + service: '@CleverAge\ProcessBundle\Task\ColumnAggregatorTask' + options: + columns: [status, category] + reference_key: group + aggregation_key: items +``` diff --git a/docs/reference/tasks/command_runner_task.md b/docs/reference/tasks/command_runner_task.md new file mode 100644 index 00000000..d6506d25 --- /dev/null +++ b/docs/reference/tasks/command_runner_task.md @@ -0,0 +1,42 @@ +CommandRunnerTask +================= + +Launch a system command for each input. The input is passed as stdin to the command, and the command's stdout is +set as the task output. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\Process\CommandRunnerTask` + +Accepted inputs +--------------- + +`string|null`: data passed as stdin to the command + +Possible outputs +---------------- + +`string`: the stdout of the executed command + +Options +------- + +| Code | Type | Required | Default | Description | +|---------------|------------------|:--------:|----------------------------|---------------------------------------------------------| +| `commandline` | `string\|array` | **X** | | The command to execute (string or array of arguments) | +| `cwd` | `string` | | Symfony project directory | Working directory for the command | +| `env` | `array\|null` | | `null` | Environment variables (inherits current env if `null`) | +| `timeout` | `integer` | | `60` | Timeout in seconds | + +Example +------- + +```yaml +# Task configuration level +run_command: + service: '@CleverAge\ProcessBundle\Task\Process\CommandRunnerTask' + options: + commandline: ['wc', '-l'] + timeout: 30 +``` diff --git a/docs/reference/tasks/csv_splitter_task.md b/docs/reference/tasks/csv_splitter_task.md new file mode 100644 index 00000000..376c56cb --- /dev/null +++ b/docs/reference/tasks/csv_splitter_task.md @@ -0,0 +1,47 @@ +CsvSplitterTask +=============== + +Split a large CSV file into smaller temporary CSV files, keeping the headers in each resulting file. Iterates over +chunks until the entire source file has been processed. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\File\Csv\CsvSplitterTask` +* **Iterable task** +* **Finalizable task** + +Accepted inputs +--------------- + +Input is ignored (file path comes from options or parent class behavior) + +Possible outputs +---------------- + +`string`: path to a temporary CSV file containing up to `max_lines` rows (plus headers) + +Options +------- + +Inherits all options from [InputCsvReaderTask](input_csv_reader_task.md), plus: + +| Code | Type | Required | Default | Description | +|-------------|-----------|:--------:|---------|-------------------------------------------------| +| `max_lines` | `integer` | | `1000` | Maximum number of data rows per split file | + +Example +------- + +```yaml +# Task configuration level +split_csv: + service: '@CleverAge\ProcessBundle\Task\File\Csv\CsvSplitterTask' + options: + file_path: 'data/large_file.csv' + delimiter: ';' + max_lines: 500 + outputs: [process_chunk] +``` + +Each iteration outputs a temporary file path containing at most 500 rows from the source CSV. diff --git a/docs/reference/tasks/deserializer_task.md b/docs/reference/tasks/deserializer_task.md new file mode 100644 index 00000000..0a9b60e9 --- /dev/null +++ b/docs/reference/tasks/deserializer_task.md @@ -0,0 +1,40 @@ +DeserializerTask +================ + +Deserialize a string input into a PHP object or data structure using Symfony's Serializer component. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\Serialization\DeserializerTask` + +Accepted inputs +--------------- + +`string`: the serialized data to deserialize + +Possible outputs +---------------- + +`any`: the deserialized object or data structure, matching the configured `type` + +Options +------- + +| Code | Type | Required | Default | Description | +|-----------|----------|:--------:|---------|-------------------------------------------------------------------| +| `type` | `string` | **X** | | The target class or type to deserialize into (e.g. `App\Entity\Product`) | +| `format` | `string` | **X** | | Deserialization format (e.g. `json`, `xml`, `csv`) | +| `context` | `array` | | `[]` | Deserialization context passed to the serializer | + +Example +------- + +```yaml +# Task configuration level +deserialize_json: + service: '@CleverAge\ProcessBundle\Task\Serialization\DeserializerTask' + options: + type: 'App\Entity\Product' + format: json +``` diff --git a/docs/reference/tasks/file_mover_task.md b/docs/reference/tasks/file_mover_task.md new file mode 100644 index 00000000..cb53fb92 --- /dev/null +++ b/docs/reference/tasks/file_mover_task.md @@ -0,0 +1,40 @@ +FileMoverTask +============= + +Move the file passed as input to a destination path. Supports overwrite and auto-increment to avoid collisions. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\File\FileMoverTask` + +Accepted inputs +--------------- + +`string`: path to the file to move + +Possible outputs +---------------- + +`string`: the final destination path + +Options +------- + +| Code | Type | Required | Default | Description | +|-----------------|-----------|:--------:|---------|--------------------------------------------------------------------------------------------| +| `destination` | `string` | **X** | | Destination path (file or directory). If a directory, the original filename is preserved. | +| `overwrite` | `boolean` | | `false` | Allow overwriting an existing file at destination | +| `autoincrement` | `boolean` | | `false` | If destination file exists, append an incremented suffix (e.g. `file-1.csv`, `file-2.csv`) | + +Example +------- + +```yaml +# Task configuration level +move_file: + service: '@CleverAge\ProcessBundle\Task\File\FileMoverTask' + options: + destination: '/archive/processed/' + autoincrement: true +``` diff --git a/docs/reference/tasks/file_remover_task.md b/docs/reference/tasks/file_remover_task.md new file mode 100644 index 00000000..37b96cb6 --- /dev/null +++ b/docs/reference/tasks/file_remover_task.md @@ -0,0 +1,28 @@ +FileRemoverTask +=============== + +Simply delete the file or directory passed as input. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\File\FileRemoverTask` + +Accepted inputs +--------------- + +`string`: path to the file or directory to remove + +Possible outputs +---------------- + +No output is set. + +Example +------- + +```yaml +# Task configuration level +cleanup: + service: '@CleverAge\ProcessBundle\Task\File\FileRemoverTask' +``` diff --git a/docs/reference/tasks/file_writer_task.md b/docs/reference/tasks/file_writer_task.md new file mode 100644 index 00000000..4f9d616c --- /dev/null +++ b/docs/reference/tasks/file_writer_task.md @@ -0,0 +1,37 @@ +FileWriterTask +============== + +Write the input content to a file at the configured path. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\File\FileWriterTask` + +Accepted inputs +--------------- + +`string`: content to write to the file + +Possible outputs +---------------- + +`string`: the file path where the content was written + +Options +------- + +| Code | Type | Required | Default | Description | +|------------|----------|:--------:|---------|-------------------------| +| `filename` | `string` | **X** | | Destination file path | + +Example +------- + +```yaml +# Task configuration level +write_file: + service: '@CleverAge\ProcessBundle\Task\File\FileWriterTask' + options: + filename: 'output/result.txt' +``` diff --git a/docs/reference/tasks/filter_task.md b/docs/reference/tasks/filter_task.md new file mode 100644 index 00000000..7fe77028 --- /dev/null +++ b/docs/reference/tasks/filter_task.md @@ -0,0 +1,41 @@ +FilterTask +========== + +Skip inputs that do not match given conditions. When the condition is not met, the input is sent to the error +output and the task is skipped. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\FilterTask` + +Accepted inputs +--------------- + +`any`: value to check against the condition + +Possible outputs +---------------- + +`any`: same as input if the condition is met + +On mismatch, the input is sent to error output and the task is skipped. + +Options +------- + +Options are provided by [ConditionTrait](../traits/condition_trait.md). Equality is softly checked, and a +non-existing key is treated as `null`. + +Example +------- + +```yaml +# Task configuration level +filter_active: + service: '@CleverAge\ProcessBundle\Task\FilterTask' + options: + match: + '[status]': active + errors: [handle_inactive] +``` diff --git a/docs/reference/tasks/group_by_aggregate_iterable_task.md b/docs/reference/tasks/group_by_aggregate_iterable_task.md new file mode 100644 index 00000000..b74a9392 --- /dev/null +++ b/docs/reference/tasks/group_by_aggregate_iterable_task.md @@ -0,0 +1,44 @@ +GroupByAggregateIterableTask +============================ + +Aggregate inputs into an associative array keyed by configurable fields. Later inputs with the same key overwrite +earlier ones, which effectively deduplicates the data. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\GroupByAggregateIterableTask` +* **Blocking task** + +Accepted inputs +--------------- + +`array` or `object`: data accessible via Symfony's PropertyAccessor + +Possible outputs +---------------- + +`array`: associative array keyed by the concatenated group-by values (joined with `-`), or skipped if empty + +Options +------- + +| Code | Type | Required | Default | Description | +|----------------------|---------|:--------:|---------|----------------------------------------------------------------------------------| +| `group_by_accessors` | `array` | **X** | | List of property paths used to build the grouping key | + +Example +------- + +```yaml +# Task configuration level +deduplicate: + service: '@CleverAge\ProcessBundle\Task\GroupByAggregateIterableTask' + options: + group_by_accessors: + - '[type]' + - '[code]' +``` + +With inputs `{type: A, code: 1, ...}` and `{type: A, code: 1, ...}`, the second input overwrites the first, +producing a single entry keyed `A-1`. diff --git a/docs/reference/tasks/object_updater_task.md b/docs/reference/tasks/object_updater_task.md new file mode 100644 index 00000000..72f7da61 --- /dev/null +++ b/docs/reference/tasks/object_updater_task.md @@ -0,0 +1,46 @@ +ObjectUpdaterTask +================= + +Takes an array containing an object and a value, updates the object's property with the given value, then returns +the updated object. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\ObjectUpdaterTask` + +Accepted inputs +--------------- + +`array`: must contain two keys: +* `object`: the object to update +* `value`: the value to set on the property + +Possible outputs +---------------- + +`object`: the updated object + +Options +------- + +| Code | Type | Required | Default | Description | +|-----------------|----------|:--------:|---------|-----------------------------------------------------------| +| `property_path` | `string` | **X** | | Property path on the object where the value will be set | + +Example +------- + +```yaml +# Task configuration level +update_object: + service: '@CleverAge\ProcessBundle\Task\ObjectUpdaterTask' + options: + property_path: 'name' +``` + +With the following input: +```php +['object' => $myEntity, 'value' => 'New Name'] +``` +The task will call `$myEntity->setName('New Name')` and output `$myEntity`. diff --git a/docs/reference/tasks/process_executor_task.md b/docs/reference/tasks/process_executor_task.md new file mode 100644 index 00000000..6895368d --- /dev/null +++ b/docs/reference/tasks/process_executor_task.md @@ -0,0 +1,41 @@ +ProcessExecutorTask +=================== + +Execute another process as a subprocess, passing the current input as the subprocess input. The subprocess output +is set as the task output. This allows chaining and composing processes. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\Process\ProcessExecutorTask` + +Accepted inputs +--------------- + +`any`: passed as input to the subprocess entry point + +Possible outputs +---------------- + +`any`: the output of the subprocess end point + +Options +------- + +| Code | Type | Required | Default | Description | +|-----------|----------|:--------:|---------|-----------------------------------------------------------------------| +| `process` | `string` | **X** | | Code of the process to execute (must exist in the process registry) | +| `context` | `array` | | `[]` | Context variables passed to the subprocess | + +Example +------- + +```yaml +# Task configuration level +run_subprocess: + service: '@CleverAge\ProcessBundle\Task\Process\ProcessExecutorTask' + options: + process: my.sub_process + context: + environment: production +``` diff --git a/docs/reference/tasks/process_launcher_task.md b/docs/reference/tasks/process_launcher_task.md new file mode 100644 index 00000000..6996255f --- /dev/null +++ b/docs/reference/tasks/process_launcher_task.md @@ -0,0 +1,51 @@ +ProcessLauncherTask +=================== + +Launch parallel subprocesses for each input received. Each subprocess is executed as a separate system process +(CLI), allowing true parallelization. The task manages a pool of running processes, waits for them to complete, +and outputs their results. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\Process\ProcessLauncherTask` +* **Iterable task** +* **Flushable task** + +Accepted inputs +--------------- + +`scalar|resource|\Traversable`: input passed as stdin to the subprocess command + +Possible outputs +---------------- + +`any`: the result of each finished subprocess (if available) + +Options +------- + +| Code | Type | Required | Default | Description | +|--------------------------------|------------------|:--------:|---------|------------------------------------------------------------------------------------------| +| `process` | `string` | **X** | | Code of the process to launch (must exist in the process registry) | +| `max_processes` | `integer` | | `3` | Maximum number of concurrent subprocesses | +| `sleep_interval` | `integer\|float` | | `1` | Time in seconds to wait when the pool is full | +| `sleep_interval_after_launch` | `integer\|float` | | `1` | Time in seconds to wait after launching a new subprocess | +| `sleep_on_finalize_interval` | `integer\|float` | | `1` | Time in seconds to wait while checking for remaining processes during finalization | +| `context` | `array` | | `[]` | Context variables passed to subprocesses | +| `json_buffering` | `boolean` | | `false` | Enable JSON buffering for subprocess output | + +Example +------- + +```yaml +# Task configuration level +parallel_launch: + service: '@CleverAge\ProcessBundle\Task\Process\ProcessLauncherTask' + options: + process: my.worker_process + max_processes: 5 + sleep_interval: 0.5 + context: + mode: parallel +``` diff --git a/docs/reference/tasks/row_aggregator_task.md b/docs/reference/tasks/row_aggregator_task.md new file mode 100644 index 00000000..281cdbb4 --- /dev/null +++ b/docs/reference/tasks/row_aggregator_task.md @@ -0,0 +1,59 @@ +RowAggregatorTask +================= + +Aggregate input rows by a common key. Rows sharing the same value for `aggregate_by` are grouped together, with +specified columns collected into a sub-array under `aggregation_key`. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\RowAggregatorTask` +* **Blocking task** + +Accepted inputs +--------------- + +`array`: each input must be an associative array containing the `aggregate_by` key and all `aggregate_columns` keys + +Possible outputs +---------------- + +`array`: indexed array of grouped rows. Each group contains the base row fields (minus the aggregate columns) plus +a `` array containing one entry per aggregated row. + +Options +------- + +| Code | Type | Required | Default | Description | +|---------------------|----------|:--------:|---------|--------------------------------------------------------------------| +| `aggregate_by` | `string` | **X** | | Column key used to group rows together | +| `aggregate_columns` | `array` | **X** | | List of column keys to collect into the aggregation sub-array | +| `aggregation_key` | `string` | **X** | | Key name for the sub-array containing aggregated column values | + +Example +------- + +Given inputs: +``` +{order_id: 1, product: "A", qty: 2} +{order_id: 1, product: "B", qty: 3} +{order_id: 2, product: "C", qty: 1} +``` + +```yaml +# Task configuration level +aggregate_rows: + service: '@CleverAge\ProcessBundle\Task\RowAggregatorTask' + options: + aggregate_by: order_id + aggregate_columns: [product, qty] + aggregation_key: lines +``` + +Output: +``` +[ + {order_id: 1, lines: [{product: "A", qty: 2}, {product: "B", qty: 3}]}, + {order_id: 2, lines: [{product: "C", qty: 1}]} +] +``` diff --git a/docs/reference/tasks/serializer_task.md b/docs/reference/tasks/serializer_task.md new file mode 100644 index 00000000..86dab1b6 --- /dev/null +++ b/docs/reference/tasks/serializer_task.md @@ -0,0 +1,40 @@ +SerializerTask +============== + +Serialize the input data into a given format using Symfony's Serializer component. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\Serialization\SerializerTask` + +Accepted inputs +--------------- + +`any`: data that can be serialized by Symfony's Serializer + +Possible outputs +---------------- + +`string`: the serialized representation of the input in the given format + +Options +------- + +| Code | Type | Required | Default | Description | +|-----------|---------|:--------:|---------|----------------------------------------------------------------| +| `format` | `string`| **X** | | Serialization format (e.g. `json`, `xml`, `csv`) | +| `context` | `array` | | `[]` | Serialization context passed to the serializer | + +Example +------- + +```yaml +# Task configuration level +serialize_to_json: + service: '@CleverAge\ProcessBundle\Task\Serialization\SerializerTask' + options: + format: json + context: + json_encode_options: !php/const JSON_PRETTY_PRINT +``` diff --git a/docs/reference/tasks/simple_batch_task.md b/docs/reference/tasks/simple_batch_task.md new file mode 100644 index 00000000..a8948d8c --- /dev/null +++ b/docs/reference/tasks/simple_batch_task.md @@ -0,0 +1,40 @@ +SimpleBatchTask +=============== + +Accumulate inputs into batches of a configurable size. Once the batch is full, it is output as an array. Any +remaining items are flushed at the end of the iteration. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\SimpleBatchTask` +* **Flushable task** + +Accepted inputs +--------------- + +`any` + +Possible outputs +---------------- + +`array`: array of accumulated inputs, with up to `batch_count` elements + +Options +------- + +| Code | Type | Required | Default | Description | +|---------------|-----------|:--------:|---------|---------------------------------| +| `batch_count` | `integer` | | `10` | Number of items per batch | + +Example +------- + +```yaml +# Task configuration level +batch: + service: '@CleverAge\ProcessBundle\Task\SimpleBatchTask' + options: + batch_count: 50 + outputs: [process_batch] +``` diff --git a/docs/reference/tasks/skip_empty_task.md b/docs/reference/tasks/skip_empty_task.md new file mode 100644 index 00000000..95fe40f5 --- /dev/null +++ b/docs/reference/tasks/skip_empty_task.md @@ -0,0 +1,30 @@ +SkipEmptyTask +============= + +Pass the input to the output, but skip the execution if the input is empty (using PHP's `empty()` check). Useful +when combined with an aggregator task to avoid processing empty results. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\SkipEmptyTask` + +Accepted inputs +--------------- + +`any` + +Possible outputs +---------------- + +`any`: same as input (skipped if input is empty) + +Example +------- + +```yaml +# Task configuration level +skip_if_empty: + service: '@CleverAge\ProcessBundle\Task\SkipEmptyTask' + outputs: [next_task] +``` diff --git a/docs/reference/tasks/split_join_line_task.md b/docs/reference/tasks/split_join_line_task.md new file mode 100644 index 00000000..5c7cfda8 --- /dev/null +++ b/docs/reference/tasks/split_join_line_task.md @@ -0,0 +1,53 @@ +SplitJoinLineTask +================= + +Split a single line (array) into multiple lines based on multiple columns and a split character. Each value from the +split columns produces a new output line, with the split value stored in a configurable join column. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\SplitJoinLineTask` +* **Iterable task** + +Accepted inputs +--------------- + +`array`: a single row with keys, including the columns to split + +Possible outputs +---------------- + +`array`: multiple rows, one for each split value. Each row contains all original columns (except the split columns) +plus a `join_column` containing the individual split value. + +Options +------- + +| Code | Type | Required | Default | Description | +|-------------------|----------|:--------:|---------|--------------------------------------------------| +| `split_columns` | `array` | **X** | | List of column keys whose values will be split | +| `join_column` | `string` | **X** | | Name of the output column containing split values| +| `split_character` | `string` | | `,` | Character used to split column values | + +Example +------- + +* Given input: `{category: "A,B,C", tag: "x,y", name: "Item1"}` + +```yaml +# Task configuration level +split_line: + service: '@CleverAge\ProcessBundle\Task\SplitJoinLineTask' + options: + split_columns: [category, tag] + join_column: value + split_character: ',' +``` + +This will produce 5 iterations: +- `{name: "Item1", value: "A"}` +- `{name: "Item1", value: "B"}` +- `{name: "Item1", value: "C"}` +- `{name: "Item1", value: "x"}` +- `{name: "Item1", value: "y"}` diff --git a/docs/reference/tasks/stat_counter_task.md b/docs/reference/tasks/stat_counter_task.md new file mode 100644 index 00000000..988fc73f --- /dev/null +++ b/docs/reference/tasks/stat_counter_task.md @@ -0,0 +1,34 @@ +StatCounterTask +=============== + +Count the number of times the task is executed. At the end of the process (finalize), logs the total count. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\Reporting\StatCounterTask` +* **Finalizable task** + +Accepted inputs +--------------- + +`any`: input is not used + +Possible outputs +---------------- + +No output is set. The total count is logged during finalization. + +Example +------- + +```yaml +# Task configuration level +count: + service: '@CleverAge\ProcessBundle\Task\Reporting\StatCounterTask' +``` + +At the end of the process, the following will be logged: +``` +Processed item count: 1234 +``` diff --git a/docs/reference/tasks/stop_task.md b/docs/reference/tasks/stop_task.md new file mode 100644 index 00000000..888be73a --- /dev/null +++ b/docs/reference/tasks/stop_task.md @@ -0,0 +1,41 @@ +StopTask +======== + +Immediately stop the process and mark it as failed. Useful to halt execution in an error branch. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\StopTask` + +Accepted inputs +--------------- + +Input is ignored + +Possible outputs +---------------- + +No output is set. The process is stopped and marked as failed. + +Example +------- + +```yaml +# Task configuration level +abort: + service: '@CleverAge\ProcessBundle\Task\StopTask' +``` + +Typically used in an error branch: + +```yaml +validate: + service: '@CleverAge\ProcessBundle\Task\Validation\ValidatorTask' + options: + error_output_violations: true + errors: [abort] + +abort: + service: '@CleverAge\ProcessBundle\Task\StopTask' +``` diff --git a/docs/reference/tasks/validator_task.md b/docs/reference/tasks/validator_task.md new file mode 100644 index 00000000..53d01a50 --- /dev/null +++ b/docs/reference/tasks/validator_task.md @@ -0,0 +1,58 @@ +ValidatorTask +============= + +Validate the input using Symfony's Validator component and pass it to the output. If validation fails, the task +either throws an exception or forwards violations to the error output. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\Validation\ValidatorTask` + +Accepted inputs +--------------- + +`any`: data to validate (object, array, scalar) + +Possible outputs +---------------- + +`any`: same as input if validation passes + +On error (when `error_output_violations` is `true`): +* error output: `ConstraintViolationListInterface` containing the violations + +Options +------- + +| Code | Type | Required | Default | Description | +|----------------------------|-----------------|:--------:|----------------------|------------------------------------------------------------------------------------------------------| +| `log_errors` | `string\|bool` | | `critical` | PSR log level for violation messages. Set to `false` to disable logging | +| `groups` | `array\|null` | | `null` | Validation groups to apply | +| `constraints` | `array\|null` | | `null` | Array of constraints definitions (loaded via `ConstraintLoader`). If `null`, uses class annotations | +| `error_output_violations` | `bool` | | `false` | If `true`, violations are sent to error output and the task is skipped instead of throwing | + +Example +------- + +* Validate input and stop on error + +```yaml +# Task configuration level +validate: + service: '@CleverAge\ProcessBundle\Task\Validation\ValidatorTask' + options: + groups: [import] +``` + +* Validate and forward violations to an error branch + +```yaml +# Task configuration level +validate: + service: '@CleverAge\ProcessBundle\Task\Validation\ValidatorTask' + options: + error_output_violations: true + log_errors: warning + errors: [handle_violations] +``` diff --git a/docs/reference/tasks/yaml_reader_task.md b/docs/reference/tasks/yaml_reader_task.md new file mode 100644 index 00000000..64ecb917 --- /dev/null +++ b/docs/reference/tasks/yaml_reader_task.md @@ -0,0 +1,39 @@ +YamlReaderTask +============== + +Reads a YAML file and iterates over its root elements. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\File\Yaml\YamlReaderTask` +* **Iterable task** + +Accepted inputs +--------------- + +Input is ignored + +Possible outputs +---------------- + +`any`: each root element of the parsed YAML file, one per iteration + +Options +------- + +| Code | Type | Required | Default | Description | +|-------------|----------|:--------:|---------|-----------------------------------------------------------------| +| `file_path` | `string` | **X** | | Path to the YAML file to read. File must exist at resolve time. | + +Example +------- + +```yaml +# Task configuration level +read_yaml: + service: '@CleverAge\ProcessBundle\Task\File\Yaml\YamlReaderTask' + options: + file_path: 'config/data.yaml' + outputs: [process_item] +``` diff --git a/docs/reference/tasks/yaml_writer_task.md b/docs/reference/tasks/yaml_writer_task.md new file mode 100644 index 00000000..55e8676b --- /dev/null +++ b/docs/reference/tasks/yaml_writer_task.md @@ -0,0 +1,39 @@ +YamlWriterTask +============== + +Writes the input data as a YAML file. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\File\Yaml\YamlWriterTask` + +Accepted inputs +--------------- + +`array`: data to dump as YAML + +Possible outputs +---------------- + +`string`: the file path where the YAML was written + +Options +------- + +| Code | Type | Required | Default | Description | +|-------------|-----------|:--------:|---------|--------------------------------------------------------------------------| +| `file_path` | `string` | **X** | | Destination file path | +| `inline` | `integer` | | `4` | Level at which the dumper switches to inline YAML (see `Yaml::dump()`) | + +Example +------- + +```yaml +# Task configuration level +write_yaml: + service: '@CleverAge\ProcessBundle\Task\File\Yaml\YamlWriterTask' + options: + file_path: 'output/export.yaml' + inline: 3 +``` diff --git a/docs/reference/transformers/array_element_transformer.md b/docs/reference/transformers/array_element_transformer.md new file mode 100644 index 00000000..39c536da --- /dev/null +++ b/docs/reference/transformers/array_element_transformer.md @@ -0,0 +1,36 @@ +ArrayElementTransformer +======================= + +Return the nth element of an array (supports negative indices). + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\Array\ArrayElementTransformer` +* **Transformer code**: `array_element` + +Accepted inputs +--------------- + +`array` + +Possible outputs +---------------- + +`any`: the element at the specified index + +Options +------- + +| Code | Type | Required | Default | Description | +|---------|-----------|:--------:|---------|--------------------------------------------------------------| +| `index` | `integer` | **X** | | Position of the element to extract (0-based, negative allowed) | + +Examples +-------- + +```yaml +# Transformer options level +array_element: + index: 2 +``` diff --git a/docs/reference/transformers/array_first_transformer.md b/docs/reference/transformers/array_first_transformer.md new file mode 100644 index 00000000..02c81f87 --- /dev/null +++ b/docs/reference/transformers/array_first_transformer.md @@ -0,0 +1,36 @@ +ArrayFirstTransformer +===================== + +Return the first element of an array. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\Array\ArrayFirstTransformer` +* **Transformer code**: `array_first` + +Accepted inputs +--------------- + +`array` or `iterable` + +Possible outputs +---------------- + +`any`: the first element of the input. If the input is not iterable and `allow_not_iterable` is `false`, the +value is returned as-is. + +Options +------- + +| Code | Type | Required | Default | Description | +|----------------------|--------|:--------:|---------|-----------------------------------------------------------------------| +| `allow_not_iterable` | `bool` | | `false` | If `false`, non-iterable values are returned unchanged | + +Examples +-------- + +```yaml +# Transformer options level +array_first: ~ +``` diff --git a/docs/reference/transformers/array_last_transformer.md b/docs/reference/transformers/array_last_transformer.md new file mode 100644 index 00000000..95a07a51 --- /dev/null +++ b/docs/reference/transformers/array_last_transformer.md @@ -0,0 +1,33 @@ +ArrayLastTransformer +==================== + +Return the last element of an array. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\Array\ArrayLastTransformer` +* **Transformer code**: `array_last` + +Accepted inputs +--------------- + +`array` + +Possible outputs +---------------- + +`any`: the last element of the input array + +Options +------- + +No options. + +Examples +-------- + +```yaml +# Transformer options level +array_last: ~ +``` diff --git a/docs/reference/transformers/array_unset_transformer.md b/docs/reference/transformers/array_unset_transformer.md new file mode 100644 index 00000000..9d594ee6 --- /dev/null +++ b/docs/reference/transformers/array_unset_transformer.md @@ -0,0 +1,36 @@ +ArrayUnsetTransformer +===================== + +Remove a key from an array. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\Array\ArrayUnsetTransformer` +* **Transformer code**: `array_unset` + +Accepted inputs +--------------- + +`array` + +Possible outputs +---------------- + +`array`: the input array without the specified key + +Options +------- + +| Code | Type | Required | Default | Description | +|-------|---------------|:--------:|---------|-----------------------------| +| `key` | `string\|int` | **X** | | The key to remove | + +Examples +-------- + +```yaml +# Transformer options level +array_unset: + key: temporary_field +``` diff --git a/docs/reference/transformers/cached_transformer.md b/docs/reference/transformers/cached_transformer.md new file mode 100644 index 00000000..5136fcff --- /dev/null +++ b/docs/reference/transformers/cached_transformer.md @@ -0,0 +1,48 @@ +CachedTransformer +================= + +Wrap a chain of transformers with a PSR-6 cache layer. If the cache contains a result for the generated key, it is +returned directly. Otherwise, the transformers are applied and the result is stored in cache. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\CachedTransformer` +* **Transformer code**: `cached` + +Accepted inputs +--------------- + +`string`: value used to generate the cache key (via `key_transformers`) + +Possible outputs +---------------- + +`any`: result of the wrapped transformers chain (or cached value) + +Options +------- + +| Code | Type | Required | Default | Description | +|--------------------|-------------------------------|:--------:|---------|-----------------------------------------------------------------------------------------------| +| `cache_key` | `string` | **X** | | Root cache key prefix | +| `ttl` | `string\|DateTimeInterface\|null` | | `null` | Cache expiration. A string is parsed as a DateTime (e.g. `+1 hour`). `null` means no expiry. | +| `transformers` | `array` | | `[]` | Transformers to apply on cache miss, see [TransformerTrait](../traits/transformer_trait.md) | +| `key_transformers` | `array` | | `[]` | Transformers to apply on the value to generate the cache key | + +Examples +-------- + +```yaml +# Transformer options level +cached: + cache_key: my_prefix + ttl: '+1 hour' + key_transformers: + slugify: ~ + transformers: + mapping: + mapping: + name: + code: '[name]' +``` diff --git a/docs/reference/transformers/callback_transformer.md b/docs/reference/transformers/callback_transformer.md new file mode 100644 index 00000000..2acc7e39 --- /dev/null +++ b/docs/reference/transformers/callback_transformer.md @@ -0,0 +1,53 @@ +CallbackTransformer +=================== + +Apply a PHP callable (function or method) on the input value. The value is inserted between configurable left and +right parameters. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\CallbackTransformer` +* **Transformer code**: `callback` + +Accepted inputs +--------------- + +`any`: passed as an argument to the callback + +Possible outputs +---------------- + +`any`: return value of the callback + +Options +------- + +| Code | Type | Required | Default | Description | +|-------------------------|-----------------|:--------:|---------|---------------------------------------------------------------------------------| +| `callback` | `string\|array` | **X** | | A valid PHP callable (e.g. `strtoupper`, `['MyClass', 'myMethod']`) | +| `left_parameters` | `array` | | `[]` | Parameters prepended before the value in the callback call | +| `right_parameters` | `array` | | `[]` | Parameters appended after the value in the callback call | +| `additional_parameters` | `array` | | `[]` | **Deprecated**: use `right_parameters` instead | + +The callback is called as: `callback(...left_parameters, $value, ...right_parameters)` + +Examples +-------- + +* Using a simple PHP function + +```yaml +# Transformer options level +callback: + callback: strtoupper +``` + +* Using a function with parameters + +```yaml +# Transformer options level +callback: + callback: str_pad + right_parameters: [10, '.', !php/const STR_PAD_LEFT] +``` diff --git a/docs/reference/transformers/cast_transformer.md b/docs/reference/transformers/cast_transformer.md new file mode 100644 index 00000000..c127f83f --- /dev/null +++ b/docs/reference/transformers/cast_transformer.md @@ -0,0 +1,36 @@ +CastTransformer +=============== + +Cast the input value to a different PHP type using `settype()`. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\CastTransformer` +* **Transformer code**: `cast` + +Accepted inputs +--------------- + +`any` + +Possible outputs +---------------- + +`any`: the input value cast to the configured type + +Options +------- + +| Code | Type | Required | Default | Description | +|--------|----------|:--------:|---------|-------------------------------------------------------------------------------| +| `type` | `string` | **X** | | Target PHP type (e.g. `int`, `string`, `bool`, `float`, `array`, `object`) | + +Examples +-------- + +```yaml +# Transformer options level +cast: + type: int +``` diff --git a/docs/reference/transformers/constant_transformer.md b/docs/reference/transformers/constant_transformer.md new file mode 100644 index 00000000..5d1fd9cf --- /dev/null +++ b/docs/reference/transformers/constant_transformer.md @@ -0,0 +1,37 @@ +ConstantTransformer +=================== + +Always return the same configured value, ignoring the input. Useful inside a mapping to set a fixed value for a +property. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\ConstantTransformer` +* **Transformer code**: `constant` + +Accepted inputs +--------------- + +Input is ignored + +Possible outputs +---------------- + +`any`: the configured constant value + +Options +------- + +| Code | Type | Required | Default | Description | +|------------|-------|:--------:|---------|--------------------------| +| `constant` | `any` | **X** | | The value to return | + +Examples +-------- + +```yaml +# Transformer options level +constant: + constant: default_value +``` diff --git a/docs/reference/transformers/convert_value_transformer.md b/docs/reference/transformers/convert_value_transformer.md new file mode 100644 index 00000000..4f892103 --- /dev/null +++ b/docs/reference/transformers/convert_value_transformer.md @@ -0,0 +1,56 @@ +ConvertValueTransformer +======================= + +Transform a value into another value based on a conversion map (lookup table). If the value is not found in the +map, the behavior depends on the `ignore_missing` and `keep_missing` options. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\ConvertValueTransformer` +* **Transformer code**: `convert_value` + +Accepted inputs +--------------- + +`string`, `int`, or `null`: a value that can be used as an array key for lookup + +Possible outputs +---------------- + +`any`: the mapped value from the conversion table + +Options +------- + +| Code | Type | Required | Default | Description | +|------------------|-----------|:--------:|---------|-----------------------------------------------------------------------------------| +| `map` | `array` | **X** | | Associative array mapping input values to output values | +| `ignore_missing` | `boolean` | | `false` | If `true`, return `null` when the value is not found in the map | +| `keep_missing` | `boolean` | | `false` | If `true`, return the original value when not found (takes precedence on ignore) | +| `auto_cast` | `boolean` | | `false` | If `true`, cast non-string/int values to string before lookup | + +Examples +-------- + +* Simple value conversion + +```yaml +# Transformer options level +convert_value: + map: + TEXTE: text + NUMERIQUE: number + DATE: date + ignore_missing: true +``` + +* Keep original value when not found + +```yaml +# Transformer options level +convert_value: + map: + old_code: new_code + keep_missing: true +``` diff --git a/docs/reference/transformers/debug_transformer.md b/docs/reference/transformers/debug_transformer.md new file mode 100644 index 00000000..910f1547 --- /dev/null +++ b/docs/reference/transformers/debug_transformer.md @@ -0,0 +1,34 @@ +DebugTransformer +================ + +Dump the current value using Symfony's VarDumper and pass it through unchanged. Useful for debugging transformer +chains. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\DebugTransformer` +* **Transformer code**: `dump` + +Accepted inputs +--------------- + +`any` + +Possible outputs +---------------- + +`any`: same as input (passthrough) + +Options +------- + +No options. + +Examples +-------- + +```yaml +# Transformer options level +dump: ~ +``` diff --git a/docs/reference/transformers/default_transformer.md b/docs/reference/transformers/default_transformer.md new file mode 100644 index 00000000..e5ffa1f8 --- /dev/null +++ b/docs/reference/transformers/default_transformer.md @@ -0,0 +1,37 @@ +DefaultTransformer +================== + +Return a default value when the input is falsy (evaluated with PHP's loose boolean check). If the input is truthy, +it is returned unchanged. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\DefaultTransformer` +* **Transformer code**: `default` + +Accepted inputs +--------------- + +`any` + +Possible outputs +---------------- + +`any`: the input value if truthy, or the configured default value + +Options +------- + +| Code | Type | Required | Default | Description | +|---------|-------|:--------:|---------|------------------------------------------------| +| `value` | `any` | **X** | | The default value to return when input is falsy | + +Examples +-------- + +```yaml +# Transformer options level +default: + value: N/A +``` diff --git a/docs/reference/transformers/denormalize_transformer.md b/docs/reference/transformers/denormalize_transformer.md new file mode 100644 index 00000000..79d3878e --- /dev/null +++ b/docs/reference/transformers/denormalize_transformer.md @@ -0,0 +1,40 @@ +DenormalizeTransformer +====================== + +Denormalize the input data into an object using Symfony's Denormalizer. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\Serialization\DenormalizeTransformer` +* **Transformer code**: `denormalize` + +Accepted inputs +--------------- + +`array`: data to denormalize + +Possible outputs +---------------- + +`object`: an instance of the configured class, populated from the input data + +Options +------- + +| Code | Type | Required | Default | Description | +|-----------|-----------------|:--------:|---------|----------------------------------------------------------| +| `class` | `string` | **X** | | Target class for denormalization | +| `format` | `string\|null` | | `null` | Format hint for the denormalizer | +| `context` | `array` | | `[]` | Denormalization context | + +Examples +-------- + +```yaml +# Transformer options level +denormalize: + class: 'App\Entity\Product' + context: + groups: [import] +``` diff --git a/docs/reference/transformers/evaluator_transformer.md b/docs/reference/transformers/evaluator_transformer.md new file mode 100644 index 00000000..bf280bb3 --- /dev/null +++ b/docs/reference/transformers/evaluator_transformer.md @@ -0,0 +1,42 @@ +EvaluatorTransformer +==================== + +Evaluate a Symfony ExpressionLanguage expression against the input value. The input is used as the expression +variables. + +See [The ExpressionLanguage Component](https://symfony.com/doc/current/components/expression_language.html) for +syntax reference. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\EvaluatorTransformer` +* **Transformer code**: `evaluator` + +Accepted inputs +--------------- + +`array`: an associative array of variables to inject into the expression + +Possible outputs +---------------- + +`any`: the result of the expression evaluation + +Options +------- + +| Code | Type | Required | Default | Description | +|--------------|-------------------|:--------:|---------|-------------------------------------------------------------------------------------------------| +| `expression` | `string` | **X** | | The expression to evaluate | +| `variables` | `array\|null` | | `null` | List of variable names for pre-parsing. If `null`, parsing is deferred (less performant). | + +Examples +-------- + +```yaml +# Transformer options level +evaluator: + expression: 'price * quantity' + variables: [price, quantity] +``` diff --git a/docs/reference/transformers/explode_transformer.md b/docs/reference/transformers/explode_transformer.md new file mode 100644 index 00000000..c5acdc76 --- /dev/null +++ b/docs/reference/transformers/explode_transformer.md @@ -0,0 +1,39 @@ +ExplodeTransformer +================== + +Split a string into an array using a delimiter (PHP's `explode()`). Returns an empty array for `null` or empty +string inputs. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\String\ExplodeTransformer` +* **Transformer code**: `explode` + +Accepted inputs +--------------- + +`string|null` + +Possible outputs +---------------- + +`array`: the exploded parts + +Options +------- + +| Code | Type | Required | Default | Description | +|-------------|----------|:--------:|---------|---------------------------------| +| `delimiter` | `string` | **X** | | The delimiter to split on | + +Examples +-------- + +```yaml +# Transformer options level +explode: + delimiter: ',' +``` + +Input `"a,b,c"` produces `["a", "b", "c"]`. diff --git a/docs/reference/transformers/expression_language_map_transformer.md b/docs/reference/transformers/expression_language_map_transformer.md new file mode 100644 index 00000000..4e7643ee --- /dev/null +++ b/docs/reference/transformers/expression_language_map_transformer.md @@ -0,0 +1,56 @@ +ExpressionLanguageMapTransformer +================================ + +Parse an input using the ExpressionLanguage component and return a specific value based on the first matching +condition. Behaves like a `switch/case` using expressions. + +See [The ExpressionLanguage Component](https://symfony.com/doc/current/components/expression_language.html) for +syntax reference. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\ExpressionLanguageMapTransformer` +* **Transformer code**: `expression_language_map` + +Accepted inputs +--------------- + +`any`: passed as the `data` variable in expressions + +Possible outputs +---------------- + +`any`: the evaluated `output` expression of the first matching `condition` + +Options +------- + +| Code | Type | Required | Default | Description | +|------------------|-----------|:--------:|---------|---------------------------------------------------------------------------------| +| `map` | `array` | **X** | | Ordered list of rules, each with a `condition` and an `output` expression | +| `ignore_missing` | `boolean` | | `false` | If `true`, return `null` when no condition matches | +| `keep_missing` | `boolean` | | `false` | If `true`, return the original value when no condition matches | + +Each entry in `map` must have: + +| Code | Type | Required | Description | +|-------------|----------|:--------:|-------------------------------------------------------| +| `condition` | `string` | **X** | ExpressionLanguage expression evaluated with `data` | +| `output` | `string` | **X** | ExpressionLanguage expression evaluated on match | + +Examples +-------- + +```yaml +# Transformer options level +expression_language_map: + map: + - condition: 'data > 100' + output: '"high"' + - condition: 'data > 50' + output: '"medium"' + - condition: 'data >= 0' + output: '"low"' + ignore_missing: true +``` diff --git a/docs/reference/transformers/hash_transformer.md b/docs/reference/transformers/hash_transformer.md new file mode 100644 index 00000000..7c454789 --- /dev/null +++ b/docs/reference/transformers/hash_transformer.md @@ -0,0 +1,37 @@ +HashTransformer +=============== + +Generate a hash of the input value using PHP's `hash()` function. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\String\HashTransformer` +* **Transformer code**: `hash` + +Accepted inputs +--------------- + +`string`: value to hash + +Possible outputs +---------------- + +`string`: the hash value (hexadecimal by default, raw binary if `raw_output` is `true`) + +Options +------- + +| Code | Type | Required | Default | Description | +|--------------|-----------|:--------:|---------|--------------------------------------------------------------------| +| `algo` | `string` | **X** | | Hash algorithm (e.g. `md5`, `sha256`, `crc32`). See `hash_algos()` | +| `raw_output` | `boolean` | | `false` | If `true`, output raw binary data instead of hexadecimal | + +Examples +-------- + +```yaml +# Transformer options level +hash: + algo: sha256 +``` diff --git a/docs/reference/transformers/instantiate_transformer.md b/docs/reference/transformers/instantiate_transformer.md new file mode 100644 index 00000000..6b243a6d --- /dev/null +++ b/docs/reference/transformers/instantiate_transformer.md @@ -0,0 +1,36 @@ +InstantiateTransformer +====================== + +Create a new object instance of the configured class, using the input array values as constructor arguments. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\Object\InstantiateTransformer` +* **Transformer code**: `instantiate` + +Accepted inputs +--------------- + +`array`: values passed as constructor arguments (in order) + +Possible outputs +---------------- + +`object`: a new instance of the configured class + +Options +------- + +| Code | Type | Required | Default | Description | +|---------|----------|:--------:|---------|------------------------------------------| +| `class` | `string` | **X** | | Fully qualified class name to instantiate | + +Examples +-------- + +```yaml +# Transformer options level +instantiate: + class: 'App\DTO\ProductData' +``` diff --git a/docs/reference/transformers/normalize_transformer.md b/docs/reference/transformers/normalize_transformer.md new file mode 100644 index 00000000..15e783ae --- /dev/null +++ b/docs/reference/transformers/normalize_transformer.md @@ -0,0 +1,38 @@ +NormalizeTransformer +==================== + +Normalize the input value (typically an object) into an array or scalar using Symfony's Normalizer. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\Serialization\NormalizeTransformer` +* **Transformer code**: `normalize` + +Accepted inputs +--------------- + +`any`: data to normalize (typically an object) + +Possible outputs +---------------- + +`array|scalar`: the normalized representation + +Options +------- + +| Code | Type | Required | Default | Description | +|-----------|-----------------|:--------:|---------|-----------------------------------------| +| `format` | `string\|null` | | `null` | Format hint for the normalizer | +| `context` | `array` | | `[]` | Normalization context | + +Examples +-------- + +```yaml +# Transformer options level +normalize: + context: + groups: [export] +``` diff --git a/docs/reference/transformers/preg_filter_transformer.md b/docs/reference/transformers/preg_filter_transformer.md new file mode 100644 index 00000000..17d0b53f --- /dev/null +++ b/docs/reference/transformers/preg_filter_transformer.md @@ -0,0 +1,39 @@ +PregFilterTransformer +===================== + +Apply PHP's `preg_filter()` on the input value. Returns the value after performing a regex search and replace, +or `null` if the pattern does not match. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\PregFilterTransformer` +* **Transformer code**: `preg_filter` + +Accepted inputs +--------------- + +`string`: the value to filter + +Possible outputs +---------------- + +`string|null`: the filtered value, or `null` if the pattern does not match + +Options +------- + +| Code | Type | Required | Default | Description | +|---------------|------------------|:--------:|---------|--------------------------------| +| `pattern` | `string\|array` | **X** | | Regex pattern(s) to search | +| `replacement` | `string\|array` | **X** | | Replacement string(s) | + +Examples +-------- + +```yaml +# Transformer options level +preg_filter: + pattern: '/[^a-z0-9]/' + replacement: '' +``` diff --git a/docs/reference/transformers/property_accessor_transformer.md b/docs/reference/transformers/property_accessor_transformer.md new file mode 100644 index 00000000..1361fa5c --- /dev/null +++ b/docs/reference/transformers/property_accessor_transformer.md @@ -0,0 +1,39 @@ +PropertyAccessorTransformer +=========================== + +Read a property from the input value using Symfony's PropertyAccessor and return it. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\Object\PropertyAccessorTransformer` +* **Transformer code**: `property_accessor` + +Accepted inputs +--------------- + +`array` or `object`: a value readable by Symfony's PropertyAccessor + +Possible outputs +---------------- + +`any`: the value at the configured property path + +Options +------- + +| Code | Type | Required | Default | Description | +|------------------|-----------|:--------:|---------|---------------------------------------------------------------------| +| `property_path` | `string` | **X** | | Property path to read (e.g. `[key]`, `property`, `nested.path`) | +| `ignore_null` | `boolean` | | `false` | If `true`, return `null` when the input value itself is `null` | +| `ignore_missing` | `boolean` | | `false` | If `true`, return `null` when the property path is not readable | + +Examples +-------- + +```yaml +# Transformer options level +property_accessor: + property_path: '[address][city]' + ignore_missing: true +``` diff --git a/docs/reference/transformers/recursive_property_setter_transformer.md b/docs/reference/transformers/recursive_property_setter_transformer.md new file mode 100644 index 00000000..1f57e78a --- /dev/null +++ b/docs/reference/transformers/recursive_property_setter_transformer.md @@ -0,0 +1,49 @@ +RecursivePropertySetterTransformer +=================================== + +Read an iterable collection from the input, then set one or more properties on each item of that collection using +values read from the input itself. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\Object\RecursivePropertySetterTransformer` +* **Transformer code**: `recursive_property_setter` + +Accepted inputs +--------------- + +`array` or `object`: must contain an iterable property (specified by `iterator`) and the source properties +(specified in `set_properties`) + +Possible outputs +---------------- + +`iterable`: the modified collection with properties set on each item + +Options +------- + +| Code | Type | Required | Default | Description | +|-------------------|-----------|:--------:|---------|-----------------------------------------------------------------------------------------------| +| `iterator` | `string` | **X** | | Property path to the iterable collection within the input | +| `set_properties` | `array` | **X** | | Map of `property_name => property_path`, where path is read from the input | +| `ignore_null` | `boolean` | | `false` | If `true`, allow `null` values for source properties | +| `ignore_missing` | `boolean` | | `false` | If `true`, skip unreadable source properties instead of throwing | + +Examples +-------- + +* Set a parent reference on each child item + +```yaml +# Transformer options level +recursive_property_setter: + iterator: 'items' + set_properties: + parentId: 'id' + parentName: 'name' +``` + +With input `{id: 1, name: "Parent", items: [{label: "A"}, {label: "B"}]}`, each item in `items` will receive +`parentId: 1` and `parentName: "Parent"`. diff --git a/docs/reference/transformers/type_setter_transformer.md b/docs/reference/transformers/type_setter_transformer.md new file mode 100644 index 00000000..79e30d2a --- /dev/null +++ b/docs/reference/transformers/type_setter_transformer.md @@ -0,0 +1,37 @@ +TypeSetterTransformer +===================== + +Change the PHP type of the input value using `settype()`. Similar to [CastTransformer](cast_transformer.md) but +with a restricted list of allowed types and explicit error handling. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\TypeSetterTransformer` +* **Transformer code**: `type_setter` + +Accepted inputs +--------------- + +`any` + +Possible outputs +---------------- + +`any`: the input value with its type changed + +Options +------- + +| Code | Type | Required | Default | Description | +|--------|----------|:--------:|---------|-----------------------------------------------------------------------------------------------------------------| +| `type` | `string` | **X** | | Target type. Allowed: `boolean`, `bool`, `integer`, `int`, `float`, `double`, `string`, `array`, `object`, `null` | + +Examples +-------- + +```yaml +# Transformer options level +type_setter: + type: string +``` diff --git a/docs/reference/transformers/unset_transformer.md b/docs/reference/transformers/unset_transformer.md new file mode 100644 index 00000000..745dd612 --- /dev/null +++ b/docs/reference/transformers/unset_transformer.md @@ -0,0 +1,50 @@ +UnsetTransformer +================ + +Remove a property from an input array, optionally based on a condition. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\UnsetTransformer` +* **Transformer code**: `unset` + +Accepted inputs +--------------- + +`array`: the input must be an array containing the property to unset + +Possible outputs +---------------- + +`array`: the input array with the specified property removed (if condition is met) + +Options +------- + +| Code | Type | Required | Default | Description | +|-------------|----------|:--------:|---------|----------------------------------------------------------------------------------| +| `property` | `string` | **X** | | Key to remove from the array | +| `condition` | `array` | | | Condition (via [ConditionTrait](../traits/condition_trait.md)) to check before unsetting | + +Examples +-------- + +* Unconditionally remove a property + +```yaml +# Transformer options level +unset: + property: internal_id +``` + +* Remove only if condition is met + +```yaml +# Transformer options level +unset: + property: debug_info + condition: + match: + '[environment]': production +``` diff --git a/docs/reference/transformers/wrapper_transformer.md b/docs/reference/transformers/wrapper_transformer.md new file mode 100644 index 00000000..4436914d --- /dev/null +++ b/docs/reference/transformers/wrapper_transformer.md @@ -0,0 +1,38 @@ +WrapperTransformer +================== + +Wrap the input value into a single-element array with a configurable key. + +Transformer reference +--------------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\WrapperTransformer` +* **Transformer code**: `wrapper` + +Accepted inputs +--------------- + +`any` + +Possible outputs +---------------- + +`array`: `[wrapper_key => value]` + +Options +------- + +| Code | Type | Required | Default | Description | +|---------------|---------------|:--------:|---------|-------------------------------------| +| `wrapper_key` | `string\|int` | | `0` | Key used to wrap the value | + +Examples +-------- + +```yaml +# Transformer options level +wrapper: + wrapper_key: data +``` + +Input `"hello"` becomes `{data: "hello"}`.