承接 dij-digital/kvk-laravel 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

dij-digital/kvk-laravel

Composer 安装命令:

composer require dij-digital/kvk-laravel

包简介

KVK API package for Laravel

README 文档

README

A Laravel package for the Dutch KVK (Kamer van Koophandel) Handelsregister API. Provides a clean, typed, and fakable interface for searching the company registry.

Requirements

  • PHP ^8.4|^8.5
  • Laravel ^12

Installation

composer require dij-digital/kvk-laravel

The service provider and facade are auto-discovered.

Publish the config file:

php artisan vendor:publish --tag=kvk

Configuration

Add your API key to .env:

KVK_API_KEY=your-api-key
KVK_BASE_URL=https://api.kvk.nl

For testing against the KVK sandbox, use:

KVK_API_KEY=l7xx1f2691f2520d487b902f4e0b57a0b197
KVK_BASE_URL=https://api.kvk.nl/test

Usage

Search

Search the KVK registry using the fluent API:

use DIJ\Kvk\Facades\KVK;

$result = KVK::search()
    ->kvkNumber('69599068')
    ->city('Amsterdam')
    ->includeInactiveRegistrations()
    ->get();

foreach ($result->items as $item) {
    echo $item->kvkNumber;  // '69599068'
    echo $item->name;       // 'Test BV Donald'
    echo $item->type;       // 'hoofdvestiging'
    echo $item->active;     // 'Ja'
}

Or pass a SearchParameters DTO directly:

use DIJ\Kvk\Data\SearchParameters;
use DIJ\Kvk\Facades\KVK;

$params = new SearchParameters(
    kvkNumber: '69599068',
    city: 'Amsterdam',
    includeInactiveRegistrations: true,
);
$result = KVK::search()->search($params);

Both approaches produce identical API calls.

Available search parameters

Method Type Description
kvkNumber(string) string 8-digit KVK number
rsin(string) string 9-digit RSIN number
branchNumber(string) string 12-digit branch number
name(string) string Trade name or statutory name
streetName(string) string Street name
city(string) string City name
postalCode(string) string Postal code (with houseNumber or poBoxNumber)
houseNumber(int) int House number (with postalCode)
houseLetter(string) string House letter (with houseNumber)
poBoxNumber(int) int PO box number (with postalCode)
type(array) array Filter: hoofdvestiging, nevenvestiging, rechtspersoon
includeInactiveRegistrations(bool) bool Include dissolved companies (default: false)
page(int) int Page number (default: 1)
resultsPerPage(int) int Results per page (default: 100, max: 100)

Base Profile

Retrieve detailed company information by KVK number using the fluent API:

use DIJ\Kvk\Facades\KVK;

// Get main company profile
$profile = KVK::baseProfile('69599068')->get();
echo $profile->kvkNumber;    // '69599068'
echo $profile->name;         // 'Test Stichting Bolderbast'
echo $profile->statutoryName; // 'Stichting Bolderbast'

// Get owner information
$owner = KVK::baseProfile('69599068')->owner();
echo $owner->legalForm;      // 'BesloteVennootschap'
foreach ($owner->addresses as $address) {
    echo $address->city;     // 'Woerden'
}

// Get main branch details
$mainBranch = KVK::baseProfile('69599068')->mainBranch();
echo $mainBranch->branchNumber;    // '000037178598'
echo $mainBranch->totalEmployees;  // 15

// Get all branches listing
$branches = KVK::baseProfile('69599068')->branches();
echo $branches->totalBranchCount;  // 1
foreach ($branches->branches as $branch) {
    echo $branch->firstTradeName;  // 'Test BV Donald'
}

// Include GPS coordinates in addresses (geoData)
$owner = KVK::baseProfile('69599068')->geoData()->owner();
foreach ($owner->addresses as $address) {
    echo $address->geoData?->gpsLatitude;  // 52.08151653230184
}

Available base profile options

Method Description
get() Main company profile — name, registration dates, trade names, SBI activities
owner() Owner information — legal form, addresses, websites
mainBranch() Main branch details — employees, addresses, trade names, SBI activities
branches() All branches listing — counts and summary per branch
geoData(bool) Include GPS coordinates in address responses (default: false)

Branch Profile

Retrieve detailed branch information by branch number (vestigingsnummer):

