Skip to content

nexus-scholar/refmanager

Repository files navigation

Nexus RefManager

Tests PHP Version Laravel Version License Total Downloads

A Laravel package for managing bibliographic references with full import/export support for Zotero, EndNote, and Mendeley.


Table of Contents


Features

  • 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

Status

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

Requirements

  • PHP 8.2+
  • Laravel 11.x / 12.x / 13.x
  • SQLite (for testing)

Installation

Via Composer

composer require nexus/refmanager

Publish Configuration

php artisan vendor:publish --tag=refmanager-config

Run Migrations

php artisan migrate

Add the Trait to Your Document Model

use Nexus\RefManager\Concerns\HasBibliographicExport;

class Document extends Model
{
    use HasBibliographicExport;
}

Quick Start

Import References

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');

Export References

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');

Artisan Commands

# 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

Supported 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

API Reference

ReferenceImporter

// 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');

Optional: Project-Scoped Deduplication

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_scope is null, deduplication remains global.

ImportResult

$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)

ReferenceExporter

// 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');

Expressive Facade Helpers (Experimental)

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');

Testing

# 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=testItParsesASingleRisRecord

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for details.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

The Nexus RefManager package is open-sourced software licensed under the MIT license.

About

Reference manager with Zotero, EndNote, and Mendeley import/export for Laravel

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors