Erstellen Sie Schritt für Schritt ein Bundle für Symfony 4

Vor etwa einem Jahr war unser Unternehmen auf dem Weg zur Trennung des riesigen Monolithen auf Magento 1 in Microservices. Als Basis wählten sie nur Symfony 4, das in der Version veröffentlicht wurde. Während dieser Zeit entwickelte ich mehrere Projekte auf diesem Framework, aber ich fand es besonders interessant, Bundles zu entwickeln und Komponenten für Symfony wiederzuverwenden. Unter der Katze eine Schritt-für-Schritt-Anleitung zur Entwicklung des HealthCheck-Bundles zur Ermittlung des Status / der Gesundheit eines Microservices unter Syfmony 4.1, in der ich versuchte, die interessantesten und komplexesten (für mich einmal) Momente zu berühren.


In unserem Unternehmen wird dieses Bundle beispielsweise verwendet, um den Status eines Produkt-Neuindex in ElasticSearch abzurufen - wie viele Produkte sind in Elastic mit aktuellen Daten enthalten und wie viele müssen indiziert werden.


Erstellen Sie ein Bündelskelett


In Symfony 3 gab es ein praktisches Bundle zum Generieren von Bundle-Skeletten, in Symfony 4 wird es jedoch nicht mehr unterstützt und daher müssen Sie das Skelett selbst erstellen. Ich beginne die Entwicklung jedes neuen Projekts mit der Gründung eines Teams


composer create-project symfony/skeleton health-check 

Bitte beachten Sie, dass Symfony 4 PHP 7.1+ unterstützt. Wenn Sie diesen Befehl in der folgenden Version ausführen, erhalten Sie das Projektskelett für Symfony 3.


Dieser Befehl erstellt ein neues Symfony 4.1-Projekt mit der folgenden Struktur:


Bild


Im Prinzip ist dies nicht erforderlich, da wir am Ende nicht so viel Dateien erstellen, aber es ist für mich bequemer, alles zu reinigen, was nicht benötigt wird, als das Notwendige mit meinen Händen zu erstellen.


composer.json


Der nächste Schritt besteht darin, composer.json an unsere Bedürfnisse anzupassen. Zunächst müssen Sie den Typ des Projekttyps in symfony-bundle diese Weise kann Symfony Flex beim Hinzufügen eines Bundles zum Projekt feststellen, dass es sich tatsächlich um ein Symfony-Bundle handelt, es automatisch verbinden und das Rezept installieren (dazu später mehr). Stellen Sie als Nächstes sicher, dass Sie die Felder name und description hinzufügen. name ist auch wichtig, da er bestimmt, in welchem ​​Ordner innerhalb des vendor Bundle abgelegt wird.


 "name": "niklesh/health-check", "description": "Health check bundle", 

Der nächste wichtige Schritt ist das Bearbeiten des autoload Abschnitts, der für das Laden der Bundle-Klassen verantwortlich ist. autoload für die Arbeitsumgebung, autoload-dev für die Arbeitsumgebung.


 "autoload": { "psr-4": { "niklesh\\HealthCheckBundle\\": "src" } }, "autoload-dev": { "psr-4": { "niklesh\\HealthCheckBundle\\Tests\\": "tests" } }, 

Der scripts kann gelöscht werden. Es enthält Skripte zum Zusammenstellen von Assets und zum Löschen des Caches nach Ausführung der composer install und composer update Befehle. Unser Bundle enthält jedoch keine Assets oder Caches. Daher sind diese Befehle unbrauchbar.


Der letzte Schritt besteht darin, die Abschnitte require und require-dev zu bearbeiten. Als Ergebnis erhalten wir Folgendes:


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

Ich stelle fest, dass die Abhängigkeiten von require installiert werden, wenn das Bundle mit dem Arbeitsentwurf verbunden ist.


Wir starten das composer update - Abhängigkeiten sind installiert.


Unnötige Reinigung


Aus den empfangenen Dateien können Sie also die folgenden Ordner sicher löschen:


  • bin - enthält die console , die zum Ausführen von Symfony-Befehlen erforderlich ist
  • config - enthält Konfigurationsdateien für das Routing, verbundene Bundles,
    Dienstleistungen usw.
  • public - enthält index.php - Einstiegspunkt in die Anwendung
  • Hier werden Var - Logs und cache gespeichert

