> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Databaseverbindingen uitbreiden vanuit packages

> Ontleed DB::extend en Connection::resolverFor van Laravel 13 en leer de prioriteit van verbindingsnamen en drivernamen, het vasthouden van verbindingen, opnieuw aanmaken en het testen van packages kennen.

Wanneer je vanuit een package databaseverbindingen uitbreidt, scheid je **het registreren van de aanmaakmethode** van **de keuze welke verbinding wordt gebruikt**. Ontwerp het zo dat alleen het installeren van de package niet de standaardverbinding van de applicatie of alle MySQL-verbindingen vervangt.

Deze pagina is gecontroleerd aan de hand van de officiële broncode van Laravel Framework `v13.40.0`. Zie [Databaseconfiguratie](https://kawax.biz/nl/database.md) voor de basis van verbindingsinstellingen en [Package discovery](https://kawax.biz/nl/advanced/package-discovery.md) voor het laden van providers.

## Kies een uitbreidingspunt

Het aanmaken van databaseverbindingen kent uitbreidingspunten met een verschillend bereik.

| Uitbreidingspunt | Toepassingsbereik | Argumenten van de callback |
| - | - | - |
| `DB::extend('verbindingsnaam', $resolver)` | De verbinding met de opgegeven naam | Configuratiearray, verbindingsnaam |
| `DB::extend('drivernaam', $resolver)` | Verbindingen die die driver gebruiken. Een uitbreiding op verbindingsnaam heeft echter voorrang | Configuratiearray, verbindingsnaam |
| `Connection::resolverFor('sqlite', $resolver)` | Connections van die driver die door de standaard-ConnectionFactory worden aangemaakt | PDO of een Closure die deze aanmaakt, databasenaam, tabelprefix, configuratiearray |

De retourwaarde van de callback die je aan `DB::extend()` doorgeeft, is geen PDO of Query Builder, maar een `Illuminate\Database\Connection`. `DatabaseManager::configure()` vereist deze klasse.

> [!WARNING]
>
> De `extend()` van de database volgt niet dezelfde aanroepconventie als de gemeenschappelijke `Illuminate\Support\Manager`. Het eerste argument van de callback is niet de applicatiecontainer, maar **de array met verbindingsinstellingen**. Neem voorbeelden van andere driveruitbreidingen niet zomaar over.

## Uitbreidingen op verbindingsnaam gaan voor drivernamen

`DatabaseManager::makeConnection()` haalt eerst de configuratie op en kiest daarna in de volgende volgorde de aanmaakmethode.

```mermaid theme={null}
flowchart TD
    A["Verbindingsnaam opgeven met DB::connection"] --> B{"Is er al een aangemaakte verbinding?"}
    B -->|Ja| C["Vastgehouden Connection retourneren"]
    B -->|Nee| D["Verbindingsinstellingen ophalen en URL-configuratie parsen"]
    D --> E{"Is er een uitbreiding op verbindingsnaam?"}
    E -->|Ja| F["Resolver van de verbindingsnaam uitvoeren"]
    E -->|Nee| G{"Is er een uitbreiding op driver?"}
    G -->|Ja| H["Resolver van de driver uitvoeren"]
    G -->|Nee| I["Aanmaken met standaard-ConnectionFactory"]
    F --> J["Events, herverbinden enz. instellen en vasthouden"]
    H --> J
    I --> J
```

* `DB::extend('reporting', ...)` wordt toegepast op `database.connections.reporting`.
* `DB::extend('mysql', ...)` wordt toegepast op verbindingen met `driver` `mysql` waarvoor geen uitbreiding op verbindingsnaam bestaat.
* Beide gebruiken hetzelfde uitbreidingsregister. Houd rekening met botsingen tussen verbindingsnamen en drivernamen en gebruik namen die specifiek zijn voor je package.
* `extend()` maakt geen configuratiearray aan. Als je alleen de uitbreiding registreert en er geen verbindingsinstellingen met die naam bestaan, volgt een exception.

## Kies een eigen drivernaam expliciet

Het volgende minimale voorbeeld koppelt de eigen naam `acme-sqlite` aan het aanmaken van een standaard SQLite-verbinding. **Het is geen voorbeeld van het implementeren van een nieuw databaseprotocol of SQL-dialect.** Het laat de grens zien tussen registreren en selecteren wanneer je een eigen adapter distribueert.

Ervan uitgaande dat `Acme\DatabaseBridge\` via Composer-PSR-4 aan `src/` is gekoppeld, plaats je dit in `src/DatabaseBridgeServiceProvider.php`.

```php theme={null}
<?php

namespace Acme\DatabaseBridge;

use Illuminate\Database\Connection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\ServiceProvider;

final class DatabaseBridgeServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        $app = $this->app;

        DB::extend('acme-sqlite', function (array $config, string $name) use ($app): Connection {
            $config['driver'] = 'sqlite';

            return $app->make('db.factory')->make($config, $name);
        });
    }
}
```

`db.factory` is de binding van de `ConnectionFactory` die Laravel deelt. Omdat de standaard-Factory rechtstreeks wordt aangeroepen, keer je niet terug naar de uitbreidingsselectie van de DatabaseManager en kun je het uitgestelde aanmaken van de SQLite-PDO en het aanmaken van de Connection hergebruiken.

Deze callback wordt uitgevoerd wanneer de verbinding voor het eerst wordt opgelost. De `boot()` van de provider registreert alleen de aanmaakmethode en voert geen verbindingstests of migrations uit. Laad hem als gewone, niet-uitgestelde provider, zodat hij geladen is voordat de betreffende verbinding voor het eerst wordt opgelost.

De gebruikende applicatie voegt de verbinding toe aan de bestaande `connections`-array in `config/database.php`. De standaardwaarde `default` wordt niet gewijzigd.

```php theme={null}
'acme_reports' => [
    'driver' => 'acme-sqlite',
    'database' => database_path('reports.sqlite'),
    'prefix' => '',
    'foreign_key_constraints' => true,
],
```

Bereid het SQLite-bestand vooraf voor en controleer de schrijfrechten voordat je het gebruikt. Ontwerp de package niet zo dat het bestand al wordt aangemaakt doordat de package alleen wordt geladen.

```php theme={null}
use Illuminate\Support\Facades\DB;

