omniscient / omnischolar
Omnischolar: one contract for a researcher's publications - author profiles, works, books and their editions, citations - read from OpenAlex, HAL, Crossref, ORCID, Open Library, arXiv and INSPIRE, merged and deduplicated, exported as BibTeX, RIS or CSL-JSON; and its Symfony bundle.
Requires
- php: >=8.2
- symfony/http-client-contracts: ^3.0
Requires (Dev)
- phpunit/phpunit: ^11.0
- symfony/config: ^6.4|^7.0|^8.0
- symfony/dependency-injection: ^6.4|^7.0|^8.0
- symfony/http-client: ^6.4|^7.0|^8.0
- symfony/http-kernel: ^6.4|^7.0|^8.0
Suggests
- ext-intl: Better title matching across accents in the Merger
- omnischolar/arxiv: arXiv: preprints
- omnischolar/crossref: Crossref: reference metadata by DOI
- omnischolar/hal: HAL: French open archive, filtered by domain (shs.droit)
- omnischolar/inspire: INSPIRE-HEP: high-energy physics literature and citations
- omnischolar/openalex: OpenAlex: profiles, works, citations, h-index
- omnischolar/openlibrary: Open Library: books, editions, covers
- omnischolar/orcid: ORCID: identity, positions and degrees, declared works
- symfony/config: In a Symfony application: the configuration of Omnischolar\Bridge\Symfony\OmnischolarBundle
- symfony/dependency-injection: In a Symfony application: the services of Omnischolar\Bridge\Symfony\OmnischolarBundle
- symfony/http-kernel: In a Symfony application: Omnischolar\Bridge\Symfony\OmnischolarBundle itself
Provides
None
Conflicts
None
Replaces
- glitchr/omnischolar: 1.x-dev
This package is auto-updated.
Last update: 2026-10-17 13:54:57 UTC
README
One contract for a researcher's publications: their profile, their works, their books and the editions of each, their citations - read from the services that know them, merged into one list, exported as BibTeX, RIS or CSL-JSON.
Published as omniscient/omnischolar (formerly glitchr/omnischolar, which this package replaces: a
composer.json that still requires the old name keeps resolving to this package, never both).
omniscient/ is the vendor of every family's core; the providers keep theirs (omnischolar/crossref...).
$works = $collector->collect([ 'openalex' => 'A5108007452', // Keitaro Nakatani on OpenAlex 'hal' => 'Keitaro Nakatani', // his deposits in HAL, by the name he signs 'crossref' => '0009-0005-1387-7295', // the works deposited with his ORCID ]); $works[0]->title; // one record per work, each field from the source trusted for it $works[0]->pdfUrl; // the full text deposited in HAL $export->bibtex($works); // @article{chocron2024acid, ...} $books = (new Merger())->merge($openlibrary->works('Monica Neagoy')); $books[0]->editions; // the editions of one book, newest first
This package holds the contract (Source\SourceInterface, Source\SourceFactory, Registry),
the models (Work, Author, Contributor, Identifier, Venue, Metrics, Affiliation), the
Merger, the Collector, the Export and a bridge for Symfony. It needs no framework: it
requires nothing but symfony/http-client-contracts, each source package symfony/http-client.
Each source is a package of its own:
| Package | Source | Key |
|---|---|---|
omnischolar/openalex |
OpenAlex: profiles and counts (h-index), works, citations, abstracts | none (mailto; a free key raises the daily budget) |
omnischolar/hal |
HAL: French open archive, full texts, filter by domain (shs.droit) |
none |
omnischolar/crossref |
Crossref: reference metadata by DOI, works by ORCID | none (mailto) |
omnischolar/orcid |
ORCID: identity, CV (positions, degrees, distinctions), declared works | none (public API) |
omnischolar/openlibrary |
Open Library: books, one record per edition, covers | none |
omnischolar/arxiv |
arXiv: preprints | none |
omnischolar/inspire |
INSPIRE-HEP: physics literature, citation summary | none |
A source answers what it can - capabilities() says what - and throws NotSupportedException
for the rest. Unknown is null or an empty page; a service down or rate limited is an
UnavailableException (RateLimitedException), which a caller never caches as "nothing".
The Merger takes one record per work: same DOI, then same ISBN (books), arXiv id, HAL id,
then same title in the same year - a different DOI on both sides always keeps two records apart.
Each field comes from the source preferred for it (configurable), identifiers are united, and
the editions of a book are grouped under the newest one.
Documentation
- Installation and first calls
- Sources: what each can and cannot do
- Models and identifiers
- Merging: the rules and the preferences
- Export: BibTeX, RIS, CSL-JSON
- Symfony
- The Docker harness
Plain PHP
composer require omniscient/omnischolar omnischolar/openalex omnischolar/hal
use Omnischolar\Collector; use Omnischolar\Hal\HalSourceFactory; use Omnischolar\OpenAlex\OpenAlexSourceFactory; use Omnischolar\Registry; use Symfony\Component\HttpClient\HttpClient; $http = HttpClient::create(); // or the application's client; a MockHttpClient in a test $registry = new Registry([new OpenAlexSourceFactory($http), new HalSourceFactory($http)], [ 'openalex' => ['factory' => 'openalex', 'options' => ['mailto' => 'you@example.org']], 'hal' => ['factory' => 'hal'], ]); $openalex = $registry->get('openalex'); $works = (new Collector($registry))->collect(['openalex' => 'A5108007452', 'hal' => 'Keitaro Nakatani']);
No bundle, no container: a factory per source package, the registry built by hand. docs/installation.md opens on a whole script that runs as it is, against the real services.
Symfony
Omnischolar\Bridge\Symfony\OmnischolarBundle does that wiring in a Symfony application
(docs/symfony.md); its components (symfony/config,
symfony/dependency-injection, symfony/http-kernel) are not required by this package.
omnischolar: sources: openalex: { factory: openalex, options: { mailto: '%env(OMNISCHOLAR_MAILTO)%' } } hal: { factory: hal } droit: { factory: hal, options: { domains: [shs.droit] } } openlibrary: { factory: openlibrary, options: { mailto: '%env(OMNISCHOLAR_MAILTO)%' } } merger: preferences: { abstract: [hal, openalex] }
public function __construct(SourceInterface $openalex, Collector $collector, Export $export) {}
Docker: every source, for real
cd docker && cp .env.dist .env docker compose run --rm omnischolar sources docker compose run --rm omnischolar works openalex A5108007452 --from 2024 --to 2024 docker compose run --rm omnischolar merge openlibrary:"Monica Neagoy" crossref:"Monica Neagoy" docker compose run --rm omnischolar bare # plain PHP: no bundle, no container, and what PHP loaded docker compose run --rm omnischolar test
Responsibility
omniscient/omnischolar and its omnischolar/* providers are independent, unofficial clients: none is
affiliated with, endorsed by or sponsored by the services it reaches. Each service keeps its own
terms (licence of their data, attribution or citation, keys, rate limits), named with a link in the
"Responsibility" section of the README of each provider that reaches one. The MIT licence covers
this code only and grants no right to any service or to its data.
Whoever installs and runs these packages is responsible for complying with those terms, for obtaining whatever they require, and for any use made of what they return. The authors publish them free of charge, make no commercial use of them, and accept no liability for how they are used (see LICENSE).
License: MIT since 2026-10-09; earlier versions remain published under LGPL-3.0-or-later.