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

# Enregistrer des drivers Storage dans un package et les résoudre à nouveau

> En analysant le FilesystemManager de Laravel 13, découvrez l'enregistrement via Storage::extend(), la conservation des instances de disque, la nouvelle résolution après un changement de configuration et une vérification qui ne dépend pas de fake.

Pour fournir une fonctionnalité de stockage depuis un package, séparez **l'enregistrement de la façon de créer le driver** de **la création des disques de l'utilisateur**. Si le simple démarrage du provider ne lance ni connexion externe ni opération sur des fichiers, vous risquez moins de casser le démarrage des environnements qui n'utilisent pas cette fonctionnalité.

Cette page s'appuie sur l'implémentation du Laravel Framework `v13.37.0`. Pour les opérations de base, consultez [Stockage de fichiers](/fr/filesystem) ; pour le chargement des providers, consultez [Découverte automatique des packages](/fr/advanced/package-discovery).

## Distinguer le nom du driver et le nom du disque

Le premier argument de `Storage::extend()` est le **nom du driver**. L'argument de `Storage::disk()`, en revanche, est le **nom du disque** défini dans `filesystems.disks`. Vous pouvez définir plusieurs disques qui utilisent le même driver.

| Élément | Exemple de cette page | Rôle |
| - | - | - |
| Nom du driver | `acme-archive-local` | Identifiant du callback qui crée le disque |
| Nom du disque | `reports`, `exports` | Identifiant de la configuration et de l'instance déjà créée |
| Configuration du disque | `root`, `throw`, etc. | Valeurs transmises au callback lors de la création de ce disque |

`FilesystemManager::resolve()` cherche un traitement de création personnalisé correspondant au `driver` de la configuration et, s'il en trouve un, l'appelle avant les drivers intégrés. Utiliser `local` ou `s3` comme nom d'extension remplace le traitement de création existant : choisissez donc un nom propre au package.

## N'enregistrer que la façon de créer dans le provider

Voici un exemple minimal qui réutilise le traitement de création du driver local standard de Laravel afin de comprendre le chemin d'enregistrement. Si votre seul objectif est le stockage local, le driver `local` habituel suffit. Pour fournir un backend propre, remplacez ce traitement par la construction d'un adaptateur Flysystem enveloppé dans le `FilesystemAdapter` de Laravel, comme dans l'exemple de la documentation officielle.

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

namespace Acme\Archive;

use Illuminate\Contracts\Foundation\Application;
use Illuminate\Filesystem\FilesystemAdapter;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\ServiceProvider;
use InvalidArgumentException;

class ArchiveServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Storage::extend('acme-archive-local', static function (
            Application $app,
            array $config,
        ): FilesystemAdapter {
            if (! is_string($config['root'] ?? null) || $config['root'] === '') {
                throw new InvalidArgumentException('Archive disk requires a root.');
            }

            return $app['filesystem']->createLocalDriver($config);
        });
    }
}
```

Ce provider est [enregistré dans le package de la manière habituelle](/fr/advanced/package-discovery). Pour qu'il soit disponible en HTTP, dans Artisan et dans les workers de file d'attente, ne limitez pas l'enregistrement avec `runningInConsole()`. De plus, ne faites pas d'un provider chargé uniquement d'enregistrer l'extension un [provider différé](/fr/advanced/deferred-provider).

Le callback reçoit l'application et **l'intégralité de la configuration du disque à résoudre**. Effectuez la validation de la configuration et la création des clients à l'intérieur du callback, et n'effectuez aucune opération sur des fichiers dans `boot()`. Dans l'exemple, `createLocalDriver()` peut créer un répertoire au moment de la création : il est donc important de séparer le moment de l'enregistrement de celui de la création.

<Tip>
  `FilesystemManager::extend()` lie le `$this` d'une closure ordinaire au Manager. Ne partez pas du principe que vous pouvez utiliser le `$this` du provider ; en utilisant une closure `static` et l'argument `$app` comme dans cet exemple, les dépendances deviennent explicites.
</Tip>

L'utilisateur ajoute la configuration dans le tableau `disks` de `config/filesystems.php`.

```php theme={null}
'reports' => [
    'driver' => 'acme-archive-local',
    'root' => storage_path('app/private/reports'),
    'throw' => true,
],
'exports' => [
    'driver' => 'acme-archive-local',
    'root' => storage_path('app/private/exports'),
    'throw' => true,
],
```

Côté utilisation, on indique le nom du disque et non le nom du driver.

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

Storage::disk('reports')->put('summary.txt', 'Monthly summary');
```

