Blog: Latest Entries (15):


Shopware: RequestHttp und setParam()

Wenn man mit Events und Hooks für Controller arbeitet, wird man oft die Request-Parameter manipulieren wollen. Wenn man aber nun einen Parameter entfernen will, muss man die setParam()-Methode verstehen, weil man sonst leicht in ein kleines Problem läuft, dass mit der getParam()-Methode zusammen hängt.


$request->setParam('sPage', null);


wird nicht funktionieren und getParam() wird den ursprünglichen Wert zurückliefern. Aber warum? Weil das Request-Object ein internes Array mit den Params beinhaltet. setParam() setzt aber den Eintrag im Array aber nicht auf null, sondern entfernt diesen aus dem Array. Soweit ok. Aber nun kommt das Problem. Wenn getParam den Key im Array nicht findet, get es auch $_GET und $_POST zurück und findet dort natürlich noch den Original-Wert von sPage und liefert den zurück.

$_GET oder $_POST kann man natürlich auch ändern.. ABER das fällt bei der automatischen Prüfung im Shopware Store auf und das Plugin wird instant abgelehnt (auch wenn $_GET in einem Kommentar steht....).


$request->setParam('sPage', 0);


So funktioniert es und durch das seltsame Casting von PHP ist 'if($request->getParam('sPage'))' dann auch false.

bbcode-image

XML ohne BOM

Wenn man mit dem XML-Parser von jcabi-xml arbeitet und der direkt am Anfang der Datei behauptet, es würde nicht nach einer XML aussehen, kann es am UTF8-BOM liegen.

bbcode-image


Hier eine kleine und schnelle Lösung:


public static String removeBOM(String payload){
return payload.charAt(0) == '\uFEFF' ? payload.substring(1) : payload;
}



Die Kunst Exceptions und Fehlermeldungen zu lesen

Wenn eine Exception auftritt oder eine Fehlermeldung kommt (egal ob per Email oder aus einem Log) ist eine Sache ganz wichtig: Ruhe bewahren!

So. Da wir nun ruhig sind, gucken wir uns die Fehlermeldung oder Exception an. Wir überlegen nicht was wir als letztes geändert haben oder welcher Klick oder welche Eingabe alles ausgelöst hat. Das wäre verschwendete Zeit, weil genau diese Info steht ja in der Fehlermeldung/Exception.

Wir lesen einmal quer rüber. Kommt uns etwas Bekannt vor? Klassennamen? Module? SQL-Statements?

Nein? Schade.. aber auch nicht so schlimm.

Wir müssen uns nur 3 Fragen beantworten:

1) Welche Daten sollten hier durch gereicht werden?
2) Wo fing es an (Ursprung der Daten)?
3) Wo wollte man hin (Ziel der Daten)?

Bei einer Nullpointer-Exception z.B. geht es darum, erst einmal heraus zu bekommen, welche Daten verloren gegangen sind.
Dann gucken wir wo die herkommen sollten und ob von dort vielleicht schon NULL her kam.
Als letztes gucken wir wo es hin sollte und ob der mit dem NULL vielleicht sogar klar gekommen wäre und der Fehler bei einem zwischen Schritt liegt oder bei so einem schon auffiel.

Am Ende bleibt nur dann zu klären, wo in dieser Kette passierte das Falsche und dann muss geklärt werden warum eben jenes passierte.

Vermuten und Eingebungen sind Teil des letzten Schrittes und nie des ersten. Aber das Wichtigste ist immer noch die Fehlermeldung/Exception auch erst einmal in Ruhe zu lesen und in ihre Teile zu zerlegen, um alle Informationen atomar vorliegen zu haben.




Alles hat nicht geholfen? Dann ist das Logging scheiße und unvollständig.. bitte das Logging verbessern :-)

Review: MGP Slim Station 8

bbcode-image


Was ist das? Es soll wohl wie ein Sonic-Kopf oder -Flügel aussehen. Man kann damit Videospiele spielen in dem man es mit einem doch ausreichend langem Kabel an die Cinch-Anschlüsse eines TV-Gerätes anschließt.
Außerdem hat es einen eingebauten Laserpointer, der sich sehr gut als Katzenspielzeug eignet. Ideale Kombination.. wenn die Katzen ankommen und nerven, weil sie glauben man will mit ihnen spielen, obwohl man eigentlich nur eine Runde Zocken will.

