Blog: Latest Entries (15):


Shopware 6: Lesbares Javascript

Wenn man in der Storefront an einem eignem JavaScript-Plugin arbeitet ist es beim Debuggen, oft nervig, dass der JavaScript Code nicht direkt lesbar ist. Oft weiß man beim eigenen Code direkt was los ist, aber gerade wenn 3rd Party Plugins auch mit rein spielen, kommt man nicht drum herum sich Exceptions mit lesbaren Stacktrace anzeigen zu lassen.

Das ist zum Glück extrem einfach:

* Port 9998 aus dem Docker-Container durchleiten
* Dem SalesChannel in dem man entwickelt die Domain "localhost" zu ordnen
* das Script bin/watch-storefront.sh starten

Nun kann man localhost:9998 im Browser aufrufen. Der JavaScript Code ist lesbar und Änderungen werden sofort übernommen ohne dass man die Storefront neu bauen muss.

Shopware 6: Produkt-Analyse per SQL

Einmal schnell gucken, wie viele und welche Art von Produkten über welchen SalesChannel und URL zu kaufen sind.


SELECT x.url, 'single' type, count(x.id)
FROM (
select d.url, p.id, p.parent_id, count(p2.id) children from sales_channel_domain d
join sales_channel sc on d.sales_channel_id = sc.id
join product_visibility pv on pv.sales_channel_id = sc.id
join product p on p.id = pv.product_id
left outer join product p2 on p.id = p2.parent_id
where sc.active = 1
group by d.url, p.id, p.parent_id
)x
WHERE x.parent_id is null and x.children < 1
group by x.url

union all

SELECT x.url, 'main' type, count(x.id)
FROM (
select d.url, p.id, p.parent_id, count(p2.id) children from sales_channel_domain d
join sales_channel sc on d.sales_channel_id = sc.id
join product_visibility pv on pv.sales_channel_id = sc.id
join product p on p.id = pv.product_id
left outer join product p2 on p.id = p2.parent_id
where sc.active = 1
group by d.url, p.id, p.parent_id
)x
WHERE x.parent_id is null and x.children > 0
group by x.url

union all

SELECT x.url, 'variant' type, count(x.id)
FROM (
select d.url, p2.id, p2.parent_id, 0 children from sales_channel_domain d
join sales_channel sc on d.sales_channel_id = sc.id
join product_visibility pv on pv.sales_channel_id = sc.id
join product p on p.id = pv.product_id
left outer join product p2 on p.id = p2.parent_id
where sc.active = 1
)x
group by x.url


Shopware 6: Id und die DBAL-Connection

Gerade in Migrations kommt man manchmal in darum herum mit den UUIDs arbeiten zu müssen. Da es binary-Daten sind muss man etwas mit den anstellen, um die aus Shopware 6 bekannte Darstellung zu erreichen und auch um diese wieder die in Datenbank zu bekommen.

Lesen der Id:
Um die aus Shopware 6 gewohnte Darstellung zu bekommen muss man in MySQL die HEX-Function verwenden. Zusätzlich muss der String noch in Kleinbuchstaben umgewandelt werden.

Schreiben der Id:
Zuerst wieder alles in Großbuchstaben umwandelnt. Dann muss mit der MySQL-Function UNHEX der Hex-String wieder in binary Data umgewandelt werden.

Es bleibt zwar etwas umständlich, aber ist damit durch aus handhabbar. Da es in dem Sinne kein Autoincrement gibt für die UUIDs hilft dann dort Uuid::randomHex().


Shopware 6: Was schon alles damit entwickelt wurde