Wir löschen auch die .env.dist src/Kernel.php , .env , .env.dist
Wir brauchen das alles nicht, weil wir ein Bundle entwickeln, keine Anwendung.


Bündelstruktur erstellen


Also haben wir die notwendigen Abhängigkeiten hinzugefügt und alles, was nicht benötigt wurde, aus unserem Bundle entfernt. Es ist Zeit, die erforderlichen Dateien und Ordner zu erstellen, um das Bundle erfolgreich mit dem Projekt zu verbinden.


Erstellen Sie zunächst im Ordner src die Datei HealthCheckBundle.php mit folgendem Inhalt:


 <?php namespace niklesh\HealthCheckBundle; use Symfony\Component\HttpKernel\Bundle\Bundle; class HealthCheckBundle extends Bundle { } 

Eine solche Klasse sollte in jedem von Ihnen erstellten Bundle enthalten sein. Er wird in die config/bundles.php Hauptprojekts aufgenommen. Außerdem kann er den "Build" des Bundles beeinflussen.


Die nächste benötigte Bundle-Komponente ist der Abschnitt DependencyInjection . Erstellen Sie den gleichnamigen Ordner mit 2 Dateien:


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

Diese Datei ist für das Parsen und Überprüfen der Bundle-Konfiguration aus Yaml- oder XML-Dateien verantwortlich. Wir werden es später ändern.


  • 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'); } } 

Diese Datei ist für das Laden von Bundle-Konfigurationsdateien, das Erstellen und Registrieren von "Definitions" -Diensten, das Laden von Parametern in einen Container usw. verantwortlich.


Der letzte Schritt in dieser Phase ist das Hinzufügen der Datei src/Resources/services.yaml , die eine Beschreibung der Dienste unseres Bundles enthält. Lass es jetzt leer.


HealthInterface


Die Hauptaufgabe unseres Bundles besteht darin, Daten über das Projekt zurückzugeben, in dem es verwendet wird. Das Sammeln von Informationen ist jedoch die Arbeit des Dienstes selbst. Unser Paket kann nur das Format der Informationen angeben, die der Dienst an ihn senden soll, und die Methode, mit der diese Informationen empfangen werden. In meiner Implementierung sollten alle Dienste (und möglicherweise mehrere), die Informationen sammeln, die HealthInterface Schnittstelle mit zwei Methoden getName : getName und getHealthInfo . Letzteres sollte ein Objekt zurückgeben, das die HealthDataInterface Schnittstelle implementiert.


Erstellen Sie zunächst die Datenschnittstelle 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; } 

Die Daten müssen einen ganzzahligen Status und zusätzliche Informationen enthalten (die übrigens leer sein können).


Da die Implementierung dieser Schnittstelle höchstwahrscheinlich für die meisten Nachkommen typisch ist, habe ich beschlossen, sie dem 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; } } 

Fügen Sie abschließend die Schnittstelle für die Datenerfassungsdienste src/Service/HealthInterface.php :


 <?php namespace niklesh\HealthCheckBundle\Service; use niklesh\HealthCheckBundle\Entity\HealthDataInterface; interface HealthInterface { public function getName(): string; public function getHealthInfo(): HealthDataInterface; } 

Controller


Der Controller gibt Daten über das Projekt auf nur einer Route weiter. Diese Route ist jedoch für alle Projekte, die dieses Bundle verwenden, gleich: /health


Die Aufgabe unseres Controllers besteht jedoch nicht nur darin, Daten HealthInterface , sondern sie auch aus den Diensten herauszuholen, die HealthInterface implementieren. HealthInterface muss der Controller Links zu jedem dieser Dienste speichern. Die addHealthService Methode ist für das Hinzufügen von Diensten zum Controller verantwortlich


Fügen Sie den Controller 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)); } } 

Zusammenstellung


Symfony kann bestimmte Aktionen mit Diensten ausführen, die eine bestimmte Schnittstelle implementieren. Sie können eine bestimmte Methode aufrufen, ein Tag hinzufügen, aber nicht alle diese Dienste in einen anderen Dienst (den Controller) übernehmen und einfügen. Dieses Problem wird in 4 Schritten gelöst:


Wir fügen jedem unserer HealthInterface das HealthInterface Tag hinzu.


Fügen Sie der Schnittstelle die TAG Konstante hinzu:


 interface HealthInterface { public const TAG = 'health.service'; } 

