Anpassung des Shopware 6 Rule Managers: Eine benutzerdefinierte Regel zum Überprüfen leerer Kunden-CustomFields

Einführung

Shopware 6 bietet mit dem Rulebuilder flexible Möglichkeiten, Abläufe und Berechtigungen zu steuern, aber manche Regeln sind mit dem Standard nicht abzubilden. Im konkreten Fall geht es darum, ein CustomField, das als Textfeld angelegt wurde daraufhin zu testen, ob es leer ist. Diese Möglichkeit wird von Shopware 6 einfach nicht in Betracht gezogen…
In diesem Blogpost beschreiben wir, wie eine benutzerdefinierte Regel erstellt werden kann, die prüft, ob ein kundenspezifisches Zusatzfeld leer ist. Diese Regel kann nützlich sein, um dynamische Preisstrategien, Versandregeln oder andere geschäftsrelevante Entscheidungen zu treffen, die auf kundenspezifischen Feldern basieren.

Voraussetzung ist das Shopware Plugin Grundgerüst. Das wird von Shopware selbst hier behandelt: https://developer.shopware.com/docs/guides/plugins/plugins/plugin-base-guide.html

Schritt 1: Regel-Klasse erstellen

Zuerst erstellen wir eine Regel-Klasse, die die notwendige Logik zur Überprüfung der benutzerdefinierten Felder enthält. Die Regel-Klasse wird im Verzeichnis <plugin root>/src/Core/Rule/ gespeichert und sieht wie folgt aus:

// <plugin root>/src/Core/Rule/CustomerCustomFieldEmptyRule.php
<?php declare(strict_types=1);

namespace YourPluginNamespace\Core\Rule;

use Shopware\Core\Framework\Rule\Rule;
use Shopware\Core\Framework\Rule\RuleScope;
use Symfony\Component\Validator\Constraints\Type;

class CustomerCustomFieldEmptyRule extends Rule
{
protected string $customFieldName;

public function __construct()
{
parent::__construct();
$this->customFieldName = '';
}

public function getName(): string
{
return 'customer_custom_field_empty';
}

public function match(RuleScope $scope): bool
{
if (!$scope instanceof \Shopware\Core\System\SalesChannel\SalesChannelContext) {
return false;
}

$customer = $scope->getCustomer();
if ($customer === null) {
return false;
}

$customFields = $customer->getCustomFields();
return empty($customFields[$this->customFieldName]);
}

public function getConstraints(): array
{
return [
'customFieldName' => [new Type('string')]
];
}
}

Diese Klasse definiert die Regel, die prüft, ob das angegebene benutzerdefinierte Feld eines Kunden leer ist.

Schritt 2: Vue-Komponente für das Admin-Interface

Als nächstes erstellen wir eine Vue-Komponente, die das benutzerdefinierte Feld im Admin-Interface zur Auswahl anbietet. Die Komponente wird im Verzeichnis <plugin root>/src/Resources/app/administration/src/component/sw-condition-customer-custom-field-empty/ gespeichert.

JavaScript-Datei

// <plugin root>/src/Resources/app/administration/src/component/sw-condition-customer-custom-field-empty/index.js
import template from './sw-condition-customer-custom-field-empty.html.twig';

const { Component, Mixin } = Shopware;
const { mapPropertyErrors } = Component.getComponentHelper();
const { Criteria } = Shopware.Data;

Component.extend('sw-condition-customer-custom-field-empty', 'sw-condition-base', {
template,

inject: ['repositoryFactory', 'feature'],

mixins: [
Mixin.getByName('sw-inline-snippet'),
],

data() {
return {
customFieldOptions: []
};
},

computed: {
customFieldCriteria() {
const criteria = new Criteria(1, 25);
criteria.addAssociation('customFieldSet');
criteria.addFilter(Criteria.equals('customFieldSet.relations.entityName', 'customer'));
criteria.addSorting(Criteria.sort('customFieldSet.name', 'ASC'));
return criteria;
},

customFieldName: {
get() {
this.ensureValueExist();
return this.condition.value.customFieldName;
},
set(customFieldName) {
this.ensureValueExist();
this.condition.value = { ...this.condition.value, customFieldName };
}
},

...mapPropertyErrors('condition', [
'value.customFieldName',
]),

currentError() {
return this.conditionValueCustomFieldNameError;
},
},

created() {
this.loadCustomFieldOptions();
},

methods: {
async loadCustomFieldOptions() {
try {
const customFieldRepository = this.repositoryFactory.create('custom_field');
const customFields = await customFieldRepository.search(this.customFieldCriteria);
this.customFieldOptions = customFields.map(field => ({
value: field.name,
label: field.config.label['en-GB'] || field.name
}));
} catch (error) {
console.error('Error loading custom field options:', error);
}
}
}
});

HTML-Template