Ich arbeite nun doch schon einige Zeit mit Shopware 6. Während ich am Anfang vielen Konzepten etwas kritisch gegenüberstand, bin ich nun doch sehr von fast allen Dingen überzeugt. Ich habe viele verschiedene Dinge schon mit Shopware 6 realisiert und einiges wäre in Shopware 5 nicht so einfach gewesen.
Gerade Vue.js in der Administration ohne irgendwelche zusätzlichen Lizenzen nutzen zu können ist super. Ich mochte immer Vue + Bootstrap und Symfony. Also am Ende fühle ich mich so was von extrem in meinen Vorlieben bestätigt... wenn auch Shopware diese Kombinationen nutzt muss ich ja schon immer richtig gelegen haben :-)

Varianten sind immer noch viel zu kompliziert. Daten in das Model für Emails rein zubekommen ist wirklich viel zu umständlich. N:M Relation in DAL ist umständlich bzw wie früher mit puren SQL. Entweder alles vorher löschen oder sich merken was genutzt wird und alles was nicht dazugehört löschen. Aber am Ende kommt man ja gut damit klar... ist eben wie mit JDBC oder PDO direkt zu arbeiten und dass habe ich lange genug gemacht.

So.. aber was kann man alles mit Shopware 6 so alles bauen? Ich habe bis jetzt nur für Kunden direkt entwickelt und falls jemand etwas hier von gerne hätte, geht das leider nur über Anfrage und dann wird ein Angebot erstellt.

1. Adressänderungen verhindern
Wie schon bei Shopware 5 war es nötig, weil SAP sonst überfordert ist.

bbcode-image


2. Register-Form erweitern
Das zu Erweitern war am Ende sehr viel einfacher als gedacht und ich nutzt einfach das Data-Mapping Event für den Customer. Der richtige Weg? Für mich funktioniert er gut.

bbcode-image


3. Blog Einträge
Das kostenlose Blog-Plugin ist schon echt super. Es fehlt nur ein Flag um Posts von er Suche auszuschließen, Typen, Rechte über Rules und Datei-Anhänge. Ja.. ich weiß.. ich könnte mich da beteiligen und alles einbauen.. sollte ich wirklich machen. Aber bis jetzt war nur Zeit das Plugin zu erweitern um Rezepte aus einem Panipro-System zu importieren.

bbcode-image


Typen sind natürlich dynamisch und es werden nur Typen auf der linken Seite angezeigt, die auch gefunden wurden.

4. Bonuspunkte und passende Produkte
Produkte die man nur oder auch gegen Bonuspunkte kaufen kann. Das war etwas komplexer und man musste über Collector und Processor des Carts eingreifen. Heute würde ich wohl einiges ein wenig anders machen, aber nicht viel und auch nur minimale Änderungen.

bbcode-image


5. Konfigurator Style #1
So kann man sich z.B. Geschenkkörbe oder PCs/Notebooks konfigurieren. In der Administration kann man sich ein Config-Preset anlegen und es verschiedenen Products zuordnen.

bbcode-image


6. Konfigurator Style #2
Ein Produkt das z.B. Hackfleisch beinhaltet so konfigurieren in welchen Formen man das Hack gerne geliefert bekommen würde. Wurde als Teil von Punkt 7 entwickelt.

bbcode-image


7. Paket verkauf
Erst alle Pakete verkaufen und dann erst das Tier schlachten. Spart Lagerkosten und andere Aufwände. Hier habe ich gelernt warum Varianten noch immer umständlich sind und CustomFields zu syncen zwischen Varianten schlechter ist als eine eigene Entity dafür zu erstellen. Aber die Anforderungen waren zuerst so das CustomFields die einfacher Lösung waren.

In Aktion:
https://www.mein-elbtaler-shop.de/Bio-Rind-Demeter/ME-1130.1

Wem also etwas hier von gefallen hat, kann sich gerne melden. Wir freuen uns immer über Anfragen.

Shopware 6: Hauptvariante ändern

Etwas was bei Shopware 6 so komplett fehlt und wo ich schon mehrmals gehört habe, dass es Kunden/Benutzern Probleme macht, ist die Hauptvariante bei Shopware 6. Die Hauptvariante ist immer die Variante, die im Dialog beim Erzeugen der Varianten zuerst gewählt wurde. Es gibt danach keine Möglichkeit mehr es zu ändern.

