Link im Backend soll einen POST-Befehl ausführen

Ich versuche seit Stunden das Problem zu lösen aber schaffe es leider nicht. Ich bin noch recht unerfahren mit Plugins erstellen für Shopware.
Ich möchte einen Link auf der Einstellungsseite für Produkte hinterlegen, wenn man auf diesen klickt (<a href=„#“ @click.prevent=„generatePdf“>PDF-Vorschau erstellen) soll in einem neuen Fenster die generierte PDF geöffnet werden.

import template from './sw-product-detail-specifications.html.twig';

const { Component } = Shopware;

Component.override('sw-product-detail-specifications', {
    template,

    methods: {
        generatePdf() {
            let htmlContent = document.getElementById('MyPlugin_html').value;
            const mediaField = document.querySelector('sw-media-field[name="MyPlugin_img"]');

            if (mediaField) {
                const mediaItem = mediaField.querySelector('.sw-media-preview-v2 img');

                if (mediaItem) {
                    htmlContent = htmlContent.replace(/{mediaUrl}/gi, mediaItem.src);
                }
            }

            if (!htmlContent) {
                this.createNotificationError({
                    title: 'Fehler',
                    message: 'Bitte gib den HTML-Inhalt ein.'
                });
                return;
            }
            
            this.$http.post('/api/v1/myplugin/create-pdf', { html: htmlContent })
                .then(response => {
                    const pdfData = response.data;
                    const blob = new Blob([pdfData], { type: 'application/pdf' });
                    const url = URL.createObjectURL(blob);

                    window.open(url, '_blank');
                })
                .catch(error => {
                    console.error(error);
                    this.createNotificationError({
                        title: 'Fehler',
                        message: 'Das PDF konnte nicht erstellt werden.'
                    });
                });
        }
    }
});

das ist der js-Code den ich anschließend mit build-administration.sh umwandle.

Wenn ich aber auf den Link klicke passiert nichts, in meiner Browser Konsole steht:

An error was captured in current module: TypeError: Cannot read properties of undefined (reading 'post')
    at Proxy.generatePdf (myplugin.js?1730830351:1:6788)
    at c.583802.n.<computed>.n.<computed> (app.js?1725261915:57:50736)
    at t2 (app.js?1725261915:45:664)
    at t5 (app.js?1725261915:45:732)
    at HTMLAnchorElement.n (app.js?1725261915:57:52359)

Mein Controller sieht so aus:

<?php declare(strict_types=1);

namespace MyPlugin\Controller;

use MyPlugin\Service\CreatePdfService;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Shopware\Core\Framework\Context;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;

class CreatePdfController extends AbstractController
{
    private CreatePdfService $createPdfService;

    public function __construct(CreatePdfService $createPdfService)
    {
        $this->createPdfService = $createPdfService;
    }

    #[Route(path: '/api/v{version}/myplugin/create-pdf', name: 'api.myplugin.create-pdf', methods: ['POST'], defaults: ['_routeScope' => ['admin']])]
    public function createPdf(Request $request): Response
    {
        $pdfData = $this->createPdfService->create($request->get('html'));
        //$pdfData = dompdf->output()
        return new Response($pdfData, 200, [
            'Content-Type' => 'application/pdf',
            'Content-Disposition' => 'inline; filename="preview.pdf"'
        ]);
    }
}

Ebenfalls denke ich das this.createNotificationError wohl dann auch nicht funktioniert.

Wäre super nett wenn mir jemand helfen könnte :slight_smile:

copy&paste ChatGPT

Ich sehe schon, das ist eine knifflige Stelle! Bei Shopware gibt es ein paar spezifische Eigenheiten, wenn man mit this.$http und solchen Benachrichtigungen in der Administration arbeitet. Ich helfe dir Schritt für Schritt herauszufinden, was da nicht klappt und wie du es zum Laufen bringen kannst. Lass uns die Sache angehen:

Problemursache

Der Fehler "Cannot read properties of undefined (reading 'post')" deutet darauf hin, dass this.$http nicht initialisiert oder verfügbar ist. this.$http existiert in Shopware 6 Administration standardmäßig nicht als $http-Instanz. Stattdessen wird in Shopware 6 oft der repositoryFactory oder axios für HTTP-Requests verwendet.

Außerdem gibt es auch das Problem mit this.createNotificationError, das auch auf fehlende Shopware-Spezifikationen hinweist.

Lösungsvorschlag: Alternative HTTP-Request Methode

Du kannst stattdessen Shopware.Service('storeService') nutzen, um den API-Call zu realisieren.

Hier eine angepasste Version des JavaScript-Codes:

javascript

Code kopieren

import template from './sw-product-detail-specifications.html.twig';

const { Component } = Shopware;

Component.override('sw-product-detail-specifications', {
    template,

    methods: {
        generatePdf() {
            let htmlContent = document.getElementById('MyPlugin_html').value;
            const mediaField = document.querySelector('sw-media-field[name="MyPlugin_img"]');

            if (mediaField) {
                const mediaItem = mediaField.querySelector('.sw-media-preview-v2 img');

                if (mediaItem) {
                    htmlContent = htmlContent.replace(/{mediaUrl}/gi, mediaItem.src);
                }
            }

            if (!htmlContent) {
                this.createNotificationError({
                    title: 'Fehler',
                    message: 'Bitte gib den HTML-Inhalt ein.'
                });
                return;
            }
            
            // Hier wird der alternative HTTP-Request verwendet
            Shopware.Service('storeService').httpClient.post(
                '/api/v1/myplugin/create-pdf',
                { html: htmlContent },
                { responseType: 'arraybuffer' }
            ).then(response => {
                const pdfData = response.data;
                const blob = new Blob([pdfData], { type: 'application/pdf' });
                const url = URL.createObjectURL(blob);

                window.open(url, '_blank');
            }).catch(error => {
                console.error(error);
                this.createNotificationError({
                    title: 'Fehler',
                    message: 'Das PDF konnte nicht erstellt werden.'
                });
            });
        }
    }
});

Erklärung der Änderungen

  1. HTTP-Request: Statt this.$http.post verwenden wir Shopware.Service('storeService').httpClient.post, was dem empfohlenen Weg für HTTP-Requests in der Administration entspricht.
  • Beachte auch, dass responseType: 'arraybuffer' gesetzt wurde, damit die PDF-Daten im richtigen Format verarbeitet werden.
  1. Fehlerbenachrichtigungen: Mit this.createNotificationError hast du den richtigen Ansatz gewählt, aber manchmal hilft es auch, das Notification-Plugin explizit zu importieren:

javascript

Code kopieren

const { Component, Mixin } = Shopware;

Component.override('sw-product-detail-specifications', {
    template,
    mixins: [Mixin.getByName('notification')],

Das Hinzufügen des Notification-Mixins sollte sicherstellen, dass createNotificationError verfügbar ist.

Zusätzliche Hinweise

  • Stelle sicher, dass der Endpunkt '/api/v1/myplugin/create-pdf' auch tatsächlich in deiner services.xml oder routes.yaml definiert ist, damit die Route funktioniert.
  • Wenn du weiterhin Schwierigkeiten hast, prüfe, ob die Route auch den richtigen Zugriff hat (_routeScope auf 'admin' setzen).
  • Starte den Entwicklungsserver nach Änderungen am Plugin neu, damit alle Änderungen geladen werden.

Probier das mal aus, und melde dich, wenn weitere Fragen auftauchen oder noch andere Dinge nicht funktionieren! :blush:

1 „Gefällt mir“