liberu-genealogy/php-dna
PHP DNA toolkit for genealogy apps: import and manage raw DNA kits, parse SNP data, compare matches, and work with shared segments and relationships in Laravel or plain PHP. Compact utilities for building genetic genealogy features.
composer require liberu-genealogy/php-dna — v4.0.0 is the current tag. There is no prior assessment, so pin ^4.0 explicitly rather than *; the v3→v4 jump is breaking (see Gotchas).CsvReader entry point and the SNPs collection class. Both were patched in this release for duplicate declarations and syntax errors, which tells you they are the load-bearing classes and the ones to read before anything else.SNPs collection, and persist rows keyed by (kit_id, rsid, chromosome, position).php artisan vendor:publish). If the package exposes config for build numbers or vendor mappings, publish it early so you are not editing vendor code later.Upload → parse → persist (the core workflow).
Store the uploaded raw file on a private disk, dispatch a queued job that streams it through CsvReader, and write SNPs in chunks. Never parse in the request cycle: real raw files are 15–30 MB and ~700k–1M lines.
// app/Jobs/ImportDnaKit.php
public function handle(): void
{
$reader = new CsvReader($this->path);
foreach ($reader->chunks(5000) as $chunk) {
Snp::insert($chunk->map(fn ($s) => [
'kit_id' => $this->kit->id,
'rsid' => $s->rsid,
'chromosome' => $s->chromosome,
'position' => $s->position,
'genotype' => $s->genotype,
])->all());
}
}
Vendor format detection. Wrap vendor sniffing in your own small resolver (header line, comment prefix, column order) and store the detected vendor + genome build on the kit record. Do not re-detect on every read; the build number matters more than anything else downstream.
Kit-to-kit comparison.
Treat comparison as a query, not a package call: join two SNP sets on rsid, filter to shared positions, and compute shared/opposing/no-call counts. This keeps you in Eloquent and lets you cache aggressively per pair.
Triangulation — you now own it.
triangulateKits() was removed in v4.0.0 with no replacement. If you relied on it, reimplement the three-way logic yourself: find segments where A↔B and B↔C overlap on the same chromosome above a cM threshold, then intersect with A↔C. Model segments in a dna_segments table (kit_id, chromosome, start, end, cm, snp_count) and compute overlap with a range query. Persist segments once at import time so triangulation becomes a cheap join instead of a scan.
Visualization is a placeholder only. v4.0.0 adds a "visualization placeholder" alongside the removal. Do not build UI against it — treat it as a marker of intent. Keep chromosome-browser rendering in your own layer (e.g. a Livewire/Inertia component fed by your segments table) so future releases can't break your frontend.
Matching against third-party kits.
Import external kits with a source flag so you can exclude them from user-facing counts and re-run comparisons after a re-import without touching the user's own kit.
triangulateKits() is gone. Any call site will fatal. Grep the codebase for triangulateKits before upgrading, and ship your own implementation (or a shim service) in the same PR. There is no deprecation path and no v3/v4 coexistence.SNPs.php and CsvReader.php. Files that previously "worked" by accident — or failed loudly — may now parse differently. Re-run your fixture tests against real AncestryDNA, 23andMe, MyHeritage and FTDNA exports after upgrading, and diff row counts per kit.-- genotypes, Y and MT chromosomes, and single-allele calls will break naive pairwise genotype comparisons. Normalize on import; decide explicitly whether -- counts as a mismatch.chunk()/generators are the escape hatch.(kit_id, rsid) plus (kit_id, chromosome, position) — comparisons and segment queries both depend on it. Without it, every match is a full scan.DnaImporter / KitMatcher services rather than calling it from controllers. Given the pace of breaking changes here (removal in a single minor bump), an anti-corruption layer is what keeps the next upgrade cheap.How can I help you explore Laravel packages today?