use DIJ\Kvk\Facades\KVK;

$branch = KVK::branchProfile('000037178598')->get();
echo $branch->branchNumber;   // '000037178598'
echo $branch->kvkNumber;      // '68750110'
echo $branch->firstTradeName; // 'Test BV Donald'

// Include GPS coordinates in addresses
$branch = KVK::branchProfile('000037178598')->geoData()->get();
foreach ($branch->addresses as $address) {
    echo $address->geoData?->gpsLatitude;
}

Available branch profile options

Method Description
get() Branch profile — trade names, employees, addresses, websites, and SBI activities
geoData(bool) Include GPS coordinates in address responses (default: false)

Naming (Trade Names)

Retrieve trade names by KVK number:

use DIJ\Kvk\Facades\KVK;

$naming = KVK::naming('69599068')->get();
echo $naming->kvkNumber;     // '69599068'
echo $naming->statutoryName; // 'Stichting Bolderbast'
echo $naming->name;          // 'Test Stichting Bolderbast'

foreach ($naming->branches as $branch) {
    echo $branch->branchNumber;     // '000037178598'
    echo $branch->firstTradeName;   // 'Test Stichting Bolderbast' (commercial)
    echo $branch->name;             // 'Stichting Branch' (non-commercial)
    echo $branch->alsoKnownAs;      // 'Branch Alias'
}

Available naming options

Method Description
get() Trade names profile — statutory name, primary name, aliases, and branch-level names

Subscriptions (Mutatieservice)

Monitor changes to KVK registry entries via the Mutatieservice (change notifications):

use DIJ\Kvk\Facades\KVK;

// List all subscriptions
$subscriptions = KVK::subscriptions()->get();
echo $subscriptions->customerId;  // 'customer-123'
foreach ($subscriptions->subscriptions as $sub) {
    echo $sub->id;         // 'subscription-456'
    echo $sub->startDate;  // '2024-01-01T00:00:00Z'
    echo $sub->active;     // true
}

// Get signals (change notifications) for a subscription
$signals = KVK::subscriptions()
    ->subscription('subscription-456')
    ->from('2024-01-01T00:00:00Z')
    ->to('2024-12-31T23:59:59Z')
    ->page(1)
    ->resultsPerPage(50)
    ->signals();

foreach ($signals->signals as $signal) {
    echo $signal->kvkNumber;   // '69792917'
    echo $signal->signalType;  // 'SignaalGewijzigdeInschrijving'
    echo $signal->timestamp;   // '2024-05-14T15:25:13.773Z'
}

// Get a specific signal's full details
$signal = KVK::subscriptions()
    ->subscription('subscription-456')
    ->signal('signal-001');

echo $signal->messageId;              // '3e96fad5-...'
echo $signal->signalType;             // 'SignaalGewijzigdeInschrijving'
echo $signal->registrationTimestamp;  // '2024-05-14T15:25:13.773Z'
echo $signal->relatesTo['kvkNummer']; // '69792917'

Available subscription options

Method Description
get() List all subscriptions for your API key
subscription(string) Scope to a specific subscription (returns a scoped builder)

Available signal options (on scoped subscription)

Method Description
from(string) Filter signals from this ISO 8601 datetime
to(string) Filter signals until this ISO 8601 datetime
page(int) Page number (default: 1)
resultsPerPage(int) Results per page (min: 10, max: 500, default: 100)
signals() List signals for this subscription (paginated)
signal(string) Get a specific signal's full details

Error Handling

The package throws typed exceptions for API failures. All exceptions extend KvkException and expose statusCode and responseBody properties.

Exception When
KvkAuthenticationException HTTP 401 or 403 — invalid or missing API key
KvkServerException HTTP 500+ — KVK API server error
KvkRequestException Any other non-successful HTTP response
use DIJ\Kvk\Exceptions\KvkAuthenticationException;
use DIJ\Kvk\Exceptions\KvkException;

try {
    $result = KVK::search()->kvkNumber('69599068')->get();
} catch (KvkAuthenticationException $e) {
    // Invalid API key — check KVK_API_KEY in .env
    $e->statusCode;    // 401
    $e->responseBody;  // raw response body
} catch (KvkException $e) {
    // Any other API error
    $e->statusCode;
    $e->responseBody;
}

Testing

The package is designed to be easily fakeable in your application tests.

