byrcsc/laravel-data-sync · 1.x
Sources and connections.
Point a definition at a disk or an inline Flysystem connection, defer files that are still uploading, and decide what happens to the supplier's copy afterwards.
source() returns a Source describing where files arrive and what to do with
them once they have been processed.
use ByRcsc\LaravelDataSync\Definitions\Source;
public function source(): Source
{
return Source::connection('supplier-sftp')
->path('products')
->minFileAge(minutes: 2)
->archiveTo('products/processed');
}Disks and connections
Source::disk() names a filesystem disk from config/filesystems.php:
Source::disk('incoming')->path('products');Source::connection() names an entry in data-sync.connections, an inline
Flysystem configuration array built on demand. Use it for a supplier server that
does not deserve a permanent disk in the application's filesystem config:
// config/data-sync.php
'connections' => [
'supplier-sftp' => [
'driver' => 'sftp',
'host' => env('SUPPLIER_SFTP_HOST'),
'username' => env('SUPPLIER_SFTP_USERNAME'),
'privateKey' => env('SUPPLIER_SFTP_KEY_PATH'),
'root' => '/outbound',
],
],Connection arrays take the same keys the driver takes in
config/filesystems.php. They are validated at boot: a non-array entry, or one
with no driver, throws. An ftp or sftp driver whose Flysystem adapter is
not installed throws too, naming the package to require.
Paths
path() names a directory relative to the disk root:
Source::disk('incoming')->path('products');Every file under that directory is a candidate, including files in subdirectories. Discovery is not filtered by extension or glob — if a definition should only see CSVs, give it a directory that only receives CSVs.
path() may also name a single file, which is what the make:sync stub
generates:
Source::disk('local')->path('imports/products.csv');An empty or missing directory yields no candidates and the run reports zero discovered files. That is a success, not an error.
Deferring files that are still arriving
Source::disk('incoming')->path('products')->minFileAge(minutes: 2);minFileAge() skips files whose modification time is more recent than the given
age, which is how you avoid reading a file the supplier is still uploading. Both
arguments are optional and additive:
->minFileAge(minutes: 1, seconds: 30);Deferred files are counted separately in the command output and picked up on a later run. Nothing is recorded in the ledger for them.
There is no lock coordination with the sender: minFileAge() is a heuristic
based on modification time. For a supplier that can write slowly for longer than
your window, ask for an upload-then-rename or a marker file instead.
What happens to the supplier's copy
By default, nothing. The source file is left exactly where it was, and the package relies on the ledger to avoid reprocessing it.
Three actions change that:
| Method | Effect |
|---|---|
archiveTo($path) | Copies the source file to another path on the source disk |
moveSourceTo($path) | Moves it to another path on the source disk |
deleteFromSource() | Deletes it |
Source::connection('supplier-sftp')
->path('outbound')
->moveSourceTo('outbound/processed');Copies and moves land at <path>/<checksum>-<filename>, so two files with the
same name never collide in the destination.
Three rules govern them:
- They run only after a verified archive. The staged file is copied to the archive disk and its checksum re-verified first. If that fails, the run fails and the source is untouched.
- They run only on a real run. Dry runs never touch the source.
moveSourceTo()wins overdeleteFromSource(). A move already removes the original, so the delete is not attempted.
A failure while applying them — a read-only supplier directory, a dropped SFTP
connection — does not fail the run. The file is already imported and archived;
undoing that would be worse. The message is recorded in the run's warnings
column instead.
Staging
Whatever the source, discovery streams each candidate to the staging disk before anything reads it. Processing, archiving, and transfers all read from staging, so a slow or flaky SFTP server is contacted once per file rather than once per chunk.
That also means staging must be reachable by whichever process eventually reads
the file. On a single machine, the default local disk is fine. Across
machines, see queues and workers.
Checking a source before you trust it
php artisan sync:doctorsync:doctor lists every configured connection and every definition's source,
and reports a failure when one cannot be reached. It is the cheapest way to
catch a rotated SFTP key before a scheduled run does.
What to read next
- File formats and readers for turning a staged file into rows.
- File identity and runs for what discovery records.
- Health checks for what
sync:doctorverifies.