{# <plugin root>/src/Resources/app/administration/src/component/sw-condition-customer-custom-field-empty/sw-condition-customer-custom-field-empty.html.twig #}
<template>
<sw-single-select v-model="customFieldName" :options="customFieldOptions" label="Select custom field" />
</template>

Diese Komponente lädt die benutzerdefinierten Felder und bietet sie im Admin-Interface zur Auswahl an.

Schritt 3: Registrierung der Regel

Damit Shopware die Regel erkennt, muss sie in der services.xml registriert werden:

<!-- <plugin root>/src/Resources/config/services.xml -->
<services>
<service id="YourPluginNamespace\Core\Rule\CustomerCustomFieldEmptyRule">
<tag name="shopware.rule.condition" />
</service>
</services>

Schritt 4: Cache leeren und Indizes aktualisieren

Nach Änderungen an den Plugin-Konfigurationen und Regel-Klassen ist es wichtig, den Cache zu leeren und die Indizes neu aufzubauen:

bin/console cache:clear
bin/console dal:refresh:index

Fehlerbehebung und Debugging

Um sicherzustellen, dass die Regel in der Storefront korrekt funktioniert, können Debugging-Logs hinzugefügt werden:

public function match(RuleScope $scope): bool
{
if (!$scope instanceof \Shopware\Core\System\SalesChannel\SalesChannelContext) {
return false;
}

$customer = $scope->getCustomer();
if ($customer === null) {
return false;
}

$customFields = $customer->getCustomFields();

// Debugging-Log
file_put_contents('/var/log/shopware_custom_field_rule.log', print_r([
'customFieldName' => $this->customFieldName,
'customFields' => $customFields,
'isEmpty' => empty($customFields[$this->customFieldName])
], true), FILE_APPEND);

return empty($customFields[$this->customFieldName]);
}

Fazit

Die Erstellung einer benutzerdefinierten Regel in Shopware 6 erfordert ein gutes Verständnis der Shopware-Architektur und der Plugin-Entwicklung. Durch die Schritte in diesem Blogpost haben wir eine benutzerdefinierte Regel erstellt, die prüft, ob ein kundenspezifisches Feld leer ist, und diese Regel erfolgreich in das Shopware-Backend integriert.

Tipps zum Testen und Vertiefung

  • Regel in verschiedenen Szenarien testen: Prüfe die Regel mit unterschiedlichen Kundenprofilen und benutzerdefinierten Feldern.
  • Logs überprüfen: Nutze die Debugging-Logs, um sicherzustellen, dass die Regel wie erwartet funktioniert.
  • Weiterführende Dokumentation: Nutze die Shopware-Dokumentation und Community-Ressourcen, um tiefer in die Themen Plugin-Entwicklung und Rule Manager einzutauchen.

Mit diesen Schritten und Tipps solltest du in der Lage sein, benutzerdefinierte Regeln in Shopware 6 zu erstellen und anzupassen, um die Funktionalität deines Shops zu erweitern und zu verbessern.

Projekt: Spielereien mit electron und craftyjs

Javascript ist die Script-Sprache hinter fast allen Webanwendungen und inzwischen durch nodejs auch als Backend-Sprache fest etabliert. Electron nutzt dieses Tool und ermöglicht es, auf nodejs und chromium basierend mit Javascript Plattform unabhängige Desktop-Anwendungen zu bauen (alle Plattformen auf denen node und chromium laufen).
Als Grundgerüst nutzt eine Electron Anwendung HTML und CSS zur Darstellung und Javascript für die Programmlogik – also handelt es sich im einfachsten Fall um nichts anderes als eine Webanwendung, gekapselt in eine Desktopanwendung.

Prominentes Beispiel für eine electron Anwendung ist der Editor Atom von gitub, für den das Framework Electron ursprünglich geschaffen wurde. Inzwischen existieren zahlreiche Anwendungen, Beispiele finden sich hier

In diesem kleinen Tutorial geht es darum, ein einfaches Programm zu erstellen, das als „Sandkasten“ für das Javascript–Spiele–Framework craftyjs dient.

Craftyjs ist eine kleine Javascript-Bibliothek, die grundlegende Mechaniken für die Spieleprogrammierung bereitstellt. Die Dokumentation ist überschaubar, ebenso wie die API, allerdings in manchen Fällen kommt man um Probieren und die Websuche nicht herum, wenn man eine bestimmte Funktion sucht.

Electron installieren

Um electron auf die Festplatte zu bekommen muss nodejs mit npm installiert sein. Unter Ubuntu installiert man die Programme im Terminal über folgenden Befehl:

sudo apt install nodejs npm

Damit ist alles bereit um Electron zu direkt installieren. Da wir aber nicht alles von vorne bauen müssen, nutzen wir die von der Projektseite selbst bereitgestellte Quick-start Vorlage. Diese lässt sich direkt von Github herunterladen oder besser via git auf die eigene Festplatte clonen.

Sofern git noch nicht installiert ist, holen wir das über diesen Befehl nach:

sudo apt install git

Nun kann die Quick-start Vorlage in den Ordner unserer Wahl installiert werden, bei mir unter ~/dev/electron/ über die Anweisung:

# Das Quick-Start Repository klonen 
$ git clone https://github.com/electron/electron-quick-start
# Das Repository öffnen
$ cd electron-quick-start
# Die Abhängigkeiten installieren und ausführen
# hier wird electron installiert und auch gleich ausgeführt
$ npm install && npm start

Die originalen Anweisungen finden Sie direkt auf der Electron Startseite.

Das erste Ausführen zeigt in etwa dieses Bild:

Damit läuft unser erstes einfaches Electron Programm.

Hinter dem Menüpunkt „View“ verstecken sich wichtige Werkzeuge: „Refresh“ – damit wird die Anwendung neu geladen und „Toggle Developer Tools“ – darüber erreichen wir die Entwickler Werkzeuge, die in Chromium über F12 zu erreichen sind.