Basic Usage

Use KVK::fake() to replace all KVK API calls with a fake that returns no results:

use DIJ\Kvk\Facades\KVK;

KVK::fake();

$result = KVK::search()->kvkNumber('69599068')->get();
// Returns a SearchResult with 0 items — no HTTP calls made

Faking Specific Responses

Pass response DTOs to KVK::fake() using named parameters to control what each endpoint returns:

use DIJ\Kvk\Data\Responses\BaseProfileResponse;
use DIJ\Kvk\Data\Responses\SearchResponse;
use DIJ\Kvk\Data\ValueObjects\SbiActivity;
use DIJ\Kvk\Facades\KVK;

// Search faking — use withSearchResponses() on the returned FakeKVK
KVK::fake()->withSearchResponses(
    SearchResponse::fake(kvkNumber: '69599068', name: 'Acme BV'),
    SearchResponse::fake(kvkNumber: '12345678', name: 'Other BV'),
);

$result = KVK::search()->get();
// $result->total === 2
// $result->items->first()->kvkNumber === '69599068'

// Customize nested data — e.g., test a specific SBI code
KVK::fake(
    baseProfile: BaseProfileResponse::fake(
        sbiActivities: [SbiActivity::fake(sbiCode: '86101')],
    ),
);

$profile = KVK::baseProfile('69599068')->get();
echo $profile->sbiActivities[0]->sbiCode; // '86101'

Available fake() parameters

Parameter Type Description
$baseProfile ?BaseProfileResponse Custom base profile response
$baseProfileOwner ?BaseProfileOwnerResponse Custom owner response
$baseProfileMainBranch ?BaseProfileMainBranchResponse Custom main branch response
$baseProfileBranches ?BaseProfileBranchesResult Custom branches result
$branchProfile ?BranchProfileResponse Custom branch profile response
$naming ?NamingResponse Custom naming response
$subscriptions ?SubscriptionsResult Custom subscriptions result
$signals ?SignalsResult Custom signals result
$signal ?SignalResponse Custom signal response
...$searchResponses SearchResponse Search responses — pass via withSearchResponses() on the returned FakeKVK

Fluent Builder Interface

You can also update a fake after it's been created using the fluent with* methods:

KVK::fake()
    ->withBaseProfile(BaseProfileResponse::fake(name: 'Updated Name'))
    ->withSearchResponses(SearchResponse::fake(kvkNumber: '11223344'));

DTO Fake Defaults

Every response DTO provides a fake() method with sensible defaults from the KVK test environment. Only specify the fields you need to override:

$response = SearchResponse::fake(
    kvkNumber: '69599068',
    name: 'Test BV Donald',
    type: 'hoofdvestiging',
);
Parameter Default
kvkNumber '69599068'
name 'Test BV Donald'
type 'hoofdvestiging'
active 'Ja'
branchNumber '000037178598'
rsin null
address null

Facade Cleanup

If you use KVK::fake() in tests that extend Laravel's TestCase, cleanup is automatic. For plain PHPUnit tests, add this to your test class:

protected function tearDown(): void
{
    \Illuminate\Support\Facades\Facade::clearResolvedInstances();
    parent::tearDown();
}

Advanced: HTTP-Level Faking

For lower-level tests that need to verify the full HTTP pipeline (including request parameters and response parsing), you can still use Http::fake() directly:

use Illuminate\Support\Facades\Http;

Http::fake([
    'api.kvk.nl/*' => Http::response([
        'pagina' => 1,
        'resultatenPerPagina' => 10,
        'totaal' => 1,
        'resultaten' => [
            [
                'kvkNummer' => '69599068',
                'naam' => 'Test BV',
                'type' => 'hoofdvestiging',
                'actief' => 'Ja',
            ],
        ],
    ]),
]);

$result = KVK::search()->kvkNumber('69599068')->get();

License

MIT

dij-digital/kvk-laravel 适用场景与选型建议

dij-digital/kvk-laravel 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 349 次下载、GitHub Stars 达 2, 最近一次更新时间为 2026 年 03 月 03 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 dij-digital/kvk-laravel 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 dij-digital/kvk-laravel 我们能提供哪些服务?
定制开发 / 二次开发

基于 dij-digital/kvk-laravel 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 349
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 2
  • 点击次数: 24
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 2
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-03-03