An sich ist die Hauptvariante aber auch nur ein FK am Product. Man kann dort einfach eine andere Variante eintragen und schon hat man seine neue Hauptvariante. Also alles auf DB-Ebene sehr einfach.

Auch das in die Administration einbauen war dann relativ einfach. Man brauchte nur zusätzlich ein Repository und eine Criteria für Varianten (WHERE parent_id = ... ). Die Id kann man direkt per v-model setzen am Product.

https://gitlab.com/hpries/HPrMainVariant

Dort habe ich meine Implementierung einmal hinterlegt. Darf gerne verwendet werden, wenn jemand oder ein Kunde auch dieses Problem hat.

bbcode-image

Shopware 6: Non-Stackable Cart-Items

Gerade wenn man ein Produkt konfigurieren kann, ist es wichtig, dass CartItems nicht einfach aufaddiert werden, sondern jede Konfiguration als eigenes CartItem im Warenkorb abgelegt wird. Das CartItem von Shopware 6 hat auch ein stackable-Flag. Nun könnte man glauben, wenn man dieses auf false setzt, dass nicht das vorhandene CartItem geändert sondern ein neues angelegt wird, wenn erkannt wird, dass das vorhandene nicht stackable ist. Falsch! Man bekommt eine Exception.

Die Lösung ist zum Glück sehr einfach. Man muss selbst die Id des CartItems ändern um ein neues anzulegen. Also wenn man setStackable(false) setzt auch gleich die Id neu setzen. Oder man baut sich ein allgemeines Plugin, dass es macht.

BeforeLineItemAddedEvent:

if (!$event->getLineItem()->isStackable()) {
$event->getLineItem()->setId(Uuid::randomHex());
}

Systemd und Tomcat 9: ProcessBuilder Exceptions

Manchmal möchte man aus einem Tomcat heraus Processe und Programme aufrufen. Wie bei SQL-Injections muss man das natürlich stark absichern, aber das Konvertieren von Bildern und Video geschieht meistens auf diese Art und Weise.

Was aber wenn der Tomcat per ProcessBuilder nichts mehr aufrufen kann außerhalb seines Verzeichnisses, obwohl er alle Recht haben sollte? Wenn es ein System mit systemd ist (z.B. ein Ubuntu) ist, kann es einfach eine Security-Einstellung sein, die den Aufruf verhindert.

Hier muss man die Start-Config für den Service anpassen. "ProtectSystem=false" ist zum Prüfen der Lösung ganz gut, sollte aber später durch eine genauere Anpassung der ReadWritePaths geöst werden.

https://stackoverflow.com/questions/64038094/disable-sandbox-tomcat-9-ubuntu-20-04

Shopware 6: Placeholder Icon ersetzen

Bei Shopware 6 ist es etwas anders das Platzhalter-Bild für Produkte ohne Bilder zu ersetzen. An sich ist es ganz einfach, wenn man weiß wie es geht. Auch Anleitungen aus dem Internet von 2019 sind nicht mehr aktuell, denn es geht nun noch einfacher!

DAs Bild ist ein SVG-Icon mit dem Namen 'placeholder'. Man kann mit der Suche schnell herausfinden, wo es überall verwendet wird. Nun muss man nur ein eigenes Icon in per Plugin einbringen. Das ist auch an sich sehr einfach. Man legt einen Pfad in seinem Plugin an "src/Resources/app/storefront/dist/assets/icon/myiconpack/" und kopiert dort seine SVG-Datei rein. Die SVG kann auch gerne als placeholder.svg bennant sein. Nun muss man den Twig-Tag "sw_icon" noch um zwei Werte ergänzen. "pack" ist der oben im Pfad genutzte Icon-Pack Name und der "namesapce" ist einfach der Name des Plugins in dem man sich gerade befindet.


