Magento 2 Webhook-meldingen • Proudnerds


Webhooks worden gebruikt om aan te geven wanneer een belangrijke gebeurtenis heeft plaatsgevonden, meestal door een melding in de vorm van een bericht naar een opgegeven webhook-URL of eindpunt te sturen. Dit kan erg handig zijn voor bepaalde evenementen, zoals wanneer een klant een bestelling plaatst of een opmerking achterlaat.

Het kan ook een erg handige manier zijn voor ontwikkelaars om direct op de hoogte te worden gesteld wanneer zich een uitzondering voordoet, zodat ze de informatie krijgen die ze nodig hebben om het probleem snel te lokaliseren en op te lossen.

In dit artikel laat ik je zien hoe je een module maakt waarmee je je eigen webhooks voor Magento 2 kunt configureren, gebruikmakend van de functie Incoming Webhooks van Slack.

de module

Laten we beginnen door een module te maken in de /app/code directory van onze Magento 2-module. In dit voorbeeld ga ik Proudnerds gebruiken als moduleverkoper en ga ik de module Webhooks noemen. Je kunt ze een naam geven zoals je wilt, want dat is jouw zaak.

We hebben de volgende mappen en bestanden nodig:

  • registration.php
  • /etc/module.xml
  • /etc/adminhtml/system.xml
  • /Model/Helper/Data.php
  • /Model/Webhook.php

registratie.php

Registreer de module in het Magento systeem. Kopieer de volgende code naar de registration.php het dossier:

<?php
 
MagentoFrameworkComponentComponentRegistrar::register(
    MagentoFrameworkComponentComponentRegistrar::MODULE,
    'Inchoo_Webhooks',
    __DIR__
);

module.xml

Declareer de naam en het bestaan ​​van de module. Kopieer de volgende code naar de /etc/module.xml het dossier:

<?xml version="1.0"?>
 
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Inchoo_Webhooks" setup_version="1.0.0">
    </module>
</config>

De configuratie

Na het instellen van de module, moeten we de beheerdersconfiguratie voor onze webhooks maken.

