Créez pas à pas un bundle pour Symfony 4

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:


image


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 { /** * {@inheritdoc} */ 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 { /** @var HealthInterface[] */ private $healthServices = []; public function addHealthService(HealthInterface $healthService) { $this->healthServices[] = $healthService; } /** * @Route("/health") * @return JsonResponse */ 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 { /** * @param HealthDataInterface[] $data */ 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; /** @var HealthInterface[] */ private $healthServices; /** @var SymfonyStyle */ 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 { /** * {@inheritdoc} */ 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'); //    $commandDefinition = new Definition(SendDataCommand::class); //        foreach ($config['senders'] as $serviceId) { $commandDefinition->addArgument(new Reference($serviceId)); } //       $commandDefinition->addTag('console.command', ['command' => SendDataCommand::COMMAND_NAME]); //     $container->setDefinition(SendDataCommand::class, $commandDefinition); } } 

Ç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 --dev server 

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; } } 

  • src/Service/Sender.php

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 { /** * @param HealthDataInterface[] $data */ 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:


image


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 .

Source: https://habr.com/ru/post/fr419451/


All Articles