{% sw_icon 'placeholder' style {
'size': 'fluid',
'pack': 'myiconpack',
'namespace': 'MyPlugin'
} %}


Nun einmal die Storefront neu bauen und schon sollte das eigene Icon genutzt werden, da wo man die Shopware-Templates entsprechend extended hat.

bbcode-image

Shopware 5: Detail Meta-Description ändern

Einfach mal die Meta-Description mit einem Prefix versehen, um kleinere SEO-Probleme zu beheben. Klingt einfach und führt schnell zur Verzweiflung. frontend/detail/header.tpl angepasst und es funktioniert nicht. Keywords ändern ist kein Problem nur die Meta-Description des Artikels will sich nicht ändern.

Lösung
Wie man schnell vermutet wird die eigene Änderung überschrieben. Der Schuldige ist das SEO-Plugin und da muss man die index.tpl anpassen. Die Änderung kann z.B. so aussehen:


{block name='frontend_index_header_meta_description'}
{if $Controller=='detail'}
EAN:{$sArticle.ean} - {$SeoMetaDescription|truncate:150:"...":true}
{elseif $SeoMetaDescription}
{$SeoMetaDescription|truncate:150:"...":true}
{else}
{$smarty.block.parent}
{/if}
{/block}


Shopware 5: Text in Bannern

Wenn man Landingpages oder Kategorien als Banner in einem Bannerslider verlinkt würde man meistens gerne auch einen Text darin unterbringen. Nur ein Bild trifft oft nicht genau den Begriff den man darstellen möchte, da in einem Shop alles ja doch sehr nahe am gleichen Thema ist.

Text in Bannern bringt aber einige Probleme mit sich:
1) Der Text skaliert nicht mit und wird schnell unschön abgeschnitten
2) Der Text läßt sich nicht einfach und schnell ändern
3) Das Styling des Textes ist nicht mehr änderbar
4) Man braucht oft einen Grafiker der den Text in das Bild einbaut

Genau diese Problem hat gerade Vape-Buddys und brauchte eine einfache, schnelle und kosten günstige Lösung. Diese Lösung besteht darin den Title des Banners als Text-Overlay über das Bilds zu legen. Hier wird auch alles über % positioniert
und passt sich dem Viewport an. Sollte der Text zu groß sein greift CSS ellipsis und schneidet den Text schön ab.

bbcode-image


bbcode-image


widgets/emotion/components/component_banner_slider.tpl

{extends file="parent:widgets/emotion/components/component_banner_slider.tpl"}

{block name="frontend_widgets_banner_slider_link"}
<div class="banner--slider-title">
{$banner.title|escape}
</div>
{$smarty.block.parent}
{/block}


Das CSS dazu

