Admin Session mocken mit EcomDev_PHPUnit in Magento Enterprise

In Integrationstests mit EcomDev_PHPUnit_Test_Case_Controller gibt es eine praktische Helper-Methode adminSession(), um Requests im Magento Backend zu testen. Mit Magento Enterprise kann es da allerdings zu dieser Fehlermeldung kommen:

Exception: Warning: in_array() expects parameter 2 to be array, null given in /home/vagrant/mwdental/www/app/code/core/Enterprise/AdminGws/Model/Role.php on line 83

So gesehen in Magento EE 1.14.1.

Ohne Details zu den Enterprise-Modulen preiszugeben, hier eine Lösung in der der schuldige Observer gemockt wird:

$adminObserverMock = $this->getModelMock(
    'enterprise_admingws/observer',
    array('adminControllerPredispatch'));
$adminObserverMock->expects($this->any())
    ->method('adminControllerPredispatch')
    ->will($this->returnSelf());
$this->replaceByMock('singleton', 'enterprise_admingws/observer',
    $adminObserverMock);
$this->adminSession();

Magento: Block-Inhalt verschwindet nach core_block_to_html_after Event

Vorsicht mit Mage_Core_Block_Abstract::toHtml() innerhalb eines Observers für core_block_to_html_after! Ich habe die Methode genutzt, um HTML aus einem Block in einen existierenden Block zu injizieren, mit dem Ergebnis dass alles außer diesem neuen Block von der Ausgabe entfernt wurde.

Beim Debugging im Core habe ich die Ursache darin gefunden, wie das Event dispatched wird:

        /**
         * Use single transport object instance for all blocks
         */
        if (self::$_transportObject === null) {
            self::$_transportObject = new Varien_Object;
        }
        self::$_transportObject->setHtml($html);
        Mage::dispatchEvent('core_block_abstract_to_html_after',
            array('block' => $this, 'transport' => self::$_transportObject));
        $html = self::$_transportObject->getHtml();

Wie man sieht, ist das Transport-Objekt, das genutzt wird um Änderungen am HTML in Observern zu ermöglichen, eine Klassenvariable von Mage_Core_Block_Abstract, und verhält sich ähnlich wie ein Singleton. Ich kann mir keinen guten Grund dafür denken aber es riecht verdächtig nach premature optimization.

Was nun passiert ist, dass während das Event verarbeitet wird, der neue Block seine eigene Ausgabe in seinem eigenen toHtml() Aufruf dem selben Transport-Objekt zuweist und die ursprüngliche Ausgabe verloren geht, wenn man sie nicht vorher gesichert hat.

Die Lösung für mein konkretes Problem war, den Block an anderer Stelle zu erstellen und vorzurendern, aber wenn das nicht getan wird, muss die Ausgabe direkt zu Beginn im Observer in eine neue Variable kopiert werden:

$html = $observer->getTransport()->getHtml(); // should be the first statement

// now you can do what you want, create other blocks, modifiy $html ...

$observer->getTransport()->setHtml($html); // should be the last statement

Retrospektive: Das Blog 2014

Ein privat und geschäftlich erfolgreiches Jahr ist herum und das neue fängt erst langsam an. Zeit, darauf zurück zu blicken wie das Blog seit dem Relaunch meiner Seite letzten Februar läuft und neue Ziele für 2015 zu stecken.

Angesagte Themen

Einige Themen stachen auf die ein oder andere Art hervor:

Unit Testing

Mein Allzeit-Top-Artikel von 2011 [PHP] Mocking Built-in Functions Like time() In Unit Tests war 2014 immer noch der zweitmeist besuchte Artikel und ich freue mich, dass das darin vorgestellte Konzept einige neue Aufmerksamkeit erfahren hat:

  • Matthew Weier O’Phinney (@mwop) nutze es, um Code zu testen, der Ausgaben erzeugt. Siehe PHP: header() mocken, um Controller zu Unit-testen
  • Markus Malkusch hat inspiriert durch meinen Artikel eine Bibliothek zum mocken von Funktionen entwickelt, php-mock. Dabei fand und dokumentierte er auch einen weiteren Sonderfall, bei dem es nicht funktioniert (aktuell ein offener PHP Bug).

PHP 5.3 Death March

Der kontroverseste, meist diskutierte und meist geklickte Artikel 2014 war meine Ankündigung, PHP 5.3 Support fallenzulassen wo immer möglich, um Adaption von aktuellen PHP Versionen voranzutreiben (5.3 hat August 2014 sein end-of-life erreicht und bekommt seitdem keine Sicherheits-Fixes mehr).

Ich fühle mich in guter Gesellschaft weil kurz darauf Anthony Ferrara (@ircmaxell) die selbe Diskussion in größerem Umfang auf Twitter und anderswo mit seinen Artikeln zu PHP Versionen anstieß:

  1. On PHP Version Requirements
  2. Being A Responsible Developer
  3. PHP Install Statistics

Vagrant