Die Verpackung allein ist schon Wunder moderner Designer-Albträume. Wenn man sich die angesehen hat, weiß man noch weniger was einen eigentlich erwartet. Sonic, Mega-Drive, Mario, Spongebob, eine mir unbekannte Figur die mit Photoshop "erweitert" wurde, Angry Birds, Shawn das Schaf, usw ... und endlose sich unterschiedene Aufzählungen der 4 Funktionen.. wiese sollte ich mir so ein Ding ins Auto hängen?

bbcode-image


Man braucht nur eine AAA-Batterie und es kann losgehen. Das Batteriefach ist nicht verschraubt, was es wohl mal sein sollte, da die Bohrungen dafür vorhanden sind.

Ist es wirklich ein Mega-Drive-Clone dadrin? Würde ja zur Optik passen. 89in1 Spiele-Sammlung und es sieht eher nach einer Auswahl aus 3-4 brauchbaren Famicom Spielen aus und einer Ansammlung von Spielen, die man wohl eher gerne aus der Famicom Historie streichen würde.

bbcode-image


Die Grafik ist extrem matschig und unscharf. Ein NES liefert ein sehr viel besseres Bild. Oder aber es ist gewollt und man wollte nicht, dass man auf modernen Tv-Geräten die einzelnen Pixel sieht.. also eine Art Weichzeichner. Aber es ist auf den Pixel genau die NES Version von Contra/Probotector.. abgesehen von den geänderten Sprites.

bbcode-image


Die Steuerung ist dabei sogar noch erstaunlich brauchbar. Nicht gut und das Startmenü funktioniert mehr schlechter als schlecht, aber innerhalb der Spiele (anhand von Contra getestet) ausreichend gut, um damit spielen zu können.

Ich habe sonst nur noch Mario Bros (ohne das Super vorne) ausprobiert und diese RipOffs wie "Angry Bird" ohne s komplett ignoriert. Es ist kein Turtles dabei, was neben Contra echt ein Highlight gewesen wäre.

bbcode-image


Fazit:
Für 5 Euro ist es ein lustiges kleines Spielzeug.. für Katzen und für Menschen.

bbcode-image


Nachtrag: Super Mario Bros funktioniert wirklich gut und ist nicht merklich schlechter als auf dem NES oder Famicom

Shopware: Einkaufswelten Code-Element

Eine wichtige Erkenntnis das Code-Element in Shopware Einkaufswelten betreffend ist, dass es Smarty unterstützt. Wer also im HTML-Teil direkt JavaScript verwenden will muss etwas mit den geschweiften Klammern aufpassen. Das gilt besonders, wenn man einfach minimized Code-Snippets von einem Anbieter in die eigene Seite integrieren möchte.


function (x) {
alert(x);
}


oder


{literal}
function(x){alert(x);}
{/literal}


funktionieren.

Shopware: XML-OrderExport Plugin

Mein 2. Shopware Plugin (also.. das 2. das in den Community-Store soll..) ist jetzt so gut wie fertig. Es fehlen nur noch ein paar Test und Dokumentation.

bbcode-image


Das Plugin stellt einen Export der Orders bereit. Im Gegensatz zu den eingebauten Export hat man hier ein paar mehr Möglichkeiten das Aufgabeformat (so lange es XML ist) anzupassen und alles zu automatisieren.

Features:

- XML Formate: nativ, openTRANS 1.0 (eher experimentell), openTRANS 2.1
- automatischer Export direkt nach der Bestellung als Datei in ein lokales Verzeichnis
- automatischer Export als XML in einem JSON Container per Push (getestet mit einem Wildfly 11 und einem RestEasy Endpoint)
- Export bestimmter Orders in ein Verzeichnis per CLI
- Abfrage über die REST-API
- REST-API: Als XML in einem JSON-Container (Liste und einzelnd)
- REST-API: Als XML (einzelnd)
- XSLT-TRansformation, damit ist man im Ausgabeformat nicht eingeschränkt (egal ob mit Automatisch, CLI oder REST-API)
- Für die openTRANS-Formate gibt es verschiedene Einstellung für Buyer-Definition und die Party-Ids

