laravel-lobbyist maintained by wiserwebsolutions
Laravel Lobbyist
Search, monitor, and summarize legislative activity — bills, votes, and elected representatives — across the United States, through a single driver-agnostic API.
This is the core package. It ships the contract, the driver manager, and the normalized data objects, but no data source of its own. You install one or more driver packages that plug in behind it:
| Package | Role |
|---|---|
wiserwebsolutions/laravel-lobbyist-legiscan |
Default nationwide driver (LegiScan API) |
wiserwebsolutions/laravel-lobbyist-palegis |
Pennsylvania driver (palegis.us RSS feeds) |
Installation
composer require wiserwebsolutions/laravel-lobbyist
# plus at least one driver — the default nationwide driver:
composer require wiserwebsolutions/laravel-lobbyist-legiscan
Publish the config if you want to change the default driver:
php artisan vendor:publish --tag=lobbyist-config
Usage
Lobbyist::state($abbr) resolves the driver registered for that state, falling
back to the default driver (legiscan) when no state-specific driver is
installed. The returned object is scoped to that state.
use WiserWebSolutions\Lobbyist\Facades\Lobbyist;
// Uses the LegiScan default driver (nationwide coverage).
$ca = Lobbyist::state('CA');
$bills = $ca->bills(); // BillCollection
$bill = $ca->bill('AB1'); // Bill (lookup by number)
// Uses the PA driver if laravel-palegis is installed, else the LegiScan default.
$pa = Lobbyist::state('PA');
$votes = $pa->votes(); // VoteCollection
$people = $pa->representatives(); // LegislatorCollection
Which operations a driver supports varies by source — check first (see below).
Capabilities
Not every data source supports every operation — an RSS feed can list current bills but cannot look up an arbitrary bill by id. Drivers therefore implement only the capabilities they can back, and you can check before calling:
use WiserWebSolutions\Lobbyist\Contracts\Capability;
use WiserWebSolutions\Lobbyist\Contracts\Providers\BillLookup;
$driver = Lobbyist::state('CA'); // LegiScan
if ($driver->supports(Capability::GetBill)) {
$bill = $driver->bill(1132030); // Bill
}
// or type-check the segregated interface directly:
if ($driver instanceof BillLookup) {
$bill = $driver->bill('AB1');
}
Calling an unsupported lookup throws UnsupportedOperationException.
| Capability | Method | Interface | LegiScan | PA (RSS) |
|---|---|---|---|---|
ListSessions |
sessions() |
SessionProvider |
✅ | ✅ |
ListBills |
bills() |
BillProvider |
✅ | ✅ |
GetBill |
bill($id) |
BillLookup |
✅ | ✅ |
ListVotes |
votes() |
VoteProvider |
— | ✅ |
GetVote |
vote($id) |
VoteLookup |
✅ | — |
ListRepresentatives |
representatives() |
RepresentativeProvider |
✅ | ✅ |
GetRepresentative |
representative($id) |
RepresentativeLookup |
✅ | — |
Data objects
Drivers return normalized spatie/laravel-data
objects — Session, Bill, Vote, Legislator — regardless of source. States
are typed via the StateEnum, chambers via Chamber, parties via Party.
These objects are provider-agnostic: each derives its typed properties from a
documented, normalized meta array (see the class docblocks for the recognized
keys) and is unaware of any specific data source. It is a driver's job to map its
raw payload into that shape — so adding a new provider never requires touching
core. Drivers typically keep the raw payload under meta['raw'] so nothing is lost.
Writing a state driver
-
Create a package that requires
wiserwebsolutions/laravel-lobbyist. -
Write a driver extending
WiserWebSolutions\Lobbyist\Support\AbstractDriverand implementing the provider/lookup interfaces you can actually back.AbstractDriverderivescapabilities()/supports()from those interfaces automatically and throwsUnsupportedOperationExceptionfor lookups you omit. -
Map your source's raw payloads into the core DTOs' normalized
metashape — keep this in a mapper class in your package (seeLegiscanMapper/PalegisMapperfor reference). Core never learns about your source. -
Register it from your service provider's
boot(), order-independently:$this->app->resolving('lobbyist', function ($manager) { $manager->extend('pa', fn () => new PaDriver(/* ... */)); }); -
Verify compliance with the shipped
WiserWebSolutions\Lobbyist\Testing\AssertsDriverContracttrait.
Testing
composer install
vendor/bin/phpunit
License
MIT © Daniel Wiser