puphpet-vagrant-puppet-magentoIch habe eine Serie über Vagrant geschrieben, speziell um es Magento-Entwicklern nahezubringen, veröffentlicht auf integer-net.de. Eine englische Zusammenfassung gab es im Webguys Adventskalender: Türchen 19: Kickstart your Magento Dev System with Vagrant. Zwei der vier Teaser in diesem Blog haben es in die Top Ten 2014 geschafft (siehe unten).
Continue reading “Retrospektive: Das Blog 2014”

Magento-Entwicklung mit Vagrant – Teil 4: Puppet – Provisioning für Fortgeschrittene

Wie in den vorigen Teilen der Serie angedeutet, ist der nächste Schritt, ein Provisionierungs-Tool zu nutzen, also ein Tool zur Automatisierung von Infrastruktur, mit dem z.B. Entwicklungs-, Test- und Produktiv-Umgebungen synchron konfiguriert werden können. Dieses ersetzt weitestgehend die Shell-Skripte zur Einrichtung der VM durch eine deklarative Sprache zur Definition des gewünschten Zustands der Systeme. Dieser Unterschied ist entscheidend: wir definieren nicht länger eine Abfolge von Befehlen (also, WIE der Zustand erreicht werden soll), sondern den Zustand selbst, und Puppet kümmert sich um die jeweils notwendige Ausführung.

Populäre Alternativen zu Puppet sind Chef und Ansible (beide in Python geschrieben). Ich habe mich für Puppet entschieden, aus folgenden Gründen:

  1. es läuft auf Ruby, genau wie Vagrant, also eine zusätzliche Technologie weniger
  2. es ist für alle gängigen Plattformen verfügbar, läuft also auch unter Windows
  3. das GUI Tool PuPHPet ermöglicht das Konfigurieren von Vagrant Boxen für PHP Anwendungen (und mittlerweile auch Ruby, Python, NodeJS) in kürzester Zeit und ohne die Syntax der Puppet DSL kennen zu müssen.

Use PuPHPet for Magento

Weiterlesen auf integer-net.de

Magento Tutorial: Wie man Increment Models nutzt, um IDs zu generieren (oder SKUs)

Hast du dich je gefragt, wie Magento die increment_id Werte für Bestellungen, Rechnungen etc. generiert und wie man diesen Mechnismus nutzen oder erweitern kann? Vielleicht hast du die eav_entity_store Tabelle entdeckt, die die jeweils letzte increment id pro Entity-Typ und Store enthält, wobei je Store ggf. ein unterschiedlicher Präfix verwendet wird:

mysql> select * from eav_entity_store;
+-----------------+----------------+----------+------------------+-------------------+
| entity_store_id | entity_type_id | store_id | increment_prefix | increment_last_id |
+-----------------+----------------+----------+------------------+-------------------+
|               1 |              5 |        1 | 1                | 100000090         |
|               2 |              6 |        1 | 1                | 100000050         |
|               3 |              8 |        1 | 1                | 100000027         |
|               4 |              7 |        1 | 1                | 100000005         |
|               5 |              1 |        0 | 0                | 000000011         |
|               6 |              5 |        2 | 2                | 200000001         |
|               7 |              5 |        3 | 3                | 300000002         |
|               8 |              8 |        3 | 3                | 300000001         |
|               9 |              6 |        3 | 3                | 300000001         |
+-----------------+----------------+----------+------------------+-------------------+
9 rows in set (0.00 sec)

In diesem Artikel erkläre ich, wie dieses System für andere Entities genutzt werden kann.

Zunächst mal, die Standard-Methode funktioniert nur mit EAV Entities, nur mit einem Attribut pro Entity und dessen Name muss increment_id sein. Ich erkläre gleich aber noch, wie diese Beschränkungen umgangen werden können.

Continue reading “Magento Tutorial: Wie man Increment Models nutzt, um IDs zu generieren (oder SKUs)”

Mage Unconference 2015 – 7.-8. März – Berlin

Mage Unconference 2015

Vom 7. bis 8. März veranstaltet FireGento die erste Mage Unconference für Kunden, Händler, Anbieter, Agenturen, Provider – und natürlich – auch Entwickler. Der Inhalt der Unconference wird ganz alleine von Dir und den anderen Teilnehmern festgelegt.

>>> Mach mit und sei Teil der Community vom 7. bis 8. März 2015 in Berlin! <<<

Ich bin dabei und hoffe auf regen Austausch. Wer Interesse hat, sollte nicht zu lange zögern, bevor die Veranstaltung wegen zu weniger verkaufter Tickets abgeblasen wird!

[CSS] Inset Box Shadow auf Grafik

Ich arbeite an einer Website auf der viele Bilder einen Schatten nach innen haben sollen. Um sie nun nicht alle in Photoshop bearbeiten zu müssen, kam mir der “inset” Wert für das CSS3 Attribut “box-shadow” gelegen, dieser kann auf Bilder jedoch nicht ohne weiteres angewendet werden. Meine Lösung dazu möchte ich hier zeigen.

CSS box-shadow over img - example
So sollte es aussehen.

