Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Synchronizer Bundle Laravel Package

ruwork/synchronizer-bundle

Symfony bundle for configurable data synchronization. Define sources, targets, and field mappings, then run repeatable sync operations to keep records consistent between your application and external systems.

View on GitHub
Deep Wiki
Context7

Getting Started

Install — pin the bundle and the library it drives

composer require ruwork/synchronizer-bundle:^0.2

The 0.2.0 release is explicitly "Synchronizer 0.2.x support", so the bundle's only job is to wire ruwork/synchronizer 0.2.x into the container. Treat the pair as one unit:

composer show ruwork/synchronizer-bundle   # confirm the exact tag
composer why ruwork/synchronizer           # confirm which 0.2.x you actually get
composer why-not ruwork/synchronizer 0.2   # if resolution fails, this names the blocker

If your app already requires ruwork/synchronizer directly (common, because you want the classes for type-hints), constrain it to ^0.2 explicitly rather than letting the bundle's transitive constraint decide. Do not mix a 0.1.x synchronizer with the 0.2.0 bundle — see Gotchas.

Register the bundle — it is a classic Symfony bundle, so either add it to config/bundles.php:

Ruwork\SynchronizerBundle\RuworkSynchronizerBundle::class => ['all' => true],

or, on a legacy Symfony 2/3 app, wire it in app/AppKernel.php. If you are not on Symfony Flex, expect to enable it by hand.

Read these first (in order) — there is still no meaningful README, so the source is the documentation:

  1. composer.json of the bundle — the ruwork/synchronizer constraint is the single most informative line in the package. It tells you which library API the bundle assumes.
  2. RuworkSynchronizerBundle.php — tells you what it registers.
  3. DependencyInjection/ (*Extension.php, Configuration.php) — the config tree, which is the contract you actually code against.
  4. Resources/config/ — service ids, tags, and whether anything is public.
  5. The synchronizer 0.2.x classes (Synchronizer, SynchronizerInterface, plus any handler/comparator/resolver interfaces) — this release note is a compatibility bump, not a feature release, so the API surface you program against lives in the library, not the bundle. Read that package's 0.2 changelog for 0.1 -> 0.2 differences.

In a running app, list the services it registers:

bin/console debug:container Synchronizer --show-private
bin/console debug:container --tag=ruwork.synchronizer   # tag name from the compiler pass
bin/console debug:config ruwork_synchronizer            # key from Configuration.php

First use case — the "diff two collections and apply/report the difference" problem: take a source iterable of domain objects and a target collection, compute adds/updates/removes, and apply them. Start with a one-off console command as your smoke test:

// src/Command/SyncCommand.php
protected function execute(InputInterface $in, OutputInterface $out): int
{
    $syncer = $this->getContainer()->get(SomeSynchronizer::class);
    $result = $syncer->synchronize($source, $target); // or ->sync(...)
    $out->writeln(sprintf('+%d ~%d -%d',
        count($result->getAdded() ?? []),
        count($result->getUpdated() ?? []),
        count($result->getRemoved() ?? []),
    ));

    return 0;
}

Verify the actual method name against the 0.2.x interface — do not trust the above signatures; they are the shape, not the API, and 0.2 may have renamed things relative to 0.1. Once the command runs against a staging DB, you have the mental model needed for everything else.

Implementation Patterns

Wrap, don’t scatter. Do not call the synchronizer directly from controllers. Put one thin application service per synchronizable relationship and inject the library's synchronizer into it:

final class OrderLineSynchronizer
{
    public function __construct(private readonly SynchronizerInterface $synchronizer) {}

    public function sync(Order $order, iterable $incoming): SyncReport
    {
        // map DTOs -> entities, then hand both sides to the package
    }
}

This isolates the bundle/library behind your own interface, which matters enormously here: the 0.2.0 release proves the package can move, but a single tag on a previously dormant project is not a support commitment. Swapping it out later becomes a one-file change.

Type-hint the library, not the bundle. Since 0.2.0 exists purely to bind the two together, nothing in your application code should reference Ruwork\SynchronizerBundle\*. Constructor-inject the library interfaces and let the bundle's config supply the wiring. That also means your unit tests need no Symfony kernel.