$connection = DB::connection('acme_reports');
$rows = $connection->select('select 1 as value');
```

Wat de gebruiker doorgeeft is de verbindingsnaam `acme_reports`, niet de drivernaam `acme-sqlite`. In het voorbeeld wordt `driver` omgezet naar `sqlite` voordat het aan de Factory wordt doorgegeven, dus ook `getDriverName()` geeft na het aanmaken `sqlite` terug.

> [!TIP]
>
> Als je binnen de resolver opnieuw `DB::connection($name)` aanroept, keer je terug naar het aanmaken van dezelfde verbinding die nog niet wordt vastgehouden. Maak de Connection met een Factory of een eigen adapter om recursie te voorkomen.

## Vervangen door een Connection-subklasse is een ander bereik

Wil je de Connection-klasse van een bestaande driver zelf vervangen, dan is er `Connection::resolverFor()`. De callback krijgt niet altijd een direct verbonden PDO, maar **soms een Closure die de PDO uitgesteld aanmaakt**.

Deze registratie wordt echter vastgehouden in een statische property van de Connection-klasse. Registreer je hem voor `sqlite`, dan heeft dat invloed op alle SQLite-verbindingen die nieuw via de standaard-Factory worden aangemaakt, inclusief het `acme-sqlite`-voorbeeld hierboven. Je kunt het niet gebruiken als vervanging voor slechts één verbindingsnaam.

* Retourneer in de callback een Connection-subklasse voor de betreffende database. Met alleen de basis-Connection blijven databasespecifieke Grammar, Processor enz. niet behouden.
* De Factory scheidt `createConnector()` en `createConnection()`. Alleen een registratie met `resolverFor()` levert nog geen PDO-connector voor een onbekende driver.
* Als je eigen resolver van `DB::extend()` de standaard-Factory niet gebruikt, wordt ook de controle op `resolverFor()` binnen de Factory niet doorlopen.
* Opnieuw registreren voor dezelfde driver overschrijft de vorige. Controleer conflicten met andere packages en het doorlekken naar tests binnen hetzelfde PHP-proces.

Packages die de impact willen beperken, overwegen eerst `DB::extend()` met een eigen verbindingsnaam of drivernaam.

## Maak onderscheid tussen reconnect en purge

De DatabaseManager houdt aangemaakte Connections per verbindingsnaam vast. Wijzigingen in de configuratie of resolver worden niet automatisch doorgevoerd in verbindingen die al zijn aangemaakt.

| Bewerking | Effect op vastgehouden Connections |
| - | - |
| `DB::extend()` | Registreert of overschrijft de volgende aanmaakprocedure. Bestaande objecten blijven ongewijzigd |
| `DB::disconnect($name)` | Verbreekt de PDO-verbinding, maar houdt de Connection vast |
| `DB::reconnect($name)` | Als deze wordt vastgehouden, worden de PDO's enz. overgenomen van een nieuw aangemaakte verbinding. Retourneert de oorspronkelijke Connection |
| `DB::purge($name)` | Verbreekt de verbinding en verwijdert deze uit wat de Manager vasthoudt. Wordt bij de volgende `connection()` opnieuw aangemaakt |
| `DB::forgetExtension($key)` | Verwijdert de registratie van de resolver. Verwijdert geen configuratie of aangemaakte verbindingen |

Vooral `reconnect()` is geen API die de klasse of configuratiearray van een vastgehouden Connection volledig vervangt. Wil je wijzigingen in de uitbreidingsklasse of verbindingsinstellingen doorvoeren, roep dan op een veilig moment zonder lopende transactie `purge()` aan en haal daarna een nieuwe verbinding op.

> [!WARNING]
>
> `purge()` vervangt Connection-referenties die door andere services of variabelen worden vastgehouden niet door de nieuwe. Bovendien zijn `::read`, `::write` en `::direct` van een verbindingsnaam aparte sleutels, dus ga er niet van uit dat het purgen van de basisnaam die ook allemaal verwijdert.
>
> Herschrijf de gedeelde verbindingsinstellingen tijdens de uitvoering niet lichtvaardig, bijvoorbeeld om van tenant te wisselen. Controleer bij langlevende workers niet alleen het vernieuwen van de configuratiecache, maar ook het herstarten van processen en de impact op vastgehouden services.

## Test het registreren en aanmaken van de package

Met [Orchestra Testbench](https://kawax.biz/nl/advanced/package-testing.md) laad je de provider en selecteer je de eigen driver daadwerkelijk. Het volgende is een voorbeeld van `tests/DatabaseBridgeTest.php`. De uitvoeringsomgeving heeft PDO en de SQLite-driver nodig.

```php theme={null}
<?php