.banner--slider-title {
position: relative;
font-size: 4rem;
color: white;
width: 100%;
height: 80%;
padding-top: 6%;
padding-left: 8%;
z-index: 100;
text-align: left;
text-shadow: 0 0 3px #000000;

white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

Nuxeo mit Keycloak-Integration

An sich ist es garnicht sooo schwer Nuxeo mit einem Keycloak zu verbinden und dann die Benutzerverwaltung allein über das Keycloak abzuwinkeln. Leider ist die Dokumentation dazu sehr dürftig und zu großen Teilen einfach veraltet und lückenhaft. Hier wird einmal in kurzer Form erklärt wie man das mit einer aktuellen Version von Nuxeo 10.10 bewerkstelligen kann. Man sollte das 10.10 Repository von Github einmal per Maven komplett selbst gebaut haben. Wir hatten die HF53-Version und ein Grundsetup als Docker-Image ist unter annonyme/nuxeo:HF53 zu finden. Besser ist aber wenn man sich das vollständig selbst baut. Das Docker-Repository hilft beim Bauen.

Die Erweiterung für Nuxeo

Das Repository für die Nuxeo Platform Login Keycloak Erweiterung ist Teil des Nuxeo Mono-Repository und kann direkt mitgebaut werden. Die Anleitung dazu ist vollkommen veraltet, aber ich nehme sie hier als Basis. Man braucht um dieses benutzen zu können:

* Den Keycloak Tomcat-8 Adapter in der Version 4.6.0
* Den Nuxeo UserMapper Service (selbe VErsion wie bei Nuxeo und der Nuxeo-Keycloak Erweiterung nutzen! z.B. HF53)

Die Dateien aus der Zip der Adapter-Dist, die JAR vom Nuxeo Platform Login Keycloak sowie die JAR des UserMapper Services müssen alle in das selbe plugin/ Verzeichnis kopiert werden wie in der Anleitung erklärt wird. Das config/ Verzeichnis wie im Repository einfach auch rüber kopieren. Der Inhalt der JSON-Datei kann direkt aus dem Nuxeo kopiert werden und
ist die Config-Datei für den Keycloak Tomcat-Adapter und hat also an sich nichts mit Nuxeo zu tun. Dem entsprechend ist die Dokumentation zu der Datei auch um Welten besser als bei den Nuxeo Komponenten.
In der Anleitung wird alles in ein Template-Verzeichnis kopiert. Ein Template ist ein Profile für verschiedene Nuxeo-Konfigurationen und es können mehrere davon gleichzeitig verwendet werden. Den Docker-Container muss man dann also mit NUXEO_TEMPLATES: docker,keycloak starten.

Das war es dan nauch. Beim Login in Nuxeo einfach einen Account aus dem Keycloak verwenden und der Benutzer sie wie die im Keycloak zugeordneten Rollen/Gruppen werden ins Nuxeo übernommen.

Wenn man nochmal mit dem Administrator-Konto ins Nuxeo will und dieser noch nicht im Keycloak angelegt ist, muss man nur direkt /nuxeo/login.jsp aufrufen und bekommt die Nuxeo-Anmeldung ohne auf die Realm-Anmeldeseite des Keycloak weiter geleitet zu werden.

Es sind keine weiteren Konfigurationen an Nuxeo nötig. Wenn man sich ein Docker-Image baut muss also nur die keycloak.json aus dem config-Verzeichnis des Templates ersetzt werden können.

--

Mit viel Unterstützung von Interspark.

PHP: mpdf vs dompdf

CSS war ja ansich schon immer ganz gut um auch damit Druckdokumente zu erstellen. Vor vielen Jahren mit FlyingSaucer und Java und heute auch mit PHP. Nun kam die Frage auf ob mpdf oder doch eher dompdf dafür geeignet wäre. Kurz.. an sich gibt es da kaum einen wirklichen Unterschied. Beide sollen ältere Bootstrap-Versionen unterstürzen. Bootstrap 3.3.x hat um 2015 auch schon für alles mögliche gereicht und man konnte damit genau so gut ansehnliche Ergebnisse erzielen wie mit 4.0 oder 5.0. Wenn man mit JavaScript unter React oder Vue unterwegs ist, gibt es natürlich viele Vorteile mit den neuen Versionen und intern hat sich viel getan, aber für rein statische Inhalte ist es für den Benutzer von Bootstrap an sich egal, ob er eine alte oder neue Version verwendet. Das Konzept ist gleich geblieben über die Jahre.

Zwischen mpdf und dompdf habe ich nur einen wirklich Unterschied ausmachen können der relavant sein könnte. dompdf kann mit <thead> und <tbody> bei Seitenumbrüchen innerhalb von Tables auf der neuen Seite den <thead> wiederholen. Gerade bei sehr großen Reports in Tabellenform ist das sehr wichtig und schon zu FlyingSaucer Zeiten eine der wichtigsten Funktionen, die alle brauchten.

Older posts:

Möchtest Du AdSense-Werbung erlauben und mir damit helfen die laufenden Kosten des Blogs tragen zu können?