Hallo, ich muss in einem Plugin, vor dem Abschluss der Bestellung und dementsprechend auch vor dem Speichern eine Prüfung einbauen, um gegebenenfalls einen Fehler zu werfen und die Bestellung nicht auszulösen.
Meine erste Idee war den Cart oder OrderService zu dekorieren, leider scheint das nicht zu klappen.
namespace MNS\Service;
class OrderServiceDecorator
{
private $decoratedService;
public function __construct($service)
{
$this->decoratedService = $service;
}
public function createOrder($data, $context)
{
}
}
gibt den Fehler: Circular reference detected for service „MNS\Service\OrderServiceDecorator“, path: „MNS\Service\OrderServiceDecorator -> MNS\Service\OrderServiceDecorator“. Gleiches passiert bei dem CartService. Ich kann hier im Constructor auch kein Interface angeben, da beide kein Interface besitzen.
Geht das prinzipiell, ist das angedacht von Shopware6, wenn ja was mache ich falsch?
Meine andere Idee war nicht den Service zu dekorieren sondern die ValidationFactory zu erweitern, Shopware\Core\Checkout\Order\Validation\OrderValidationFactory. Hier weiß ich allerdings gar nicht wie ich ran komme, gibt es hierfür möglichkeiten diese zu erweitern?
bringt mich schonmal an einen anderen Fehler Argument 5 passed to Shopware\Storefront\Controller\CheckoutController::__construct() must be an instance of Shopware\Core\Checkout\Order\SalesChannel\OrderService …
Auch Logisch, da ich kein Interface habe, kann ich das natürlich nicht mit übergeben.
Deshalb extende ich OrderService und rufe dann die createOrder über den decorated Service auf, das sollte evtl. funktionieren.
Einfacher und auch Eleganter wären hier natürlich Interfaces oder das Erweitern der Validierungsregeln.
@Shyim Danke das hat viele Probleme gelöst - konnte ihn an mehreren Stellen schon gut einsetzen.
Der CartValidator funktioniert bei allen Routes im Checkout, bis auf ‘frontend.checkout.finish.order’, wenn ich in dieser Route eine exception werfe, bekomme ich eine Symfony Fehlermeldung “The cart is invalid, got 1 error(s).”, werde aber nicht wieder zurück an auf die confirm seite geworfen bzw. kann es von dort aus ja auch nicht provozieren.
Ich habe versucht mit dem “BuildValidationEvent” eine Fehlermeldung zu provozieren, irgendwie will das aber alles nicht richtig, nichtmal ein “die()” greift hier.
class ValidationSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
BuildValidationEvent::class => 'cartValidation'
];
}
public function cartValidation(BuildValidationEvent $event)
{
die('validation event');
}
}
Ich muss nach der “confirm”-Seite prüfen ob alle Daten richtig sind und notfalls den User zurück zur “confirm”-Seite schicken, um ihm eine Fehlermeldung auszugeben.
@Shyim Danke das hat viele Probleme gelöst - konnte ihn an mehreren Stellen schon gut einsetzen.
Der CartValidator funktioniert bei allen Routes im Checkout, bis auf ‚frontend.checkout.finish.order‘, wenn ich in dieser Route eine exception werfe, bekomme ich eine Symfony Fehlermeldung „The cart is invalid, got 1 error(s).“, werde aber nicht wieder zurück an auf die confirm seite geworfen bzw. kann es von dort aus ja auch nicht provozieren.
Ich habe versucht mit dem „BuildValidationEvent“ eine Fehlermeldung zu provozieren, irgendwie will das aber alles nicht richtig, nichtmal ein „die()“ greift hier.
class ValidationSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
BuildValidationEvent::class => ‚cartValidation‘
];
}
public function cartValidation(BuildValidationEvent $event)
{
die(‚validation event‘);
}
}
Ich muss nach der „confirm“-Seite prüfen ob alle Daten richtig sind und notfalls den User zurück zur „confirm“-Seite schicken, um ihm eine Fehlermeldung auszugeben.
Grossartige Fragen. Wir stehen gerade vor dem genau gleichen Problem. Dieser Thread war sehr hilfreich.
Gibt es bereits neue Erkenntnisse, wie die Bestellung nach „confirm“ überprüft/abgelehnt werden kann?
Ich bin vorsichtig geworden mit dem Cartvalidator, die Prüfung findet auch statt wenn du zu confirm gehst, wirft dort aber nur einen symfony Fehler, ohne das du eingreifen kannst.
Ich hänge mich an das
framework.validation.order.create Event, dort kriegst du ein Buildvalidationevent. Mit dem du die Validierung der cart übernehmen kannst.
$data = $this->requestStack->getCurrentRequest()->request;
// eigener validator, andere können im Core gefunden werden
$definition = new DataValidationDefinition('XXX');
$definition->add('name des validator',
new ValidatorClass()
);
$violations = $this->validator->getViolations($data->all(), $definition);
if (!$violations->count()) {
return;
}
// wirf diese Exception und du kommst zurück zur confirm seite
throw new ConstraintViolationException($violations, $data->all());
Sorry für evtl. Formatierungsfehler, bin am Smartphone unterwegs.
kannst du hier nochmal etwas mehr Kontext geben? Ich habe genau das gleiche Problem wie du hier, weiß aber nicht was du mit “an das framework.validation.order.create Event hängen” meinst.
Ich möchte hierzu kurz eine Info geben.
In dem BuildValidationEvent ist der Name „dynamisch“.
Dieser wird aus einem Prefix und dem Namen der in dem Event enthaltenen DataValidationDefinition gebildet, sodass z.b. folgender Name am ende herauskommt:
framework.validation.cms_extensions.form.create
Da muss man also in der getSubscribedEvents Methode nicht den Klassennamen als Key eintragen sondern genau diesen dynamischen Namen.
Dieser muss dann entsprechend im Code erst herausgefunden werden.
Ich denke das wurde so gemacht, damit man nicht auf alle BuildValidationEvents subscribed, da dieses Event doch an einigen Stellen genutzt wird. Stattdessen will man ja meist nur eine bestimmte Validation verändern.