A Laravel package for managing bibliographic references with full import/export support for Zotero, EndNote, and Mendeley.
- Features
- Requirements
- Installation
- Quick Start
- Usage
- Supported Formats
- API Reference
- Testing
- Contributing
- License
- Multi-format Import/Export - RIS, BibTeX, CSL-JSON, and EndNote XML
- Smart Deduplication - DOI exact match + title+year fuzzy matching
- Collection Management - Named reference lists with notes and tagging
- Event-Driven - Fire events for logging and post-processing hooks
- Streaming Exports - Memory-safe exports for large collections
- SLR Integration - Filter and export screened/included documents
v1.0 - Stable. Parsers, importer, and exporter are production-ready.
| Component | Status |
|---|---|
| RIS Parser/Exporter | ✅ Stable |
| BibTeX Parser/Exporter | ✅ Stable |
| CSL-JSON Parser/Exporter | ✅ Stable |
| EndNote XML Parser/Exporter | ✅ Stable |
| Deduplication | ✅ Stable |
| Events & Logging | ✅ Stable |
| Streaming Exports | ✅ Stable |
| Facade Helpers | 🧪 Experimental |
- PHP 8.2+
- Laravel 11.x / 12.x / 13.x
- SQLite (for testing)
composer require nexus/refmanagerphp artisan vendor:publish --tag=refmanager-configphp artisan migrateuse Nexus\RefManager\Concerns\HasBibliographicExport;
class Document extends Model
{
use HasBibliographicExport;
}use Nexus\RefManager\ReferenceImporter;
// Import from file (auto-detects format)
$result = app(ReferenceImporter::class)
->withOptions(['deduplicate' => true, 'save' => true])
->fromFile('library.ris');
// Import from string with explicit format
$result = app(ReferenceImporter::class)
->fromString($risContent, 'ris');use Nexus\RefManager\ReferenceExporter;
// Export as string
$ris = app(ReferenceExporter::class)->toString($documents, 'ris');
// Export as streaming download
return app(ReferenceExporter::class)
->toResponse($documents, 'bibtex', 'library.bib');# Import a file
php artisan refmanager:import library.ris --project=1
# Dry-run import
php artisan refmanager:import library.ris --dry-run
# Export documents
php artisan refmanager:export --project=1 --format=ris --output=library.ris
# List supported formats
php artisan refmanager:formats| Format | Extension | MIME Type | Import | Export |
|---|---|---|---|---|
| RIS | .ris |
application/x-research-info-systems |
✅ | ✅ |
| BibTeX | .bib |
application/x-bibtex |
✅ | ✅ |
| CSL-JSON | .json |
application/vnd.citationstyles.csl+json |
✅ | ✅ |
| EndNote XML | .xml |
application/xml |
✅ | ✅ |
// From file (auto-detects format by extension)
$result = $importer->fromFile('/path/to/library.ris');
// From uploaded file
$result = $importer->fromUpload($request->file('library'));
// From raw string
$result = $importer->fromString($content, 'ris');
// With options
$result = $importer->withOptions([
'deduplicate' => true, // default: true
'save' => false, // default: false (return unsaved models)
'project_id' => 7,
'collection_id' => 42,
])->fromFile('/path/to/library.bib');By default, project_id is passed through the importer and API but no project filter is applied unless you configure one.
This keeps the package schema-agnostic for apps that do not store project ownership on the document table.
After publishing config, set refmanager.deduplication.project_scope to a callable:
// config/refmanager.php
'deduplication' => [
// ...
'project_scope' => static function ($query, int $projectId): void {
$query->where('project_id', $projectId);
},
],Notes:
- The callback receives the Eloquent query builder and the incoming
project_id. - The callback is applied to DOI, PubMed, and title/year deduplication tiers.
- If
project_scopeisnull, deduplication remains global.
$result->documents; // All parsed records (including duplicates)
$result->imported; // Net-new documents
$result->duplicates; // Duplicate records found
$result->failed; // Records that failed to parse
$result->log; // ImportLog audit record
$result->total(); // Total count
$result->count(); // Imported count
$result->wasSuccessful(); // bool (no failures)// As string
$ris = $exporter->toString($documents, 'ris');
// As streaming response
return $exporter->toResponse($documents, 'bibtex', 'library.bib');
// From collection
return $exporter->fromCollection($collection, 'csl_json');use Nexus\RefManager\Support\ExporterBuilder;
// From documents collection
$ris = ExporterBuilder::documents($documents)->asRis();
// From a specific project
$bibtex = ExporterBuilder::project(7)->asBibtex();
// From a collection
$json = ExporterBuilder::collection($collection)->asCslJson();
// Download as file
return ExporterBuilder::documents($documents)->download('ris', 'library.ris');# Install dependencies
composer install
# Run all tests
composer test
# or
./vendor/bin/phpunit
# Run with testdox output
./vendor/bin/phpunit --testdox
# Run single test file
./vendor/bin/phpunit tests/Unit/Formats/RisFormatTest.php
# Run single test method
./vendor/bin/phpunit --filter=testItParsesASingleRisRecordContributions are welcome! Please see CONTRIBUTING.md for details.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
The Nexus RefManager package is open-sourced software licensed under the MIT license.