Kopieer de volgende code naar de /etc/adminhtml/system.xml het dossier:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
    <system>
        <section id="system">
            <group id="inchoo_webhooks" sortOrder="999" translate="label comment" showInDefault="1" showInWebsite="0" showInStore="0">
                <label>Webhook Notifications</label>
                <comment>
                    <![CDATA[To create Slack Incoming webhooks, visit <a href="https://api.slack.com/incoming-webhooks">https://api.slack.com/incoming-webhooks</a>]]>
                </comment>
 
                <field id="enable_webhooks" translate="label comment" type="select" sortOrder="5" showInDefault="1" showInWebsite="0" showInStore="0">
                    <label>Enabled</label>
                    <source_model>MagentoConfigModelConfigSourceYesno</source_model>
                </field>
 
                <field id="incoming_webhook_url" translate="label comment" type="text" sortOrder="10" showInDefault="1" showInWebsite="0" showInStore="0">
                    <label>Incoming Webhook URL</label>
                    <depends>
                        <field id="enable_webhooks">1</field>
                    </depends>
                </field>
 
                <field id="webhook_store_label" translate="label comment" type="text" sortOrder="15" showInDefault="1" showInWebsite="0" showInStore="0">
                    <label>Store Label</label>
                    <depends>
                        <field id="enable_webhooks">1</field>
                    </depends>
                </field>
 
                <field id="webhook_message_prefix" translate="label comment" type="text" sortOrder="20" showInDefault="1" showInWebsite="0" showInStore="0">
                    <label>Message Prefix</label>
                    <depends>
                        <field id="enable_webhooks">1</field>
                    </depends>
                </field>
 
                <field id="enable_stack_trace" translate="label comment" type="select" sortOrder="25" showInDefault="1" showInWebsite="0" showInStore="0">
                    <label>Stack Trace</label>
                    <source_model>MagentoConfigModelConfigSourceYesno</source_model>
                    <depends>
                        <field id="enable_webhooks">1</field>
                    </depends>
                </field>
            </group>
        </section>
    </system>
</config>

Wat dit doet, is dat het webhook-configuratievelden toevoegt aan de Magento 2-beheerdersinterface. Deze velden zijn te vinden onder: Stores -> Configuration -> Advanced -> Webhook Notifications en ze zouden er zo uit moeten zien:

Webhook Notifications

  • Ingeschakeld: schakelt de webhook-functionaliteit in
  • Inkomende webhook-URL: een webhook-URL geleverd door een geconfigureerde Slack-app
  • Winkellabel: het label dat in het webhook-bericht wordt weergegeven, bevat de winkel-URL
  • Berichtvoorvoegsel: tekst die vóór het webhook-bericht wordt geplaatst, Slack-emoji-codes kunnen hier worden gebruikt
  • Stapelspoor: indien ingeschakeld, tonen webhook-berichten een stacktracering na het opgegeven bericht

Om je eigen te maken Inkomende webhook-URL, ga naar https://api.slack.com/messaging/webhooks en volg de stappen daar. Voel je vrij om een ​​andere dienst te gebruiken.

de helper

De gegevens die in de configuratievelden zijn ingevoerd, worden opgeslagen in de core_config_data tabel, en we hebben een manier nodig om die informatie op te halen. Kopieer de volgende code naar de /Helper/Data.php het dossier:

<?php
 
declare(strict_types=1);
 
namespace ProudnerdsWebhooksHelper;
 
use MagentoFrameworkAppHelperAbstractHelper;
use MagentoFrameworkAppHelperContext;
use MagentoFrameworkAppConfigScopeConfigInterface;
use MagentoFrameworkExceptionNoSuchEntityException;
use MagentoStoreModelStoreManagerInterface;
 
/**
 * Class Data
 * @package ProudnerdsWebhooksHelper
 */
class Data extends AbstractHelper
{
    /**
     * @var StoreManagerInterface
     */
    private $storeManager;
 
    /**
     * Base path to Proudnerds Webhooks configuration values
     */
    private const XML_PATH_WEBHOOKS = 'system/inchoo_webhooks';
    private const XML_WEBHOOKS_ENABLED = self::XML_PATH_WEBHOOKS . '/enable_webhooks';
    private const XML_WEBHOOKS_STACK_TRACE_ENABLED = self::XML_PATH_WEBHOOKS . '/enable_stack_trace';
    private const XML_WEBHOOKS_INCOMING_WEBHOOK_URL = self::XML_PATH_WEBHOOKS . '/incoming_webhook_url';
    private const XML_WEBHOOKS_MESSAGE_PREFIX = self::XML_PATH_WEBHOOKS . '/webhook_message_prefix';
    private const XML_WEBHOOKS_STORE_LABEL = self::XML_PATH_WEBHOOKS . '/webhook_store_label';
 
    /**
     * Data constructor.
     *
     * @param Context $context
     * @param ScopeConfigInterface $scopeConfig
     * @param StoreManagerInterface $storeManager
     */
    public function __construct(
        Context $context,
        ScopeConfigInterface $scopeConfig,
        StoreManagerInterface $storeManager
    ) {
        $this->scopeConfig = $scopeConfig;
        $this->storeManager = $storeManager;
        parent::__construct($context);
    }
 
    /**
     * @return bool
     */
    public function isEnabled(): bool
    {
        return $this->scopeConfig->isSetFlag(self::XML_WEBHOOKS_ENABLED);
    }
 
    /**
     * @return bool
     */
    public function isStackTraceEnabled(): bool
    {
        return $this->scopeConfig->isSetFlag(self::XML_WEBHOOKS_STACK_TRACE_ENABLED);
    }
 
    /**
     * @return mixed
     */
    public function getIncomingWebhookURL()
    {
        return $this->scopeConfig->getValue(self::XML_WEBHOOKS_INCOMING_WEBHOOK_URL);
    }
 
    /**
     * @return mixed
     */
    public function getWebhookMessagePrefix()
    {
        return $this->scopeConfig->getValue(self::XML_WEBHOOKS_MESSAGE_PREFIX);
    }
 
    /**
     * @return mixed
     */
    public function getStoreLabel()
    {
        return $this->scopeConfig->getValue(self::XML_WEBHOOKS_STORE_LABEL);
    }
 
    /**
     * @return string
     * @throws NoSuchEntityException
     */
    public function getStoreName(): string
    {
        return $this->storeManager->getStore()->getName();
    }
 
    /**
     * @return mixed
     * @throws NoSuchEntityException
     */
    public function getStoreUrl()
    {
        return $this->storeManager->getStore()->getBaseUrl();
    }
}

Deze klasse bevat de paden naar onze opgeslagen waarden in de core_config_data

table en een aantal openbare methoden die we in onze Webhook-klasse gaan gebruiken om die gegevens op te halen.

de webhook

Nu onze configuratie is ingesteld en we onze hulpmethoden hebben, moeten we de Webhook-klasse definiëren die de logica zal bevatten die alle gegevens verwerkt en een bericht naar een geconfigureerde webhook-URL stuurt.

Kopieer de volgende code naar de /Model/Webhook.php het dossier:

<?php
 
declare(strict_types=1);
 
namespace ProudnerdsWebhooksModel;
 
use ProudnerdsWebhooksHelperData;
use MagentoFrameworkExceptionNoSuchEntityException;
use MagentoFrameworkHTTPAdapterCurlFactory;
use PsrLogLoggerInterface;
 
/**
 * Class Webhook
 * @package ProudnerdsWebhooksModel
 */
class Webhook
{
    /**
     * @var Data
     */
    private $webHookHelper;
 
    /**
     * @var CurlFactory
     */
    private $curlFactory;
 
    /**
     * @var LoggerInterface
     */
    private $logger;
 
    /**
     * Webhook constructor.
     * @param Data $webHookHelper
     * @param CurlFactory $curlFactory
     * @param LoggerInterface $logger
     */
    public function __construct(
        Data $webHookHelper,
        CurlFactory $curlFactory,
        LoggerInterface $logger
    ) {
        $this->webHookHelper = $webHookHelper;
        $this->curlFactory = $curlFactory;
        $this->logger = $logger;
    }
 
    /**
     * @param string $message
     * @return void
     * @throws NoSuchEntityException
     */
    public function sendWebhook(string $message): void
    {
        if (!$this->webHookHelper->isEnabled()) {
            return;
        }
 
        $url = $this->webHookHelper->getIncomingWebhookURL();
        $messagePrefix = $this->webHookHelper->getWebhookMessagePrefix();
 
        $storeName = $this->webHookHelper->getStoreName();
        $storeUrl = $this->webHookHelper->getStoreUrl();
        $storeLabel = $this->webHookHelper->getStoreLabel();
 
        $message = $messagePrefix ? $messagePrefix . ' ' . $message : $message;
 
        $text = '<' . $storeUrl . '|' . $storeLabel . '> | ' . $storeName . ': ' . $message;
        $text = $this->webHookHelper->isStackTraceEnabled() ? $text . ' ' . $this->stackTrace() : $text;
 
        $header = ['Content-type: application/json'];
        $body = json_encode(["text" =>  $text]);
 
        $client = $this->curlFactory->create();
        $client->addOption(CURLOPT_CONNECTTIMEOUT, 2);
        $client->addOption(CURLOPT_TIMEOUT, 3);
        $client->write(Zend_Http_Client::POST, $url, '1.1', $header, $body);
 
        $response = $client->read();
        $responseCode = Zend_Http_Response::extractCode($response);
 
        if ($responseCode !== 200) {
            $this->logger->log(100, 'Failed to send a message to the following Webhook: ' . $url);
        }
 
        $client->close();
    }
 
    /**
     * @return string
     */
    private function stackTrace(): string
    {
        $stackTrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
        $trace = [];
        foreach ($stackTrace as $row => $data) {
            if (!array_key_exists('file', $data) || !array_key_exists('line', $data)) {
                $trace[] = "# <unknown>";
            } else {
                $trace[] = "#{$row} {$data['file']}:{$data['line']} -> {$data['function']}()";
            }
        }
 
        return '```' .  implode("n", $trace) . '```';
    }
}

Laten we de code doornemen.

De klasse Webhook bevat twee methoden, de public sendWebhook() methode, en de privé stackTrace() methode.

De sendWebhook() methode is waar de meeste magie gebeurt. Er kan maar één argument aan deze methode worden doorgegeven, en dat is het bericht dat we via onze webhook willen sturen, in ons geval naar een Slack-kanaal. We kunnen deze methode bijvoorbeeld in een catch-blok aanroepen en het argument dat eraan wordt doorgegeven, kan het uitzonderingsbericht en de statuscode zijn.

In de methode controleren we eerst of webhooks zijn ingeschakeld in de beheerdersconfiguratie. Indien waar, gaat de methode verder en haalt de URL van de inkomende webhook, het berichtvoorvoegsel, de winkelnaam, de winkel-URL en het winkellabel op met behulp van de methoden die zijn gedefinieerd in onze Data.php-helper.

Daarna wordt het bericht opgemaakt met het berichtvoorvoegsel, de winkel-URL, het winkellabel en de winkelnaam. Als Stack Trace is ingeschakeld in de configuratie, wordt het verwerkt door de stackTrace() methode en toegevoegd aan de definitieve tekst.

De aanvraagheader wordt ingesteld als Content-type: application/json en de uiteindelijke tekst wordt json-gecodeerd en ingesteld in de hoofdtekst van het verzoek.

Omdat we de webhook-aanroep synchroon uitvoeren, maken we een Curl-instantie en stellen we de time-out voor de verbindingspoging in op 2 seconden en de uitvoeringstijd op 3 seconden, omdat we niet willen dat het verzoek te lang wordt uitgevoerd. We sturen het verzoek vervolgens via de webhook-URL en registreren eventuele mislukte pogingen om het bericht te verzenden.

Het einde

Roep de aan om de zaken af ​​te ronden bin/magento setup:upgrade commando en configureer de webhook via de beheerdersinterface. U kunt nu de gemaakte Webhook-klasse in elke andere aangepaste code injecteren en de bijbehorende . noemen sendWebhook() methode.

Een webhook-melding met Stack Trace ingeschakeld zou er ongeveer zo uit moeten zien:

Slack Webhook

Als je vragen of problemen hebt, aarzel dan niet om hieronder een reactie achter te laten.

badges

Let’s connect

We hebben altijd zin in nieuwe en uitdagende projecten. We gaan graag met je in gesprek!