<Info>
  Cet exemple ne montre que le chemin de création pour le stockage local. La distribution de fichiers via `serve` et la fourniture d'URL temporaires ne sont pas couvertes. Si un adaptateur propre prend en charge la génération d'URL, la visibilité, la lecture seule, etc., vérifiez chaque implémentation et les packages de dépendance nécessaires, et ne supposez pas qu'il suffit de transmettre une clé de configuration pour les activer.
</Info>

## Les disques nommés sont conservés après leur création

`disk('reports')` n'appelle pas le callback à chaque fois. La méthode `get()` du Manager privilégie l'instance déjà créée présente dans le tableau interne `$disks`. Ce n'est que si le disque n'a pas encore été créé que l'appel passe par `resolve()`, et le résultat est conservé avec le nom du disque comme clé.

```mermaid theme={null}
flowchart TD
    A["boot() du provider"] --> B["Enregistrer le traitement de création avec extend()"]
    B --> C["Storage::disk('reports')"]
    C --> D{"reports déjà créé ?"}
    D -->|Oui| E["Renvoyer l'instance conservée"]
    D -->|Non| F["Lire driver et transmettre la configuration au traitement de création"]
    F --> G["Conserver le résultat sous reports"]
    G --> E
```

Par conséquent, effectuer les opérations suivantes dans le même processus ne met pas automatiquement à jour un disque déjà créé.

* Modifier `filesystems.disks.reports` avec `config()`.
* Appeler à nouveau `Storage::extend()` pour le même nom de driver.

`FilesystemServiceProvider` enregistre aussi le Manager lui-même comme singleton. Dans les processus de longue durée, ne supposez pas que les disques sont forcément recréés à chaque requête ou à chaque job.

## Après un changement de configuration, ne résoudre à nouveau que les disques nécessaires

Pour modifier la configuration et vérifier le résultat dans un même processus, séparez la mise à jour de la configuration de la suppression du disque conservé.

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

$before = Storage::disk('reports');

config(['filesystems.disks.reports.root' => storage_path('app/private/reports-v2')]);
Storage::forgetDisk('reports');

$after = Storage::disk('reports');
```

`forgetDisk()` retire le nom indiqué du tableau de conservation du Manager. Le prochain appel à `disk()` relit la configuration actuelle. Dans la version examinée, `purge()` se contente lui aussi de retirer le nom indiqué : il n'appelle pas de méthode de fermeture de connexion d'un backend propre.

<Warning>
  Les références conservées côté utilisation, comme `$before`, ne sont pas réécrites pour autant. Il en va de même lorsqu'un service singleton conserve un ancien disque. N'utilisez pas `forgetDisk()` comme un mécanisme qui mettrait à jour d'un seul coup toutes les références ou les autres processus.
</Warning>

Lors d'un changement de configuration en production ou d'une mise à jour du package, recréez le cache de configuration selon votre déploiement habituel et redémarrez aussi les workers de longue durée. Le cache de configuration et le tableau de conservation des disques de ce processus sont deux choses distinctes.

### Utiliser build pour une configuration temporaire

Si vous ne voulez pas modifier une configuration partagée nommée, vous pouvez utiliser un [disque à la demande](/fr/filesystem).

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

$disk = Storage::build([
    'driver' => 'acme-archive-local',
    'root' => storage_path('app/private/one-off-export'),
    'throw' => true,
]);
```