Als Nächstes müssen Sie dieses Tag jedem Dienst hinzufügen. Bei der Projektkonfiguration kann dies sein
Implementieren Sie in der Datei config/services.yaml im Abschnitt _instanceof . In unserem Fall dies
Der Eintrag würde folgendermaßen aussehen:


 serivces: _instanceof: niklesh\HealthCheckBundle\Service\HealthInterface: tags: - !php/const niklesh\HealthCheckBundle\Service\HealthInterface::TAG 

Wenn Sie dem Benutzer die Konfiguration des Bundles zuweisen, funktioniert dies im Prinzip. Meiner Meinung nach ist dies jedoch nicht der richtige Ansatz. Das Bundle selbst muss beim Hinzufügen zum Projekt korrekt verbunden und mit minimalem Benutzereingriff konfiguriert werden. Jemand könnte sich daran erinnern, dass wir unsere eigenen services.yaml im Bundle haben, aber nein, es wird uns nicht helfen. Diese Einstellung funktioniert nur, wenn sie sich in der Projektdatei befindet, nicht im Bundle.
Ich weiß nicht, ob dies ein Fehler oder eine Funktion ist, aber jetzt haben wir das, was wir haben. Daher müssen wir den Bundle-Kompilierungsprozess infiltrieren.


src/HealthCheckBundle.php und definieren Sie die build neu:


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

Jetzt wird jede Klasse, die HealthInterface implementiert, mit Tags versehen.


Registrieren des Controllers als Dienst


Im nächsten Schritt müssen wir den Controller als Service kontaktieren, während wir das Bundle kompilieren. Bei der Arbeit mit dem Projekt werden dort standardmäßig alle Klassen als Dienste registriert. Bei der Arbeit mit dem Bundle müssen wir jedoch explizit festlegen, welche Klassen Dienste sein sollen, Argumente für sie angeben und angeben, ob sie öffentlich sein werden.


Öffnen Sie die Datei src/Resources/config/services.yaml und fügen Sie den folgenden Inhalt hinzu


 services: niklesh\HealthCheckBundle\Controller\HealthController: autoconfigure: true 

Wir haben den Controller explizit als Service registriert, jetzt kann in der Kompilierungsphase darauf zugegriffen werden.


Hinzufügen von Diensten zum Controller.


In der Phase der Kompilierung des Containers und der Bundles können wir nur mit Service-Definitionen arbeiten. In diesem Stadium müssen wir die Definition des HealthController und angeben, dass nach seiner Erstellung alle mit unserem Tag gekennzeichneten Dienste hinzugefügt werden müssen. Für solche Operationen in Bundles sind Klassen verantwortlich, die die Schnittstelle implementieren
Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface


Erstellen Sie die folgende 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)]); } } } 

Wie Sie sehen können, verwenden wir zuerst die findDefinition Methode findDefinition um den Controller findDefinition übernehmen, dann - alle Dienste nach Tag und fügen dann in einer Schleife jedem gefundenen Dienst einen Aufruf der addHealthService Methode hinzu, wobei wir den Link zu diesem Dienst übergeben.


CompilerPath


Der letzte Schritt besteht darin, unseren HealthServicePath zum Bundle-Kompilierungsprozess hinzuzufügen. HealthCheckBundle wir zur HealthCheckBundle Klasse zurück und ändern die build etwas weiter. Als Ergebnis erhalten wir:


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

Grundsätzlich ist unser Bundle zu diesem Zeitpunkt einsatzbereit. Es kann Informationssammlungsdienste finden, mit ihnen arbeiten und bei Kontaktaufnahme /health eine Antwort geben (Sie müssen nur Routing-Einstellungen hinzufügen, wenn Sie eine Verbindung herstellen), aber ich habe beschlossen, die Möglichkeit einzubauen, Informationen nicht nur auf Anfrage zu senden, sondern auch diese Informationen an zu senden oder beispielsweise mithilfe einer POST-Anforderung oder über einen Warteschlangenmanager.


HealthSenderInterface


Diese Schnittstelle soll die Klassen beschreiben, die für das Senden von Daten an einen Ort verantwortlich sind. Erstellen Sie es in 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; } 

