PHP code example of alwayscurious / laravel-vin

1. Go to this page and download the library: Download alwayscurious/laravel-vin library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

alwayscurious / laravel-vin example snippets


use AlwaysCurious\Vin\Facades\Vin;

// Throws VinLookupException on an invalid VIN, an API failure, or when
// live decoding is disabled by configuration.
$vehicle = Vin::lookup('7YAMYFS50TY009706');

// Optional model-year hint to improve decoding accuracy:
$vehicle = Vin::lookup('7YAMYFS50TY009706', 2026);

use AlwaysCurious\Vin\VinLookupService;

public function __construct(private readonly VinLookupService $vin) {}

// ...
$vehicle = $this->vin->lookup('7YAMYFS50TY009706');

$vehicle = Vin::tryLookup('7YAMYFS50TY009706');

if ($vehicle !== null) {
    // ...
}

Vin::isValid('7yamyfs50ty009706'); // true — input is normalized first
Vin::isValid('NOT-A-VIN');         // false

use AlwaysCurious\Vin\Rules\Vin as VinRule;

$request->validate([
    'vin' => [']);

$result = Vin::inspect('7YAMYFS50TY009706');

$result->valid;             // true  — structurally valid AND correct check digit
$result->structurallyValid; // true  — always equals Vin::isValid()
$result->checkDigitValid;   // true
$result->errors;            // []

// A structurally valid VIN with a mistyped check digit:
$bad = Vin::inspect('7YAMYFS51TY009706');
$bad->fails();              // true
$bad->messages();           // ['The VIN check digit (9th character) does not match; the VIN may be mistyped.']

// Each failure mode is distinguishable:
Vin::inspect('IYAMYFS50TY009706')->errors; // [VinValidationError::IllegalCharacters]  (I/O/Q rejected)
Vin::inspect('7YAMYFS50TY00970')->errors;  // [VinValidationError::WrongLength]         (not 17 chars)

$vehicles = Vin::lookupMany(['7YAMYFS50TY009706', '1HGCM82633A004352']);

$vehicles['7YAMYFS50TY009706']->make; // 'HYUNDAI'

use AlwaysCurious\Vin\VinFailureReason;
use AlwaysCurious\Vin\VinLookupException;

try {
    $vehicle = Vin::lookup($request->input('vin'));
} catch (VinLookupException $e) {
    return match ($e->reason) {
        VinFailureReason::InvalidVin        => back()->withErrors(['vin' => 'That isn’t a valid VIN.']),
        VinFailureReason::Disabled          => response('VIN decoding is temporarily disabled.', 503),
        default                             => $e->reason->isTransient()
            ? response('The VIN service is unavailable, try again shortly.', 503)
            : throw $e,
    };
}

use AlwaysCurious\Vin\Events\VinDecoded;
use Illuminate\Support\Facades\Event;

Event::listen(function (VinDecoded $event) {
    Telemetry::record('vin.decoded', [
        'vin' => $event->vehicle->vin,
        'driver' => $event->driver,
        'cached' => $event->fromCache,
    ]);
});

$vehicle->vin;           // '7YAMYFS50TY009706'
$vehicle->year;          // 2026 (int|null)
$vehicle->make;          // 'HYUNDAI'
$vehicle->model;         // 'Ioniq 9'
$vehicle->trim;          // 'Calligraphy'
$vehicle->bodyClass;     // 'Sport Utility Vehicle (SUV)/Multi-Purpose Vehicle (MPV)'
$vehicle->vehicleType;   // 'MULTIPURPOSE PASSENGER VEHICLE (MPV)'
$vehicle->manufacturer;  // 'HYUNDAI MOTOR GROUP METAPLANT AMERICA'
$vehicle->errorCode;     // 0 (int|null) — primary NHTSA decode status
$vehicle->errorText;     // string|null

$vehicle->series;        // string|null — hydrated from the 'typed' level up (see below)

$vehicle->decodedSuccessfully(); // true when NHTSA reports a clean decode (error code 0)
$vehicle->isFullyIdentified();   // true when year + make + model are all present

$vehicle->toArray();  // snake_cased array (identity + nested groups; see below)
json_encode($vehicle); // JsonSerializable — same shape as toArray()

$vehicle->only(['make', 'model', 'year', 'trim']);
// ['make' => 'HYUNDAI', 'model' => 'Ioniq 9', 'year' => 2026, 'trim' => 'Calligraphy']

$vehicle->toColumns(['year' => 'model_year', 'make' => 'make', 'bodyClass' => 'body_class']);
// ['model_year' => 2026, 'make' => 'HYUNDAI', 'body_class' => 'Sport Utility Vehicle (SUV)/...']

$car->fill($vehicle->toColumns([...]));

$vehicle->engine->fuelTypePrimary;      // 'Electric'
$vehicle->engine->horsepower;           // int|null   e.g. 422
$vehicle->engine->displacementL;        // float|null e.g. 5.0
$vehicle->engine->driveType;            // 'AWD'
$vehicle->engine->transmissionStyle;    // 'Automatic'
$vehicle->engine->electrificationLevel; // 'BEV (Battery Electric Vehicle)'

$vehicle->body->doors;                  // int|null   e.g. 4
$vehicle->body->seats;                  // int|null
$vehicle->body->gvwr;                   // 'Class 2E: 6,001 - 7,000 lb ...'

$vehicle->safety->airbagCurtain;        // 'All Rows'
$vehicle->safety->rearVisibilitySystem; // 'Standard' — NHTSA's backup-camera field
$vehicle->safety->electronicStabilityControl; // 'Standard'

$vehicle->plant->city;                  // 'ELLABELL'
$vehicle->plant->country;               // 'UNITED STATES (USA)'

$vehicle->attribute('DestinationMarket');       // 'North America'
$vehicle->attribute('NoSuchField');             // null
$vehicle->attribute('NoSuchField', 'unknown');  // 'unknown' — optional default

$vehicle->attributes; // ['Make' => 'HYUNDAI', 'EngineHP' => '422', ...] full non-empty row

namespace App\Vin;

use AlwaysCurious\Vin\Contracts\VinDecoder;
use AlwaysCurious\Vin\VehicleData;
use AlwaysCurious\Vin\VinLookupException;
use Illuminate\Support\Facades\Http;

class AcmeVinDecoder implements VinDecoder
{
    public function __construct(private readonly string $apiKey) {}

    public function decode(string $vin, ?int $modelYear = null): VehicleData
    {
        $response = Http::withToken($this->apiKey)
            ->acceptJson()
            ->get("https://vin.acme.test/decode/{$vin}");

        if ($response->failed()) {
            throw VinLookupException::requestFailed($vin, $response->status());
        }

        // Map the provider's shape onto VehicleData however it returns data.
        return new VehicleData(
            vin: $vin,
            year: $response->json('year'),
            make: $response->json('make'),
            model: $response->json('model'),
            series: $response->json('series'),
            trim: $response->json('trim'),
            bodyClass: $response->json('body_class'),
            errorCode: 0,
            errorText: null,
        );
    }
}

use AlwaysCurious\Vin\Facades\Vin;
use App\Vin\AcmeVinDecoder;

Vin::extend('acme', fn ($app) => new AcmeVinDecoder($app['config']['services.acme.key']));

$vehicle = Vin::using('acme')->lookup('7YAMYFS50TY009706');

use AlwaysCurious\Vin\Facades\Vin;
use AlwaysCurious\Vin\VehicleData;

$fake = Vin::fake([
    '1FTFW1E50NKF12345' => VehicleData::fake(make: 'Ford', model: 'F-150'),
]);

$vehicle = Vin::lookup('1FTFW1E50NKF12345'); // 'Ford' — no HTTP call

$fake->assertLookedUp('1FTFW1E50NKF12345');
$fake->assertLookedUpCount(1);

use AlwaysCurious\Vin\Facades\Vin;
use Illuminate\Support\Facades\Http;

Http::fake([
    'vpic.nhtsa.dot.gov/*' => Http::response([
        'Results' => [[
            'Make' => 'HYUNDAI',
            'Model' => 'Ioniq 9',
            'ModelYear' => '2026',
            'ErrorCode' => '0',
        ]],
    ]),
]);

$vehicle = Vin::lookup('7YAMYFS50TY009706');
bash
php artisan vendor:publish --tag=vin-config