Auf img Elemente direkt angewendet, bleibt der Schatten hinter dem Bild, ist also nur bei Grafiken mit Transparenz überhaupt sichtbar. Führt man ein Wrapper-Element ein, das den Schatten zugewiesen bekommt, liegt dies zunächst mal auch hinter dem Bild, lässt sich aber mit z-index positionieren. Leider muss das Bild nach hinten gesetzt werden, den Wrapper vor das Bild setzen ist nicht möglich 1:

Continue reading “[CSS] Inset Box Shadow auf Grafik”

Notes:

  1. Kann mir das jemand erklären? 100% Durchblick beim z-index habe ich offenbar noch nicht.

Warum ich aktiv PHP 5.3 Kompatibilität aufgeben werde

PHP Supported Versions

Das geht ganz einfach und elegant, da in PHP 5.4 die short array syntax eingeführt wurde:

$everySingleArrayInitializationFromNowOn = [];

Warum dieser Schritt? Eine alarmierend große Zahl an Websites läuft noch auf PHP 5.3, das seit dem 14.8.2014 nach einem Jahr “security only” Support nicht mehr aktualisiert wird. Das heißt im Klartext, die nächste kritische Sicherheitslücke wird nur noch für Versionen ab 5.4 gefixt. Die aktive Weiterentwicklung am PHP 5.4 Branch ist übrigens auch am 14.9.2014 eingestellt worden, auch hier sind wir bereits in der “security only” Phase. Am 28.8.2014 ist PHP 5.6 released worden, am 20.6.2013 also vor fast 1,5 Jahren PHP 5.5

Im Jahre 2014 sollten wir also alle längst auf PHP 5.5 arbeiten. Soweit die Theorie. In der Praxis sieht es leider so aus:
PHP versions statistics - October 2014 - Pascal MARTIN
Quelle: http://blog.pascal-martin.fr/post/php-versions-stats-2014-10-en

Fast die Hälfte der Alexa Top 1M Sites, die auf PHP laufen, geben noch die Version 5.3 an, knapp ein viertel sogar noch 5.2, das seit Januar 2011 nicht mehr supported wird. PHP 5.2.17 ist sogar die am meisten in der Statistik auftauchende Patch-Version.

Gründe gibt es vermutlich viele:

  • “never touch a running system” Mentalität
  • Gar nicht oder nicht ausreichend gewartete Server
  • Inkompatible Frameworks und Legacy Anwendungen

Auf einige Hintergründe will ich kurz eingehen.

Continue reading “Warum ich aktiv PHP 5.3 Kompatibilität aufgeben werde”

Magento-Entwicklung mit Vagrant – Teil 3: Projektstrukturen für Magento

Im ersten Teil der Artikelserie zu Magento mit Vagrant habe ich Vagrant und die automatische Synchronisation mit Rsync vorgestellt, im zweiten Teil ein einfaches Basis-Setup der Vagrantbox für Magento. In diesem Teil soll es nun um die Projektstrukturierung gehen.

Mögliche Strukturen, aufbauend auf dem Basis-Vagrant-Setup:

Eigener Code separiert von Core und Extensions in src/

Das meiner Meinung nach ideale Setup habe ich im letzten Beitrag bereits beschrieben:

Die hier vorgestellte Struktur empfehle ich für neu entwickelte Shops. Mögliche Alternativen werden in einem separaten Beitrag erläutert. Der Quellcode verteilt sich auf folgende Verzeichnisse:

Verzeichnis Inhalt
/.modman Magento-Extensions
/src Projektspezifischer Code (inkl. gekaufter Extensions)
/vendor Nicht-Magento-spezifische Bibliotheken
/www Magento-Core

Durch Modman werden auf der Vagrantbox zusätzlich Symlinks in .modman (nach src) und www (nach .modman) erstellt.

In /www/ gibt es also keinerlei custom code, alles kommt mit Composer und Modman entweder aus /vendor bzw. /.modman (für fremden Code und eigene, projektübergreifende Module) oder aus /src (für eigenen, shop-spezifischen Code).

Weiterlesen auf integer-net.de

Magento-Entwicklung mit Vagrant – Teil 2: Beispiel-Setup mit Shell-Skripten

Vagrant + Magento

Im ersten Teil der Artikelserie zu Magento mit Vagrant habe ich Vagrant und die automatische Synchronisation mit Rsync vorgestellt. Nun kommen wir zu einem konkreten Setup der Vagrantbox für Magento.

Für das Provisionieren (also automatisches aufsetzen) der Box nutzen wir Shell-Skripte. Für Fortgeschrittene komme ich im letzten Teil der Serie zu einem anspruchsvolleres Setup mit Puppet und werde auch eine einsatzfertige Magento-Box veröffentlichen.

Zum Einstieg in Vagrant empfehle ich allerdings die hier vorgestellte Variante zu übernehmen und ein wenig mit der Konfiguration zu experimentieren. Sie steht vollständig auf Github zur Verfügung. Auch wenn das GUI Tool PuPHPet die Puppet-Konfiguration kinderleicht macht und man die Puppet DSL (Domain specific language) so nicht kennen muss, holt man sich zusätzliche Komplexität ins Haus, was im Fehlerfall einige Stunden und Frustration kosten kann.

Weiterlesen auf integer-net.de