`build()` appelle directement `resolve()` avec la configuration indiquée et n'ajoute pas le résultat au tableau de conservation des disques nommés. L'enregistrement du driver personnalisé reste nécessaire, mais chaque appel passe par le traitement de création. Même lorsque vous utilisez des destinations dynamiques, ne concevez pas le système de sorte que la destination ou la cible de connexion puisse être choisie sans restriction à partir des saisies de l'utilisateur.

## Tester le chemin de création séparément de fake

`Storage::fake('reports')` remplace ce disque par un disque local de test via la méthode `set()` du Manager. C'est pratique pour tester les opérations sur des fichiers de l'application, mais cela **ne vérifie pas que le traitement de création personnalisé du package est correctement enregistré et exécuté**.

Après avoir chargé `ArchiveServiceProvider` dans [l'environnement de test du package](/fr/advanced/package-testing), vérifiez séparément les points suivants.

| Test | Ce qu'il faut vérifier |
| - | - |
| Démarrage normal | Si aucun disque n'est utilisé, ni la validation de la configuration ni les opérations sur des fichiers du traitement de création ne démarrent |
| Disques nommés | `reports` et `exports` reçoivent chacun leur propre configuration et sont des instances différentes |
| Nouvelle récupération du même nom | Appeler `disk('reports')` deux fois renvoie la même instance |
| Changement de configuration | Changer seulement la configuration renvoie la même instance ; après `forgetDisk()`, l'instance est différente |
| À la demande | Appeler `build()` deux fois avec la même configuration renvoie des instances différentes |
| Configuration invalide | Dans cet exemple, la résolution d'un disque sans `root` lève une exception |
| Lecture et écriture réelles | Vérifier l'enregistrement, la récupération et la suppression dans un répertoire dédié aux tests, puis nettoyer à la fin |
| Avec cache de configuration | Le driver est aussi enregistré et résolu dans une application de vérification fraîchement démarrée |

Pour un backend externe propre, séparez les tests de création qui n'utilisent pas le réseau des tests de connexion dans un environnement de vérification préparé explicitement. Ne considérez pas la réussite de fake comme une preuve de compatibilité avec le service réel.

## Checklist de maintenance à long terme

* Documenter comme spécification publique le nom du driver, les clés de configuration, l'API de la valeur de retour et le traitement des exceptions et de `throw`.
* Utiliser un nom d'extension qui n'entre pas en conflit avec les drivers standard ou d'autres packages.
* Ne pas résoudre ni utiliser de disque au simple démarrage du provider.
* Lors d'un changement de configuration, distinguer le cache de configuration, le tableau de conservation du Manager, les références côté utilisation et les autres processus.
* Pour chaque version de Laravel prise en charge, vérifier en continu la création, la nouvelle résolution et les opérations réelles sur des fichiers.

## Sources primaires consultées

* [Documentation officielle de Laravel : systèmes de fichiers personnalisés](https://github.com/laravel/docs/blob/12080c72699b/filesystem.md#custom-filesystems)
* [FilesystemManager : disk, build, resolve, forgetDisk, purge, extend](https://github.com/laravel/framework/blob/v13.37.0/src/Illuminate/Filesystem/FilesystemManager.php)
* [FilesystemServiceProvider : enregistrement du Manager comme singleton](https://github.com/laravel/framework/blob/v13.37.0/src/Illuminate/Filesystem/FilesystemServiceProvider.php)
* [Façade Storage : remplacement par un disque local via fake](https://github.com/laravel/framework/blob/v13.37.0/src/Illuminate/Support/Facades/Storage.php)
* [Tests officiels de Laravel : création, suppression et closures personnalisées des disques](https://github.com/laravel/framework/blob/v13.37.0/tests/Filesystem/FilesystemManagerTest.php)


## Related topics

- [Cache d'un package et intégration à optimize](/fr/advanced/package-optimization.md)
- [Enregistrement et portée des middlewares d'un package](/fr/advanced/package-middleware.md)
- [Package core et pilotes personnalisés - Feedable](/fr/packages/feedable/core.md)
- [Ajouter des informations de diagnostic du package à about](/fr/advanced/package-about.md)
- [Enregistrement et mise en cache des écouteurs d'événements d'un package](/fr/advanced/package-events.md)


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