Il y a environ un an, notre entreprise s'est dirigée vers la séparation de l'énorme monolithe de Magento 1 en microservices. Comme base, ils n'ont choisi que Symfony 4, qui a été publié dans la version Pendant ce temps, j'ai développé plusieurs projets sur ce framework, mais j'ai particuliÚrement trouvé intéressant de développer des bundles, des composants réutilisés pour Symfony. Sous le chat, un guide étape par étape sur le développement du bundle HealthCheck pour obtenir l'état / la santé d'un microservice sous Syfmony 4.1, dans lequel j'ai essayé de toucher aux moments les plus intéressants et complexes (pour moi une fois).
Dans notre entreprise, cet ensemble est utilisé, par exemple, pour obtenir le statut d'une réindexation de produit dans ElasticSearch - combien de produits sont contenus dans Elastic avec les données actuelles et combien nécessitent une indexation.
Créer un squelette de bundle
Dans Symfony 3, il y avait un bundle pratique pour gĂ©nĂ©rer des squelettes de bundle, mais dans Symfony 4, il n'est plus pris en charge et vous devez donc crĂ©er le squelette vous-mĂȘme. Je commence le dĂ©veloppement de chaque nouveau projet en lançant une Ă©quipe
composer create-project symfony/skeleton health-check
Veuillez noter que Symfony 4 prend en charge PHP 7.1+, donc si vous exécutez cette commande sur la version ci-dessous, vous obtiendrez le squelette du projet pour Symfony 3.
Cette commande crée un nouveau projet Symfony 4.1 avec la structure suivante:

En principe, ce n'est pas nécessaire, à cause des fichiers créés dont nous n'avons pas tellement besoin à la fin, mais il est plus pratique pour moi de nettoyer tout ce qui n'est pas nécessaire que de créer le nécessaire avec mes mains.
composer.json
L'étape suivante consiste à modifier composer.json
selon nos besoins. Tout d'abord, vous devez changer le type du type de projet en symfony-bundle
cela aidera Symfony Flex à déterminer lors de l'ajout d'un bundle au projet qu'il s'agit vraiment d'un bundle Symfony, le connecter automatiquement et installer la recette (mais plus à ce sujet plus tard). Assurez-vous ensuite d'ajouter les champs de name
et de description
. name
est également important car il détermine dans quel dossier du vendor
bundle sera placé.
"name": "niklesh/health-check", "description": "Health check bundle",
La prochaine étape importante consiste à modifier la section de autoload
, qui est responsable du chargement des classes de bundle. autoload
pour l'environnement de travail, autoload-dev
pour l'environnement de travail.
"autoload": { "psr-4": { "niklesh\\HealthCheckBundle\\": "src" } }, "autoload-dev": { "psr-4": { "niklesh\\HealthCheckBundle\\Tests\\": "tests" } },
La section des scripts
peut ĂȘtre supprimĂ©e. Il contient des scripts pour assembler les actifs et vider le cache aprĂšs avoir exĂ©cutĂ© les commandes d' composer install
et de composer update
, cependant, notre bundle ne contient aucun actif ni cache, ces commandes sont donc inutiles.
La derniÚre étape consiste à modifier les sections require
et require-dev
. En conséquence, nous obtenons ce qui suit:
"require": { "php": "^7.1.3", "ext-ctype": "*", "ext-iconv": "*", "symfony/flex": "^1.0", "symfony/framework-bundle": "^4.1", "sensio/framework-extra-bundle": "^5.2", "symfony/lts": "^4@dev", "symfony/yaml": "^4.1" }
Je note que les dépendances de require
seront installées lorsque le bundle sera connecté au brouillon de travail.
Nous commençons la composer update
- les dépendances sont installées.
Nettoyage inutile
Ainsi, à partir des fichiers reçus, vous pouvez supprimer en toute sécurité les dossiers suivants:
- bin - contient le fichier de
console
nécessaire pour exécuter les commandes Symfony - config - contient des fichiers de configuration pour le routage, les bundles connectés,
services, etc. - public - contient
index.php
- point d'entrée vers l'application - var - les journaux et le
cache
sont stockés ici
Nous .env
.env.dist
src/Kernel.php
, .env
, .env.dist
Nous n'avons pas besoin de tout cela car nous développons un bundle, pas une application.
Création d'une structure de bundle
Nous avons donc ajouté les dépendances nécessaires et nettoyé tout ce qui n'était pas nécessaire de notre bundle. Il est temps de créer les fichiers et dossiers nécessaires pour connecter correctement le bundle au projet.
Tout d'abord, dans le dossier src
, créez le fichier HealthCheckBundle.php
avec le contenu suivant:
<?php namespace niklesh\HealthCheckBundle; use Symfony\Component\HttpKernel\Bundle\Bundle; class HealthCheckBundle extends Bundle { }
Une telle classe doit figurer dans chaque bundle que vous créez. Il sera config/bundles.php
dans le config/bundles.php
projet principal. De plus, il peut influencer la "construction" du bundle.
Le prochain composant de bundle nécessaire est la section DependencyInjection
. CrĂ©ez le dossier du mĂȘme nom avec 2 fichiers:
src/DependencyInjection/Configuration.php
<?php namespace niklesh\HealthCheckBundle\DependencyInjection; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; class Configuration implements ConfigurationInterface { public function getConfigTreeBuilder() { $treeBuilder = new TreeBuilder(); $treeBuilder->root('health_check'); return $treeBuilder; } }
Ce fichier est chargé d'analyser et de valider la configuration de l'ensemble à partir de fichiers Yaml ou xml. Nous le modifierons plus tard.
src/DependencyInjection/HealthCheckExtension.php
<?php namespace niklesh\HealthCheckBundle\DependencyInjection; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\DependencyInjection\Loader; class HealthCheckExtension extends Extension { public function load(array $configs, ContainerBuilder $container) { $configuration = new Configuration(); $this->processConfiguration($configuration, $configs); $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); $loader->load('services.yaml'); } }
Ce fichier est responsable du chargement des fichiers de configuration du bundle, de la création et de l'enregistrement des services de «définition», du chargement des paramÚtres dans un conteneur, etc.
Et la derniÚre étape à ce stade consiste à ajouter le fichier src/Resources/services.yaml
, qui contiendra une description des services de notre bundle. Laissez-le vide pour l'instant.
HealthInterface
La tĂąche principale de notre bundle sera de renvoyer des donnĂ©es sur le projet dans lequel il est utilisĂ©. Mais la collecte d'informations est le travail du service lui-mĂȘme, notre bundle ne peut qu'indiquer le format des informations que le service doit lui transmettre, et la mĂ©thode qui recevra ces informations. Dans mon implĂ©mentation, tous les services (et il peut y en avoir plusieurs) qui collectent des informations doivent implĂ©menter l'interface getName
avec 2 méthodes: getName
et getHealthInfo
. Ce dernier doit renvoyer un objet qui implémente l'interface HealthDataInterface
.
Tout d'abord, créez l'interface de données src/Entity/HealthDataInterface.php
:
<?php namespace niklesh\HealthCheckBundle\Entity; interface HealthDataInterface { public const STATUS_OK = 1; public const STATUS_WARNING = 2; public const STATUS_DANGER = 3; public const STATUS_CRITICAL = 4; public function getStatus(): int; public function getAdditionalInfo(): array; }
Les donnĂ©es doivent contenir un Ă©tat entier et des informations supplĂ©mentaires (qui, soit dit en passant, peuvent ĂȘtre vides).
Ătant donnĂ© que la mise en Ćuvre de cette interface sera probablement typique de la plupart des descendants, j'ai dĂ©cidĂ© de l'ajouter au src/Entity/CommonHealthData.php
:
<?php namespace niklesh\HealthCheckBundle\Entity; class CommonHealthData implements HealthDataInterface { private $status; private $additionalInfo = []; public function __construct(int $status) { $this->status = $status; } public function setStatus(int $status) { $this->status = $status; } public function setAdditionalInfo(array $additionalInfo) { $this->additionalInfo = $additionalInfo; } public function getStatus(): int { return $this->status; } public function getAdditionalInfo(): array { return $this->additionalInfo; } }
Enfin, ajoutez l'interface pour les services de collecte de données src/Service/HealthInterface.php
:
<?php namespace niklesh\HealthCheckBundle\Service; use niklesh\HealthCheckBundle\Entity\HealthDataInterface; interface HealthInterface { public function getName(): string; public function getHealthInfo(): HealthDataInterface; }
ContrĂŽleur
Le contrĂŽleur fournira des donnĂ©es sur le projet dans un seul itinĂ©raire. Mais cette route sera la mĂȘme pour tous les projets utilisant ce bundle: /health
Cependant, la tùche de notre contrÎleur n'est pas seulement de fournir des données, mais également de les extraire des services qui implémentent HealthInterface
; en conséquence, le contrÎleur doit stocker des liens vers chacun de ces services. La méthode addHealthService
sera chargée d'ajouter des services au contrÎleur
Ajoutez le contrĂŽleur src/Controller/HealthController.php
:
<?php namespace niklesh\HealthCheckBundle\Controller; use niklesh\HealthCheckBundle\Service\HealthInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\Routing\Annotation\Route; class HealthController extends AbstractController { private $healthServices = []; public function addHealthService(HealthInterface $healthService) { $this->healthServices[] = $healthService; } public function getHealth(): JsonResponse { return $this->json(array_map(function (HealthInterface $healthService) { $info = $healthService->getHealthInfo(); return [ 'name' => $healthService->getName(), 'info' => [ 'status' => $info->getStatus(), 'additional_info' => $info->getAdditionalInfo() ] ]; }, $this->healthServices)); } }
Compilation
Symfony peut effectuer certaines actions avec des services qui implémentent une interface spécifique. Vous pouvez appeler une méthode spécifique, ajouter une balise, mais vous ne pouvez pas prendre et injecter tous ces services dans un autre service (qui est le contrÎleur). Ce problÚme est résolu en 4 étapes:
Nous ajoutons Ă chacun de nos HealthInterface
implémentation de la balise HealthInterface
.
Ajoutez la constante TAG
Ă l'interface:
interface HealthInterface { public const TAG = 'health.service'; }
Ensuite, vous devez ajouter cette balise Ă chaque service. Dans le cas d'une configuration de projet, cela peut ĂȘtre
implémenter dans le fichier config/services.yaml
dans la section _instanceof
. Dans notre cas, cela
l'entrée ressemblerait à ceci:
serivces: _instanceof: niklesh\HealthCheckBundle\Service\HealthInterface: tags: - !php/const niklesh\HealthCheckBundle\Service\HealthInterface::TAG
Et, en principe, si vous confiez la configuration du bundle Ă l'utilisateur, cela fonctionnera, mais Ă mon avis, ce n'est pas la bonne approche, le bundle lui-mĂȘme doit ĂȘtre connectĂ© correctement et configurĂ© avec une intervention minimale de l'utilisateur lorsqu'il est ajoutĂ© au projet. Quelqu'un peut se souvenir que nous avons nos propres services.yaml
dans le bundle, mais non, cela ne nous aidera pas. Ce paramĂštre ne fonctionne que s'il se trouve dans le fichier de projet, pas dans le bundle.
Je ne sais pas si c'est un bug ou une fonctionnalité, mais maintenant nous avons ce que nous avons. Par conséquent, nous devrons infiltrer le processus de compilation du bundle.
Accédez au src/HealthCheckBundle.php
et redéfinissez la méthode de build
:
<?php namespace niklesh\HealthCheckBundle; use niklesh\HealthCheckBundle\Service\HealthInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; class HealthCheckBundle extends Bundle { public function build(ContainerBuilder $container) { parent::build($container); $container->registerForAutoconfiguration(HealthInterface::class)->addTag(HealthInterface::TAG); } }
Désormais, chaque classe qui implémente HealthInterface
sera étiquetée.
Enregistrement du contrĂŽleur en tant que service
Dans l'étape suivante, nous devrons contacter le contrÎleur en tant que service, au stade de la compilation du bundle. Dans le cas de travailler avec le projet, toutes les classes sont enregistrées en tant que services par défaut, mais dans le cas de travailler avec le bundle, nous devons déterminer explicitement quelles classes seront des services, mettre des arguments pour elles et indiquer si elles seront publiques.
Ouvrez le fichier src/Resources/config/services.yaml
et ajoutez le contenu suivant
services: niklesh\HealthCheckBundle\Controller\HealthController: autoconfigure: true
Nous avons explicitement enregistré le contrÎleur en tant que service, maintenant il est accessible au stade de la compilation.
Ajout de services au contrĂŽleur.
Au stade de la compilation du conteneur et des bundles, nous ne pouvons fonctionner qu'avec des définitions de service. à ce stade, nous devons prendre la définition du HealthController
et indiquer qu'aprÚs sa création, il est nécessaire d'y ajouter tous les services marqués de notre balise. Pour de telles opérations en bundles, les classes qui implémentent l'interface sont responsables
Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface
Créez la src/DependencyInjection/Compiler/HealthServicePath.php
:
<?php namespace niklesh\HealthCheckBundle\DependencyInjection\Compiler; use niklesh\HealthCheckBundle\Controller\HealthController; use niklesh\HealthCheckBundle\Service\HealthInterface; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; class HealthServicesPath implements CompilerPassInterface { public function process(ContainerBuilder $container) { if (!$container->has(HealthController::class)) { return; } $controller = $container->findDefinition(HealthController::class); foreach (array_keys($container->findTaggedServiceIds(HealthInterface::TAG)) as $serviceId) { $controller->addMethodCall('addHealthService', [new Reference($serviceId)]); } } }
Comme vous pouvez le voir, nous utilisons d'abord la méthode findDefinition
prendre le contrÎleur, puis - tous les services par tag, puis, en boucle, ajoutons un appel à la méthode addHealthService
Ă chaque service trouvĂ©, oĂč nous transmettons le lien vers ce service.
Utilisation de CompilerPath
La derniÚre étape consiste à ajouter notre HealthServicePath
au processus de compilation du bundle. Revenons Ă la classe HealthCheckBundle
et modifions un peu plus la méthode de build
. En conséquence, nous obtenons:
<?php namespace niklesh\HealthCheckBundle; use niklesh\HealthCheckBundle\DependencyInjection\Compiler\HealthServicesPath; use niklesh\HealthCheckBundle\Service\HealthInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; class HealthCheckBundle extends Bundle { public function build(ContainerBuilder $container) { parent::build($container); $container->addCompilerPass(new HealthServicesPath()); $container->registerForAutoconfiguration(HealthInterface::class)->addTag(HealthInterface::TAG); } }
Fondamentalement, Ă ce stade, notre offre est prĂȘte Ă l'emploi. Il peut trouver des services de collecte d'informations, travailler avec eux et donner une rĂ©ponse lors du contact /health
(il vous suffit d'ajouter des paramÚtres de routage lors de la connexion), mais j'ai décidé d'y mettre non seulement la possibilité d'envoyer des informations sur demande, mais également de pouvoir envoyer ces informations à ou, par exemple, à l'aide d'une demande POST ou via un gestionnaire de files d'attente.
HealthSenderInterface
Cette interface est destinée à décrire les classes responsables de l'envoi de données quelque part. Créez-le dans src/Service/HealthSenderInterface
<?php namespace niklesh\HealthCheckBundle\Service; use niklesh\HealthCheckBundle\Entity\HealthDataInterface; interface HealthSenderInterface { public function send(array $data): void; public function getDescription(): string; public function getName(): string; }
Comme vous pouvez le voir, la méthode send
traitera en quelque sorte le tableau de données reçu de toutes les classes implémentant HealthInterface
, puis l'enverra lĂ oĂč il le faut.
Les getName
getDescription
et getName
sont nécessaires simplement pour afficher des informations lors de l'exécution d'une commande de console.
Senddatacommand
Commencer à envoyer des données à des ressources tierces sera la commande de la console SendDataCommand
. Sa tùche consiste à collecter des données pour la distribution, puis à appeler la méthode d' send
sur chacun des services de distribution. Ăvidemment, cette commande rĂ©pĂ©tera partiellement la logique du contrĂŽleur, mais pas en tout.
<?php namespace niklesh\HealthCheckBundle\Command; use niklesh\HealthCheckBundle\Entity\HealthDataInterface; use niklesh\HealthCheckBundle\Service\HealthInterface; use niklesh\HealthCheckBundle\Service\HealthSenderInterface; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Throwable; class SendDataCommand extends Command { public const COMMAND_NAME = 'health:send-info'; private $senders; private $healthServices; private $io; public function __construct(HealthSenderInterface... $senders) { parent::__construct(self::COMMAND_NAME); $this->senders = $senders; } public function addHealthService(HealthInterface $healthService) { $this->healthServices[] = $healthService; } protected function configure() { parent::configure(); $this->setDescription('Send health data by senders'); } protected function initialize(InputInterface $input, OutputInterface $output) { parent::initialize($input, $output); $this->io = new SymfonyStyle($input, $output); } protected function execute(InputInterface $input, OutputInterface $output) { $this->io->title('Sending health info'); try { $data = array_map(function (HealthInterface $service): HealthDataInterface { return $service->getHealthInfo(); }, $this->healthServices); foreach ($this->senders as $sender) { $this->outputInfo($sender); $sender->send($data); } $this->io->success('Data is sent by all senders'); } catch (Throwable $exception) { $this->io->error('Exception occurred: ' . $exception->getMessage()); $this->io->text($exception->getTraceAsString()); } } private function outputInfo(HealthSenderInterface $sender) { if ($name = $sender->getName()) { $this->io->writeln($name); } if ($description = $sender->getDescription()) { $this->io->writeln($description); } } }
HealthServicesPath
, écrivons l'ajout de services de collecte de données à l'équipe.
<?php namespace niklesh\HealthCheckBundle\DependencyInjection\Compiler; use niklesh\HealthCheckBundle\Command\SendDataCommand; use niklesh\HealthCheckBundle\Controller\HealthController; use niklesh\HealthCheckBundle\Service\HealthInterface; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; class HealthServicesPath implements CompilerPassInterface { public function process(ContainerBuilder $container) { if (!$container->has(HealthController::class)) { return; } $controller = $container->findDefinition(HealthController::class); $commandDefinition = $container->findDefinition(SendDataCommand::class); foreach (array_keys($container->findTaggedServiceIds(HealthInterface::TAG)) as $serviceId) { $controller->addMethodCall('addHealthService', [new Reference($serviceId)]); $commandDefinition->addMethodCall('addHealthService', [new Reference($serviceId)]); } } }
Comme vous pouvez le voir, la commande du constructeur accepte un tableau d'expĂ©diteurs. Dans ce cas, vous ne pourrez pas utiliser la fonction de liaison automatique des dĂ©pendances; nous devons crĂ©er et enregistrer une Ă©quipe nous-mĂȘmes. La seule question est de savoir quels services d'expĂ©diteur ajouter Ă cette commande. Nous indiquerons leur identifiant dans la configuration du bundle comme ceci:
health_check: senders: - '@sender.service1' - '@sender.service2'
Notre bundle ne sait toujours pas gérer de telles configurations, nous allons l'enseigner. Accédez à Configuration.php
et ajoutez l'arborescence de configuration:
<?php namespace niklesh\HealthCheckBundle\DependencyInjection; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; class Configuration implements ConfigurationInterface { public function getConfigTreeBuilder() { $treeBuilder = new TreeBuilder(); $rootNode = $treeBuilder->root('health_check'); $rootNode ->children() ->arrayNode('senders') ->scalarPrototype()->end() ->end() ->end() ; return $treeBuilder; } }
Ce code dĂ©termine que le nĆud racine sera le nĆud health_check
, qui contiendra le senders
tableau des senders
, qui à son tour contiendra un certain nombre de lignes. Voilà , maintenant notre bundle sait comment gérer la configuration, que nous avons décrite ci-dessus. Il est temps d'inscrire l'équipe. Pour ce faire, accédez à HealthCheckExtension
et ajoutez le code suivant:
<?php namespace niklesh\HealthCheckBundle\DependencyInjection; use niklesh\HealthCheckBundle\Command\SendDataCommand; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\DependencyInjection\Loader; use Symfony\Component\DependencyInjection\Reference; class HealthCheckExtension extends Extension { public function load(array $configs, ContainerBuilder $container) { $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); $loader->load('services.yaml');
Ăa y est, notre Ă©quipe est dĂ©terminĂ©e. Maintenant, aprĂšs avoir ajoutĂ© le bundle au projet, lorsqu'il est appelĂ©
bin/console
nous verrons une liste de commandes, dont la nĂŽtre: health:send-info
, vous pouvez l'appeler de la mĂȘme maniĂšre: bin/console health:send-info
Notre bundle est prĂȘt. Il est temps de le tester sur le projet. CrĂ©ez un projet vide:
composer create-project symfony/skeleton health-test-project
Ajoutez-y notre paquet fraßchement préparé, pour cela nous ajoutons la section des repositories
dans composer.json
:
"repositories": [ { "type": "vcs", "url": "https://github.com/HEKET313/health-check" } ]
Et exécutez la commande:
composer require niklesh/health-check
Et aussi, pour le démarrage le plus rapide, ajoutez un serveur symphony à notre projet:
composer req
Le bundle est connecté, Symfony Flex le connecte automatiquement à config/bundles.php
, mais pour créer automatiquement des fichiers de configuration, vous devez créer une recette. à propos des recettes est magnifiquement peint dans un autre article ici: https://habr.com/post/345382/ - alors peignez comment créer des recettes, etc. Je ne serai pas là , et il n'y a pas encore de recette pour ce pack.
Néanmoins, des fichiers de configuration sont nécessaires, alors créez-les avec des poignées:
config/routes/niklesh_health.yaml
health_check: resource: "@HealthCheckBundle/Controller/HealthController.php" prefix: / type: annotation
config/packages/hiklesh_health.yaml
health_check: senders: - 'App\Service\Sender'
Vous devez maintenant implémenter les classes d'envoi d'informations pour l'équipe et la classe de collecte d'informations
src/Service/DataCollector.php
Ici, tout est extrĂȘmement simple.
<?php namespace App\Service; use niklesh\HealthCheckBundle\Entity\CommonHealthData; use niklesh\HealthCheckBundle\Entity\HealthDataInterface; use niklesh\HealthCheckBundle\Service\HealthInterface; class DataCollector implements HealthInterface { public function getName(): string { return 'Data collector'; } public function getHealthInfo(): HealthDataInterface { $data = new CommonHealthData(HealthDataInterface::STATUS_OK); $data->setAdditionalInfo(['some_data' => 'some_value']); return $data; } }
Et ici, c'est encore plus facile
<?php namespace App\Service; use niklesh\HealthCheckBundle\Entity\HealthDataInterface; use niklesh\HealthCheckBundle\Service\HealthSenderInterface; class Sender implements HealthSenderInterface { public function send(array $data): void { print "Data sent\n"; } public function getDescription(): string { return 'Sender description'; } public function getName(): string { return 'Sender name'; } }
C'est fait! Vider le cache et démarrer le serveur
bin/console cache:clear bin/console server:start
Vous pouvez maintenant essayer notre équipe:
bin/console health:send-info
Nous obtenons une si belle conclusion:

Enfin, nous frappons sur notre itinéraire http://127.0.0.1:8000/health
et obtenons une moins belle, mais aussi conclusion:
[{"name":"Data collector","info":{"status":1,"additional_info":{"some_data":"some_value"}}}]
C'est tout! J'espÚre que ce tutoriel simple aidera quelqu'un à comprendre les bases de l'écriture de bundles pour Symfony 4.
Le code source PS est disponible ici .