{"id":28905683,"url":"https://github.com/code-rhapsodie/ibexa-dataflow-bundle","last_synced_at":"2026-02-24T15:39:22.383Z","repository":{"id":299707507,"uuid":"902308481","full_name":"code-rhapsodie/ibexa-dataflow-bundle","owner":"code-rhapsodie","description":null,"archived":false,"fork":false,"pushed_at":"2025-11-13T15:20:36.000Z","size":2164,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"v5.x","last_synced_at":"2025-12-29T03:19:50.718Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/code-rhapsodie.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-12-12T10:11:09.000Z","updated_at":"2025-07-04T06:41:46.000Z","dependencies_parsed_at":null,"dependency_job_id":"857e65a6-f006-450e-9979-7d9726a4de5d","html_url":"https://github.com/code-rhapsodie/ibexa-dataflow-bundle","commit_stats":null,"previous_names":["code-rhapsodie/ibexa-dataflow-bundle"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/code-rhapsodie/ibexa-dataflow-bundle","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/code-rhapsodie%2Fibexa-dataflow-bundle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/code-rhapsodie%2Fibexa-dataflow-bundle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/code-rhapsodie%2Fibexa-dataflow-bundle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/code-rhapsodie%2Fibexa-dataflow-bundle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/code-rhapsodie","download_url":"https://codeload.github.com/code-rhapsodie/ibexa-dataflow-bundle/tar.gz/refs/heads/v5.x","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/code-rhapsodie%2Fibexa-dataflow-bundle/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29788320,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-24T10:45:18.109Z","status":"ssl_error","status_checked_at":"2026-02-24T10:45:09.911Z","response_time":75,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-21T13:39:08.062Z","updated_at":"2026-02-24T15:39:22.378Z","avatar_url":"https://github.com/code-rhapsodie.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Code Rhapsodie Ibexa Dataflow Bundle\n\nIbexa DataflowBundle is a bundle\nintegrating [Code Rhapsodie Dataflow bundle](https://github.com/code-rhapsodie/dataflow-bundle) into Ibexa 4.0+.\nDataflows can be piloted from an interface integrated into the Ibexa backoffice.\nIbexa Dataflow bundle is intended to manage content imports from external data sources.\n\n\u003e Note: before using this bundle, please read\n\u003e the [Code Rhapsodie Dataflow bundle documentation](https://github.com/code-rhapsodie/dataflow-bundle/blob/master/README.md).\n\n\u003e Command line notice: When you use Dataflow commands, **use `--siteaccess` instead of `--connection`** except\n\u003e for `code-rhapsodie:dataflow:dump-schema` command.\n\n| Ibexa Dataflow Version | Ibexa Content Version | Status                        |\n|------------------------|-----------------------|-------------------------------|\n| 5.x                    | 4.x                   | :white_check_mark: Maintained |\n\n## User Interface (UI)\n\nThe UI lets you create workflow processes from any defined `DataflowTypes`, and set options to each.\n\nProcesses can be set to run either:\n\n- only once, at a given date and time\n- regularly, by defining the first run date and time, and the interval between subsequent runs\n\n## Installation\n\n### Step 1: Install the bundle via composer\n\n```shell script\n$ composer require code-rhapsodie/ibexa-dataflow-bundle\n```\n\n### Step 2: Enable the bundle\n\n\u003e Note: The loading order between the Dataflow bundle and Ibexa Dataflow bundle is important. Dataflow must be loaded\n\u003e first.\n\nAdd those two lines in the `config/bundles.php` file:\n\n```php\n\u003c?php\n\nreturn [\n     // ...\n    CodeRhapsodie\\DataflowBundle\\CodeRhapsodieDataflowBundle::class =\u003e ['all' =\u003e true],\n    CodeRhapsodie\\IbexaDataflowBundle\\CodeRhapsodieIbexaDataflowBundle::class =\u003e ['all' =\u003e true],\n    // ...\n];\n```\n\n### Step 3: Import bundle routing file\n\n```yaml\n# config/routing/ibexa_dataflow.yaml\n\n_cr.ibexa_dataflow:\n  resource: '@CodeRhapsodieIbexaDataflowBundle/Resources/config/routing.yaml'\n```\n\n### Step 4: Update the database schema\n\nPlease refer to\nthe [Code-Rhapsodie Dataflow Bundle installation guide](https://github.com/code-rhapsodie/dataflow-bundle#update-the-database).\n\n### Step 5: Schedule the job runner\n\nPlease refer to\nthe [Code-Rhapsodie Dataflow Bundle Queue section](https://github.com/code-rhapsodie/dataflow-bundle#queue).\n\n## Configuration\n\nBy default, the `ContentWriter` will publish contents using the `admin` user. If you want to use another user (with\nsufficient permissions), you can configure it like this:\n\n```yaml\n# config/packages/code_rhapsodie_ibexa_dataflow.yaml\n\ncode_rhapsodie_ibexa_dataflow:\n  # Integer values are assumed to be user ids, non-integer values are assumed to be user logins\n  admin_login_or_id: webmaster\n```\n\n## Define your Dataflow\n\nBefore using the admin UI to manage your dataflows, you need to define them. Please refer\nto [Code-Rhapsodie Dataflow type documentation](https://github.com/code-rhapsodie/dataflow-bundle#define-a-dataflow-type).\n\n## Use the ContentWriter\n\nTo add or update Ibexa contents, you can use the `CodeRhapsodie\\IbexaDataflowBundle\\Writer\\ContentWriter` writer.\n\n### Step 1: Inject the dependencies and add the writer\n\nInject the `ContentWriter` service into the constructor of your DataflowType and add the content writer into the writer\nlist like this:\n\n```php\n// In your DataflowType\n\nuse CodeRhapsodie\\IbexaDataflowBundle\\Writer\\ContentWriter;\nuse CodeRhapsodie\\DataflowBundle\\DataflowType\\AbstractDataflowType;\n[...]\n\nclass MyDataflowType extends AbstractDataflowType\n{\n    //[...]\n    public function __construct(private readonly ContentWriter $contentWriter)\n    {\n    }\n    //[...]\n    protected function buildDataflow(DataflowBuilder $builder, array $options): void\n    {\n        //[...]\n        $builder-\u003eaddWriter($this-\u003econtentWriter);\n    }\n}\n```\n\n### Step 2: Add a step for prepare the content\n\nTo process Ibexa contents into your Dataflow, you need to transform the data into `ContentCreateStructure`\nor `ContentUpdateStructure` objects.\nin order to respectively create or update contents.\n\nBut, in order to determine if the content already exists or not, you first need to look up for it.\n\nOne way is to use the remote id to search for the content.\n\nIn the following example, the remote id pattern is `article-\u003cid\u003e` with the `\u003cid\u003e` replaced by the data id provided by\nthe reader.\nTo check if the content exists or not, I use the service `ContentService` provided by Ibexa.\n\nThe step is added as an anonymous function and has 3 types of return values:\n\n* When the step returns `false`, the data is dropped.\n* When the step returns a `ContentCreateStructure`, the data will be saved into a new Ibexa content.\n* When the step returns a `ContentUpdateStructure`, the existing Ibexa content will be updated by overwriting all\n  defined fields in the data.\n\nFor the new content, you must provide one or more \"parent location id\" as the 3rd argument of\nthe `ContentCreateStructure` constructor.\n\nIn this example, I have added a new folder to store all articles.\n\nTo get the location id of the parent Ibexa content, go to the admin UI and select the future parent content, click on\nthe details tabs, and read the \"Location id\" like this:\n\n![parent folder](src/Resources/doc/dest_folder.png)\n\n\u003e Note: the best practice is to define this parent id in your `parameters.yaml` file or your `.env.local` file for each\n\u003e execution environment.\n\n```php\n// In your DataflowType\n\nuse CodeRhapsodie\\IbexaDataflowBundle\\Factory\\ContentStructureFactory;\nuse CodeRhapsodie\\IbexaDataflowBundle\\Writer\\ContentWriter;\nuse CodeRhapsodie\\DataflowBundle\\DataflowType\\AbstractDataflowType;\n[...]\n\nclass MyDataflowType extends AbstractDataflowType\n{\n    //[...]\n    public function __construct(\n        private readonly ContentWriter $contentWriter,\n        private readonly ContentStructureFactory $contentStructureFactory\n    ) {\n    }\n    //[...]\n    protected function buildDataflow(DataflowBuilder $builder, array $options): void\n    {\n        //[...]\n        $builder-\u003eaddStep(function ($data) {\n            if (!isset($data['id'])) {\n                return false;\n            }\n\n            $remoteId = sprintf('article-%d', $data['id']);\n            unset($data['id']);\n\n            return $this-\u003econtentStructureFactory-\u003etransform(\n                $data,\n                $remoteId,\n                'eng-GB',\n                'article2',\n                54, //Parent location id\n                ContentStructureFactoryInterface::MODE_INSERT_OR_UPDATE //Optional value. Other choice : ContentStructureFactoryInterface::MODE_INSERT_ONLY or ContentStructureFactoryInterface::MODE_UPDATE_ONLY\n            );\n        });\n        // If you want the writer log\n        $this-\u003econtentWriter-\u003esetLogger($this-\u003elogger);\n        $builder-\u003eaddWriter($this-\u003econtentWriter);\n    }\n}\n```\n\nThis example uses `ContentStructureFactory` to check if the content exists and returns the adequate `ContentStrucure` to\npass to the content writer.\n\n## Use the NotModifiedContentFilter\n\nWhen updating contents, you might want to ignore contents where the update would not result in any actual changes in\nfields values. In that case, you can add the `NotModifiedContentFilter` as one of your steps.\n\n```php\n// In your DataflowType\npublic function __construct(NotModifiedContentFilter $notModifiedContentFilter)\n{\n    $this-\u003enotModifiedContentFilter = $notModifiedContentFilter;\n}\n\n//[...]\nprotected function buildDataflow(DataflowBuilder $builder, array $options): void\n{\n    //[...]\n    // If you want the filter log\n    $this-\u003enotModifiedContentFilter-\u003esetLogger($this-\u003elogger);\n    $builder-\u003eaddStep($this-\u003enotModifiedContentFilter);\n    //[...]\n}\n```\n\nThis filter compares each field value in the `ContentUpdateStructure` received to the fields values in the existing\ncontent object. If all values are identical, this filter will return `false`, otherwise, the `ContentUpdateStructure`\nwill be returned as is.\n\nNot all field types are supported by this filter. Il a field type is not supported, values will be assumed different. If\nyour dataflow is dealing with content types containing unsupported field types, it is better to simply not use\nthe `NotModifiedContentFilter` to prevent unnecessary overhead.\n\n### Supported field types\n\n- ezstring\n- ezauthor\n- ezboolean\n- ezcountry\n- ezdate\n- ezdatetime\n- ezemail\n- ezfloat\n- ezisbn\n- ezobjectrelation\n- ezobjectrelationlist\n- ezkeyword\n- ezselection\n- eztext\n- eztime\n- eztags\n- novaseometas\n- ezurl\n- ezmatrix\n- ezgmaplocation\n- ezrichtext\n\n### Add custom field comparator\n\nIf you want to add support for a field type, simply create your own comparator.\n\n```php\n\u003c?php\n\nuse CodeRhapsodie\\IbexaDataflowBundle\\Core\\FieldComparator\\AbstractFieldComparator;\nuse Ibexa\\Core\\FieldType\\Value;\n//[...]\n\nclass MyFieldComparator extends AbstractFieldComparator\n{\n    //[...]\n    protected function compareValues(Value $currentValue, Value $newValue): bool\n    {\n        // Return true if values are identical, false if values are different.\n    }\n}\n\n```\n\n```yaml\n# Service declaration\nApp\\FieldComparator\\MyFieldComparator:\n  parent: 'CodeRhapsodie\\IbexaDataflowBundle\\Core\\FieldComparator\\AbstractFieldComparator'\n  tags:\n    - { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'my_field_type_identifier' }\n```\n\n# Admin UI\n\n## Access to the Ibexa Dataflow UI\n\nYou can access the Ibexa Dataflow administration UI from your Ibexa admin back-office.\n\n![Admin menu](src/Resources/doc/admin_menu.png)\n\n1. Click to \"Admin\"\n1. Click to \"Ibexa Dataflow\"\n\n## Scheduled dataflow list\n\nWhen you access to the Ibexa Dataflow administration UI, you arrive on the scheduled dataflow list page:\n\n![Scheduled dataflow list](src/Resources/doc/scheduled_list.png)\n\n1. Scheduled dataflow list\n1. Button to add a new scheduled dataflow\n1. Tools available for each scheduled dataflow. In order from left to right :\n    1. Display the history for this dataflow schedule\n    1. Edit this dataflow schedule\n    1. Enable/Disable this dataflow schedule\n    1. Delete this dataflow schedule\n\n\u003e Note: You can define more than one schedule for any given dataflow.\n\n## Add a new schedule\n\nGo to the Ibexa Dataflow admin, and click on the \"+\" orange button.\n\nIn the new popin, fill in the fields:\n\n![Add a new schedule](src/Resources/doc/add_new_schedule.png)\n\n1. Type the Dataflow schedule name\n1. Select the Dataflow type. The list is automatically generated from the list of Symfony services with the\n   tags `coderhapsodie.dataflow.type`. If your dataflow type is not\n   present, [check the configuration](https://github.com/code-rhapsodie/dataflow-bundle#check-if-your-dataflowtype-is-ready)\n1. Type here the Dataflow options. Basic expected format: one option per line and option name and value separated\n   with `: `. For more complex options, the whole YAML format is supported.\n1. Type here the frequency. The value must be compatible with the the\n   PHP [strtotime](https://www.php.net/manual/en/function.strtotime.php) function.\n1. Choose the date and time of the first job.\n1. Check if you want to run this Dataflow.\n\nFinally, click on the \"Create\" button.\n\n## Read the history\n\nWhen you click on the \"History\" tab in the Ibexa Dataflow admin UI, the job history for all Dataflow configured and\nexecuted is displayed.\n\n![History list](src/Resources/doc/history_list.png)\n\n1. The history list\n1. A summary of each job dates and number of items processed.\n1. Click on the question mark icon to display the job details.\n1. Click on the text icon to display the job exception log.\n1. Switch between displaying all jobs, or only non-empty jobs (at least 1 item was processed)\n\nDetails of one scheduled job:\n\n![Job execution details](src/Resources/doc/job_successful.png)\n\n## One-shot job\n\nIf you don't want to run a Dataflow periodically, you can add a single execution at the time and date that you want.\n\nGo to the Ibexa Dataflow admin UI and click on the \"Oneshot\" tab.\n\n![Oneshot list](src/Resources/doc/oneshot_list.png)\n\n1. This button allows you to create a new one-shot job (see below).\n1. A summary of each job dates and number of items processed.\n1. Click on the question mark icon to display the job details.\n1. Click on the text icon to display the job exception log.\n\nDetails of one-shot job:\n\n![onshot details](src/Resources/doc/job_failed.png)\n\nHere the job has fail.\n\n## Add a one-shot job\n\nGo to the Ibexa Dataflow admin UI and click on the \"Oneshot\" tab. Click on the \"+ Create\" button to open the add popin.\n\n![The add one-shot popin](src/Resources/doc/one_shot_job.png)\n\n1. Type the Dataflow job name\n1. Select the Dataflow type. The list is automatically generated from the list of Symfony services with the\n   tags `coderhapsodie.dataflow.type`. If your dataflow type is not\n   present, [check the configuration](https://github.com/code-rhapsodie/dataflow-bundle#check-if-your-dataflowtype-is-ready)\n1. Type here the Dataflow options. Basic expected format: one option per line and option name and value separated\n   with `: `. For more complex options, the whole YAML format is supported.\n1. Choose the date and time of the first job.\n\nFinally, click on the \"Create\" button.\n\n# Rights\n\nIf a non-administrator user needs read-only access to the dataflow interface, add the `Setup / Administrate`\nand `Ibexa Dataflow / View` policies in one of their roles.\n\n# Issues and feature requests\n\nPlease report issues and request features at https://github.com/code-rhapsodie/ibexa-dataflow-bundle/issues.\n\n# Contributing\n\nContributions are very welcome. Please see [CONTRIBUTING.md](CONTRIBUTING.md) for\ndetails. Thanks\nto [everyone who has contributed](https://github.com/code-rhapsodie/ibexa-dataflow-bundle/graphs/contributors)\nalready.\n\n# License\n\nThis package is licensed under the [MIT license](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcode-rhapsodie%2Fibexa-dataflow-bundle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcode-rhapsodie%2Fibexa-dataflow-bundle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcode-rhapsodie%2Fibexa-dataflow-bundle/lists"}