Console-command workflow. Drive syncs from commands rather than request cycles. Typical flow:

  • --dry-run flag that runs the diff and prints adds/updates/removes without persisting (implement the dry-run in your wrapper, not the bundle).
  • --limit/--batch for large collections; flush inside the loop if the underlying collection is Doctrine-managed.
  • Wrap each run in a transaction only if the synchronizer is side-effect-free and idempotent — verify before assuming.

Doctrine integration. The natural fit is an explicit service call after forms/imports mutate a collection, then let the synchronizer reconcile the owning side. Prefer explicit calls in your service layer over lifecycle listeners: preUpdate/postFlush ordering around collection diffs is exactly where this kind of code becomes hard to debug.

Reporting pattern. If the bundle returns a result object, map it immediately into your own DTO/event (SyncReport, ItemAdded, ItemRemoved). This decouples logging, metrics, and messaging from whatever shape the package uses — and shields you from any 0.2 result-object renames.

Tag-based registration. If the bundle registers synchronizers by tag, use the tag for autoconfiguration:

services:
  _defaults:
    autoconfigure: true
  App\Sync\:
    resource: '../src/Sync/'

Check Configuration.php for the exact tag and required attributes before relying on this. A compatibility-only release is a good moment to re-read it — a tag name that changed in 0.2.0 will fail silently (services simply not registered).

Batch/console composition. For scheduled syncs, register the command in App\Command\ and schedule via cron or a scheduler; the bundle itself has no scheduling opinions.

Gotchas and Tips

  • The 0.2.0 release is one line: "Synchronizer 0.2.x support." That is a compatibility bump, not a maintenance turnaround. It invalidates "unreleased since 2018", but it does not give you a roadmap, a CI badge, or a Symfony 7 promise. Still pin exact versions and still keep the fork/path-repo plan in your back pocket: "repositories": [{"type": "vcs", "url": "https://github.com/yourfork/..."}].
  • Version skew is now the #1 failure mode. The bundle 0.2.0 assumes synchronizer 0.2.x internals. A stale vendor tree, a transitive ^0.1 from another package, or a lockfile you forgot to refresh will boot fine and misbehave at runtime. After upgrading, composer show ruwork/synchronizer and confirm 0.2.x before debugging anything else.
  • Coming from 0.1.x is the real upgrade. Any breaking changes you hit are almost certainly in the library, not the bundle — read ruwork/synchronizer's upgrade notes for the 0.1 -> 0.2 diff and diff your own wrapper's calls against the 0.2 interface. Method/result renames on the synchronizer are the expected breakage.
  • Symfony version ceiling. The bundle's own Symfony constraint may still point at 3.4/4.x. It will probably boot on 5.x with deprecation notices and will likely break on 6/7 due to Bundle class signature changes — the 0.2.0 tag did not necessarily widen this. Test bin/console cache:clear before committing to it.
  • Docs are still absent. debug:container and debug:config (with the bundle’s config key) are your only discovery tools. Do not guess config keys — read Configuration.php.
  • Zero dependents / zero community examples. No Stack Overflow answers, no blog posts. Every integration decision is yours; keep it behind your own interface (see above).
  • Public vs private services. On Symfony 4+ all bundle services default to private, so $container->get() will fail. Inject via constructor in a service instead, or add a compiler-pass alias in your own bundle for the specific service you need.
  • Naming collisions. "Synchronizer" is a crowded namespace (symfony/lock, custom syncers, doctrine/dbal sync tools). Namespace-qualify any service ids you define.
  • Idempotency is not guaranteed. Do not assume re-running is a no-op; write a test that runs synchronize twice and asserts the collection is unchanged the second time before you put it behind cron. Write it now, against 0.2.x, so a future bump has a regression net.
  • Debugging tip. Log the computed adds/removes at debug level from your wrapper — the failure mode of collection reconciliation is usually an equality/identity comparison (=== vs. business key) that silently produces "remove everything, re-add everything." Force the synchronizer to compare on a stable business key rather than object identity. This is also the first thing to re-verify after the 0.2.0 upgrade.
  • Extension point. If the package exposes a "matcher", "comparator", or "resolver" strategy, that is where you customize identity semantics. It is the only part worth extending; everything else should live in your wrapper.
  • Migration path. Given the still-thin maintenance signal, budget for replacement. The wrapper interface you introduce on day one is what you reimplement against a hand-written 50-line diff loop (spl_object_id/business-key maps) if the bundle must go — and the 0.2.0 bump is a reminder to keep that interface narrow.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package