bbcode-image


Es ist also ein Plugin was rein auf die Integration von Shopware in vorhandene Bestell-Prozesse mit ERP-Systemen wie SAP ausgelegt ist. Arbeit wirklich gut mit Java Application Servern wie Wirldfly zusammen und auch zum Debuggen ist es sehr praktisch die Bestellungen als XML zu dumpen.

bbcode-image


Ein relativ alter Fork des Plugin wird bei https://www.notebookswieneu.de genutzt, um die Bestellungen als openTRANS 1.0 an das SAP-System
zu übermitteln.

Diese Woche werden die letzten Dinge erledigt und dann wird es hoffentlich Anfang nächster Woche für den Store eingereicht.

Differenz in Tagen mit Java Time-API

Wir berechnen die Differenz in Tagen, für ein Datum, das als String kommt und in der Zukunft liegen muss.


int days = 0;

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
LocalDateTime dateFuture = LocalDateTime.parse(dateValue.trim(), formatter);
LocalDateTime now = LocalDateTime.now();

if(dateFuture.isAfter(now)){
days = Duration.between(now.toLocalDate().atStartOfDay(), dateFuture.toLocalDate().atStartOfDay()).toDays();
}


An sich ganz einfach und hat alles was man sich sonst selbst gebaut hat. Gerade in PHP erinnere ich mich noch sehr daran startOfDay implementiert zu haben.

Shopware: Meine Config für die DEV-VM

Da ich jetzt für die Entwicklung mit Shopware unter Windows eine Ubuntu-VM. Meine Config-Datei für die VM sieht momentan so aus:


<?php return array (
'db' =>
array (
'host' => 'localhost',
'port' => '3306',
'username' => 'root',
'password' => 'root',
'dbname' => 'shopware',
),
'front' => [
'showException' => true,
'throwExceptions' => true,
'noErrorHandler' => false,
],
'phpsettings' => [
'display_errors' => 1,
],
'mail' => [
'type' => 'file',
'path' => $this->DocPath().'mails'
],
);


Damit sollte so weit alles was für die Entwicklung wichtig ist angezeigt werden und auch die Emails sollten gespeichert, aber nicht versendet werden.

Universelles Ant build-script für Shopware-Plugins

Mit dieser build.xml kann man eine Zip-Datei bauen, die von Shopware für Plugins akzeptiert wird. Wenn man Phing und nicht Ant verwendet, muss man ${basedir} durch ${project.basedir} ersetzen.


<project name="build ShopwarePlugin-Zip" default="zip">
<target name="copy">
<basename property="pluginname" file="${basedir}"/>

<mkdir dir="./tmp/building/${pluginname}/${pluginname}"/>

<copy todir="./tmp/building/${pluginname}/${pluginname}" overwrite="true">
<fileset dir=".">
<exclude name="build.xml" />
<exclude name="${pluginname}.zip" />
<exclude name=".git/**" />
<exclude name=".svn/**" />
<exclude name="tmp/**" />
</fileset>
</copy>

<touch>
<fileset dir="./tmp/building/${pluginname}">
<include name="**" />
</fileset>
</touch>
</target>

<target name="zip" depends="copy">
<zip destfile="${pluginname}.zip" basedir="./tmp/building/${pluginname}"/>
<delete dir="./tmp"/>
</target>
</project>

Images und Media von einer URL in Shopware

Falls man mal wie in der REST-API ein Bild per URL importieren möchte. Das kann der Fall sein, wenn man sich einen eigenen Importer für ein Format wie BMECat oder so geschrieben hat.


/** @var $media Media */
$media = $this->getMediaResource()->internalCreateMediaByFileLink(
$imageData['imgUrl']
);

$image->setMain(1); //1 is primary image, 2 is the rest
$image->setMedia($media);
$image->setArticle($article);
$image->setPath($media->getName());
$image->setExtension($media->getExtension());
$image->setDescription($media->getDescription());