namespace Acme\DatabaseBridge\Tests;

use Acme\DatabaseBridge\DatabaseBridgeServiceProvider;
use Illuminate\Database\SQLiteConnection;
use Orchestra\Testbench\TestCase;

final class DatabaseBridgeTest extends TestCase
{
    protected function getPackageProviders($app): array
    {
        return [DatabaseBridgeServiceProvider::class];
    }

    protected function defineEnvironment($app): void
    {
        $app['config']->set('database.default', 'testing');
        $app['config']->set('database.connections.acme_reports', [
            'driver' => 'acme-sqlite',
            'database' => ':memory:',
            'prefix' => '',
        ]);
    }

    public function test_registration_does_not_create_connections(): void
    {
        $manager = $this->app->make('db');

        $this->assertSame('testing', $manager->getDefaultConnection());
        $this->assertArrayNotHasKey('acme_reports', $manager->getConnections());
    }

    public function test_connection_is_reused_and_purge_creates_a_new_one(): void
    {
        $manager = $this->app->make('db');
        $first = $manager->connection('acme_reports');

        $this->assertInstanceOf(SQLiteConnection::class, $first);
        $this->assertSame('acme_reports', $first->getName());
        $this->assertSame('sqlite', $first->getDriverName());
        $this->assertSame(1, (int) $first->selectOne('select 1 as value')->value);
        $this->assertSame($first, $manager->connection('acme_reports'));
        $this->assertSame($first, $manager->reconnect('acme_reports'));

        $manager->purge('acme_reports');

        $second = $manager->connection('acme_reports');

        $this->assertNotSame($first, $second);
        $this->assertSame(1, (int) $second->selectOne('select 1 as value')->value);
    }
}
```

Omdat de inhoud van `:memory:` verloren gaat wanneer de verbinding wordt verbroken, verwacht deze test niet dat tabellen of data behouden blijven. Voeg in een echte package ook het volgende toe.

* Dat de resolver van de verbindingsnaam voorrang heeft op de resolver van de drivernaam.
* Dat opnieuw registreren onder dezelfde naam en `forgetExtension()` aangemaakte Connections niet vervangen.
* Exceptions bij ontbrekende verplichte instellingen en het gedrag bij een mislukte verbinding.
* De functies die je belooft te ondersteunen, zoals migrations, transacties en read/write-scheiding op ondersteunde databases.
* Dat registraties en verbindingsstatus niet door elkaar raken bij langlevende workers of in combinatie met meerdere packages.

## Controlepunten voor onderhoud

* Wordt er met een eigen naam opt-in gewerkt, zonder stilzwijgend de standaardverbinding of ingebouwde drivers te overschrijven?
* Worden er geen Closures of verbindingsobjecten in de configuratiecache gezet, en staat de aanmaaklogica in de provider?
* Worden verbindingsdoelen en inloggegevens beheerd als betrouwbare applicatieconfiguratie?
* Heb je de argumenten van `extend()`, de aanmaakvolgorde van de Factory en wat `reconnect()` overneemt opnieuw gecontroleerd voor de ondersteunde Laravel-versies?
* Informeer je gebruikers over de procedure voor opnieuw aanmaken na configuratiewijzigingen en het herstarten van workers?

## Gerelateerde pagina's

* [Laravel-packages ontwikkelen](https://kawax.biz/nl/advanced/package-development.md)
* [Levensduur van packageservices ontwerpen](https://kawax.biz/nl/advanced/package-service-lifetimes.md)
* [Packageconfiguratie samenvoegen en cachen](https://kawax.biz/nl/advanced/package-config-merging.md)
* [Migrations van packages publiceren en bijwerken](https://kawax.biz/nl/advanced/package-migrations.md)

## Geraadpleegde primaire bronnen

* [Officiële Laravel-documentatie: database en meerdere verbindingen](https://github.com/laravel/docs/blob/13.x/database.md#using-multiple-database-connections)
* [Officiële Laravel-documentatie: serviceproviders van packages](https://github.com/laravel/docs/blob/13.x/packages.md#service-providers)
* [DatabaseManager: aanmaakvolgorde, registratie van uitbreidingen, vasthouden van verbindingen en herverbinden](https://github.com/laravel/framework/blob/v13.40.0/src/Illuminate/Database/DatabaseManager.php)
* [ConnectionFactory: uitgesteld aanmaken van PDO en Connection-resolver](https://github.com/laravel/framework/blob/v13.40.0/src/Illuminate/Database/Connectors/ConnectionFactory.php)
* [Connection: resolverFor en getResolver](https://github.com/laravel/framework/blob/v13.40.0/src/Illuminate/Database/Connection.php)
* [DatabaseServiceProvider: registratie van db en db.factory](https://github.com/laravel/framework/blob/v13.40.0/src/Illuminate/Database/DatabaseServiceProvider.php)


## Related topics

- [Logchannels voor packages uitbreiden en opnieuw resolven](https://kawax.biz/nl/advanced/package-logging.md)
- [Cache](https://kawax.biz/nl/cache.md)
- [Aangepaste notificatiekanalen in een package en verificatie van de bezorging](https://kawax.biz/nl/advanced/package-notification-channels.md)
- [Hooks na het resolven van packageservices](https://kawax.biz/nl/advanced/package-service-resolution.md)
- [Logging](https://kawax.biz/nl/logging.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.