Wie Sie sehen können, verarbeitet die send Methode das empfangene Datenarray von allen Klassen, die HealthInterface implementieren, und sendet es dann an den gewünschten Ort.
Die getName getDescription und getName werden lediglich benötigt, um Informationen anzuzeigen, wenn ein Konsolenbefehl ausgeführt wird.


Senddatacommand


Starten Sie das Senden von Daten an Ressourcen von Drittanbietern mit dem Konsolenbefehl SendDataCommand . Seine Aufgabe besteht darin, Daten für die Verteilung zu sammeln und dann die send für jeden der Verteilungsdienste aufzurufen. Offensichtlich wiederholt dieser Befehl teilweise die Logik der Steuerung, aber nicht in allem.


 <?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 und schreiben dem Team zusätzliche Datenerfassungsdienste.


 <?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)]); } } } 

Wie Sie sehen können, akzeptiert der Befehl im Konstruktor ein Array von Absendern. In diesem Fall können Sie die Funktion zur automatischen Bindung von Abhängigkeiten nicht verwenden. Wir müssen selbst ein Team erstellen und registrieren. Die Frage ist nur, welche Absenderdienste diesem Befehl hinzugefügt werden sollen. Wir werden ihre ID in der Bundle-Konfiguration wie folgt angeben:


 health_check: senders: - '@sender.service1' - '@sender.service2' 

Unser Bundle weiß immer noch nicht, wie man mit solchen Konfigurationen umgeht, wir werden es lehren. Gehen Sie zu Configuration.php und fügen Sie den Konfigurationsbaum hinzu:


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

Dieser Code bestimmt, dass der health_check der health_check Knoten ist, der den senders Array- senders , der wiederum eine bestimmte Anzahl von Zeilen enthält. Das war's, jetzt weiß unser Bundle, wie man mit der oben beschriebenen Konfiguration umgeht. Es ist Zeit, das Team zu registrieren. Gehen Sie dazu zu HealthCheckExtension und fügen Sie den folgenden Code hinzu:


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

Das war's, unser Team ist entschlossen. Jetzt nach dem Hinzufügen des Bundles zum Projekt, wenn aufgerufen
bin/console Wir sehen eine Liste von Befehlen, einschließlich unserer: health:send-info , Sie können es genauso nennen: bin/console health:send-info


Unser Bundle ist fertig. Es ist Zeit, es am Projekt zu testen. Erstellen Sie ein leeres Projekt:


 composer create-project symfony/skeleton health-test-project 

Fügen Sie unser frisch gebackenes Bundle hinzu. Dazu fügen wir den Abschnitt repositories in composer.json :


 "repositories": [ { "type": "vcs", "url": "https://github.com/HEKET313/health-check" } ] 

Und führen Sie den Befehl aus:


 composer require niklesh/health-check 

Fügen Sie unserem Projekt für den schnellsten Start einen Symphony-Server hinzu:


 composer req --dev server 

Das Bundle ist verbunden, Symfony Flex verbindet es automatisch mit config/bundles.php jedoch automatisch Konfigurationsdateien zu erstellen, müssen Sie ein Rezept erstellen. Über Rezepte wird in einem anderen Artikel hier wunderschön gemalt: https://habr.com/post/345382/ - also malen Sie, wie man Rezepte usw. erstellt. Ich werde nicht hier sein und es gibt noch kein Rezept für dieses Bundle.


Trotzdem werden Konfigurationsdateien benötigt, also erstellen Sie sie mit Handles:


  • 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' 

Jetzt müssen Sie die Informationssendeklassen für das Team und die Informationssammelklasse implementieren


  • src/Service/DataCollector.php

Hier ist alles sehr einfach.


 <?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

Und hier ist es noch einfacher


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

Fertig! Leeren Sie den Cache und starten Sie den Server


 bin/console cache:clear bin/console server:start 

Jetzt können Sie unser Team ausprobieren:


 bin/console health:send-info 

Wir bekommen so ein schönes Fazit:


Bild


Schließlich klopfen wir auf unserer Route http://127.0.0.1:8000/health und bekommen eine weniger schöne, aber auch Schlussfolgerung:


 [{"name":"Data collector","info":{"status":1,"additional_info":{"some_data":"some_value"}}}] 

Das ist alles! Ich hoffe, dieses einfache Tutorial hilft jemandem, die Grundlagen des Schreibens von Bundles für Symfony 4 zu verstehen.


PS- Quellcode finden Sie hier .

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


All Articles