$image->setPosition($article->getImages()->getCount());


Ist an sich ganz einfach und funktioniert sehr gut.

Die URL kann vom Typ HTTP, HTTPS, FTP, FTPS und FILE sein.

Shopware: Alle Attr-Felder im Export

Ich hatte es schon fertig und dachte ich könnte es später auch mal im Community Store anbieten.. aber dann kam mir schon jemand zu vor und dann auch noch kosten los.

Also hier einfach mein Plugin als Code für jeden:


<?php
namespace HPrExportAttrExtend;

use Doctrine\DBAL\Connection;
use Shopware\Components\Plugin;

class HPrExportAttrExtend extends Plugin{

private $ignoreFields = [
'articleID',
'articledetailsID',
'attr1',
'attr2',
'attr3',
'attr4',
'attr5',
'attr6',
'attr7',
'attr8',
'attr9',
'attr10',
'attr11',
'attr12',
'attr13',
'attr14',
'attr15',
'attr16',
'attr17',
'attr18',
'attr19',
'attr20',
];

public static function getSubscribedEvents(){
return [
'sExport::sCreateSql::after' => 'extendExportArticleSql',
];
}

public function extendExportArticleSql(\Enlight_Hook_HookArgs $args){
$sql = $args->getReturn();

$fields = $this->getAllColumnNames();
if(count($fields) > 0){
$fields[] = 'at.attr20';

$sql = preg_replace("/at\.attr20/i", implode(', ', $fields), $sql);
}

$args->setReturn($sql);
}

private function getAllColumnNames(){
/** @var Connection $dbal */
$dbal = $this->container->get('dbal_connection');
$sql = 'SHOW columns FROM :tablename';
$stmt = $dbal->prepare($sql);
$stmt->execute(['tablename' => 's_articles_attributes']);
$rows = $stmt->fetchAll();
$fields = [];
foreach ($rows as $row){
$name = $row['field'];
if(!in_array($name, $this->ignoreFields)){
$fields[] = 'at.' . $name;
}
}
return $fields;
}
}

Shopware: In einer Ubuntu VM für Windows-Benutzer

Um unseren Shopware-Server aufzusetzen brauchen wir

- Apache (mit php7.0-mod)
- PHP7 (common,mysql,gd,xml,json,xsl,intl,gettext,mbstring,zip)
- MySQL Server
- OpenSSH Server
- PHPMyAdmin (wichtig hier Apache2 auszuwählen.. also mit Sternchen sichtbar nicht nur makiert)

Dann folgt die conf für den Apache und der Eintrag in die Host-Datei.

bbcode-image


Jetzt können wir Shopware downloaden und installieren

bbcode-image


Nun folgt die Netzwerk Konfiguration mit VirtualBox und die Anpassungen der hosts-Datei unter Windows.

bbcode-image


bbcode-image


bbcode-image


bbcode-image


Am Ende können wir mit dem Browser auf Shopware und mit WinSCP auf das System und das Shopware-Verzeichnis zugreifen.

bbcode-image


bbcode-image


So können wir unser lokalen Plugin-Verzeichnis mit dem auf dem Server synchron halten und Änderungen werden automatisch auf den Server gepusht.

Mein 1. Shopware Plugin verfügbar

Es ist soweit.. mein erstes Shopware Plugin ist im Community Store verfügbar.

bbcode-image


Kunden-Registrierung blockieren

Toll fand ich, dass man während des Freigabeprozesses wirklich mit Menschen zu tun hatte und einem auch wirklich von sich aus geholfen wurde.
Meine Erfahrungen beim Mozilla Store für Firefox OS waren da ganz anders. Da erhielt man eine Email mit sehr allgemeinen Punkten gegen was man verstoßen hätte und Hilfe was man noch müssen für die Freigabe gab es so gar nicht.
Deswegen werde ich mich dann jetzt daran machen weitere Plugins zu schreiben und zu veröffentlichen.

Erstmal Shopware mit Vagrant auf meiner Windows Workstation zum Laufen bekommen. Dann geht es sicher alles noch schneller und einfacher.

Oder ich richtige mir doch eine eigene Ubuntu VM ein... mal gucken.

Older posts: