webcodr

Amplify 2.0

Ich habe Amplify grundlegend überarbeitet und mit ein paar neuen Features ausgestattet:

  • Redcarpet wurde durch kramdown ersetzt und unterstützt damit auch die Markdown-Erweiterungen, die kramdown anbietet.
  • Automatisches Verlinken von URLs
  • HTML-Sanitation
  • Das Syntax-Highlighting übernimmt nun das Gem ‘pygments.rb’. Der Umweg über Pygmentizr fällt damit intern weg und verbessert die Reaktionszeiten deutlich.
  • Das Frontend basiert nun auf AngularJS.
  • Komplett überarbeiteter Quelltext.
  • JSON-basierte API

kramdown, das automatische Verlinken und die HTML-Sanitation werden über das Gem ‘slodown’ von Hendrik Mans erledigt.

Die neue JSON-basierte API ist über eine andere URL erreichbar:

http://amplify.webcodr.de/api/2.0/transform

Ein Beispiel-Request via POST:

{
 	"source": "# Hello World!"
}

Und die entsprechende Antwort von Amplify:

{
	"html": "<h1 id=\"hello-world\">Hello World!</h1>",
 	"source": "# Hello World!"
}

Wer, wie früher, ohne JSON auskommen möchte, nutzt bitte folgende URL:

http://amplify.webcodr.de/api/1.0/transform

Die bisherige Möglichkeit einfach einen POST-Request auf die Amplify-URL abzusetzen ist nur noch aus Gründen der Kompatibilität zu bestehenden Anwendungen aktiv, wird aber langfristig deaktiviert.

Zukünftige Features werde ich außerdem nur für die JSON-basierte API 2.0 implementieren.

Des weiteren plane ich Amplify langfristig nicht mehr auf Heroku laufen zu lassen, da die App einfach zu häufig in den Schlafmodus versetzt wird und anschließend sehr lange braucht, bis sie auf Anfragen reagiert.

Ich könnte zwar einfach einen Dyno hinzubuchen, aber das ist nicht gerade billig und es gibt wirklich kostengünstigere Möglichkeiten, Ruby-Web-Applikationen zu hosten – beispielsweise bei Uberspace.de.

Aus technischer Sicht dürfte noch interessant sein, dass Amplify nun mit Capybara automatisiert getestet wird und auf Travis CI sowie testweise Circle CI (mit automatischem Heroku-Deployment) läuft.

Say Hello to Mango

Was’n das?

Finger weg! Diese Mango schmeckt nicht.

Mango ist ein Object Document Mapper für MongoDB und PHP.

Und MongoAppKit?

MongoAppKit hat ein Problem, denn es ist nicht nur ein ODM und kann noch so einiges mehr. Theoretisch kann man zwar die ODM-Komponente auch ohne den ganzen anderen Krempel nutzen, aber es bleibt eine große Abhängigkeit zu Silex, die man auch nicht so einfach wieder los wird.

Dies und das im Vergleich schlechte Handling bzw. der geringe Komfort von MongoAppKit, haben mich dazu bewogen mit Mango einen universell einsatzbaren und leicht handzuhabenden ODM zu entwickeln.

Mango wurde stark von Mongoid für Ruby inspiriert und soll dessen Funktionalität zumindest teilweise in PHP abbilden. Das ist einfacher gesagt als getan, denn Ruby bietet wesentlich elegantere Möglichkeiten diverse Probleme zu lösen, als es mit PHP derzeit machbar ist.

Los geht’s …

Installation via Composer

$ php composer.phar require webcodr/mango:*

Ein Dokument anzulegen ist ein Kinderspiel

<?php

namespace MyProject\Model;

use Mango\Document;
use Mango\DocumentInterface;

class User implements DocumentInterface
{
    use Document;

    private function addFields()
    {
        $this->addField('name', ['type' => 'String']);
        $this->addField('email', ['type' => 'String']);
        $this->addField('created_at', ['type' => 'DateTime', 'index' => true, 'default' => 'now'];
        $this->addField('updated_at', ['type' => 'DateTime', 'index' => true, 'default' => 'now'];
    }
}

Es ist lediglich nötig, dass die Model-Klasse das Interface DocumentInterface implementiert und den Trait Document einbindet. In der Hook-Methode addFields() werden anschließend noch die Felder des Dokuments deklariert.

Mango nutzt etwas Magic: Der Klassenname des Models ist gleichzeitig auch der Name der Collection (klein geschrieben). Soll die Collection anders heißen bzw. das Model eine vorhandene nutzen, muss lediglich die Methode getCollectionName() überschrieben werden.

Go, Mango, go!

<?php

use Mango\Mango;
use Mango\DocumentManager;

use Document\User;

$mango = new Mango('mongodb://localhost/galactica');
$dm = new DocumentManager($mango);
$user = new User();
$user->name = 'William Adama';
$user->email 'william.adama@bsg-75.mil';
$user->store();

Das Mango-Object erwartet eine gültige MongoDB URI, falls notwendig inkl. Benutzer, Passwort, Port usw.

Dem Document Manager kommt eine vergleichbare Aufgabe zu, wie dem Entity Manager in Doctrine2.

Für mehr Komfort holt sich eine Model-Klasse den Document Manager über eine statische Methode ab. Daher können Methoden wie store() direkt über die Model-Klasse abgewickelt werden.

Dokumente abfragen

<?php

$user = User::where(['name' => 'William Adama']);
echo $user->count(); // = 1
echo $user->first()->email; // = william.adama@bsg-75.mil

Eine Abfrage kann einfach über die statische Methode where() ausgeführt werden. Die Syntax der Abfragen entspricht derzeit noch der normalen MongoDB Query API. Für die Zukunft plane ich aber eine Abstraktionsebene für die Abfragen, vergleichbar mit Mongoid.

Eine Abfrage kit where() oder find() gibt immer ein Cursor-Objekt zurück, das anhand der aufgerufenen Methode entscheiden kann, ob der Zugriff auf den MongoCursor oder das Abfrageergebnis in Form einer Instanz von MutableMap erfolgt.

In obigem Beispiel ist count() eine Methode des Cursors, während first() schon auf der Ergebnis zugreift. Wie MongoCursor kann auch die Cursor-Klasse von Mango einfach über das Ergebnis iterieren.

Durch die dynamische Unterscheidung zwischen MongoCursor- und Datenzugriff, können auf eine Instanz der Cursor-Klasse auch alle Methoden von MutableMap angewandt werden.

Beispielsweise:

<?php

User::where()->reverse()->slice(0, 2)->each(function($document) {
    echo $document->name;
});

Natürlich macht dieser Code wenig Sinn, da man das wesentlich effizienter über die Cursor-Methoden erledigen kann. Das Beispiel soll lediglich zeigen, was möglich wäre.

Hydration

Mango sorgt automatisch dafür, dass die Dokumente im Ergebnis immer Instanzen ihrer jeweiligen Model-Klasse sind.

Die Hydration-Automatik sorgt außerdem dafür, dass die Daten intern als jeweilige Typ-Klasse von Mango gehalten werden.

Typ-Klassen halten die Daten und können sie in zwei Formaten zurückgeben. Konfiguriert man ein Feld als DateTime bekommt Mango intern beim Speichern automatisch ein MongoDate-Objekt. Greift man hingegen außerhalb von Mango auf den Wert zu, bekäme man in diesem Fall eine Instanz der Klasse DateTime zurück.

Soweit zum aktuellen Funktionsumfang von Mango. Es ist bei weitem noch nicht fertig, kann aber für kleine Projekte schon einsetzt werden. Ich verwende es selbst in der aktuellsten Version von CodrPress und es macht wesentlich mehr Spaß als MongoAppKit, ohne ein monströses Schlachtschiff wie Doctrine zu sein.

Natürlich gibt’s Mango auch bei GitHub.

Services ftw!

Wer kennt das nicht? Man findet eine nette Software-Bibliothek in einer bestimmten Sprache, die vom Server der eigenen Web-Applikation nicht unterstützt wird oder nur sehr umständlich auf andere Weise genutzt werden kann.

So erging es mir mit Tools für Markdown-Rendering und server-basiertem Syntax-Highlighting. Zwar habe ich dafür ja im Oktober die Composer-Pakete SilexMarkdown und Radiant geschrieben, die beide auf bereits vorhandenen Bibliotheken fußen.

Ich war mit beiden nie recht glücklich. Für Ruby und Python gibt es viel schönere, wesentlich umfangreichere Lösungen:

  • Pygments ist ein Python geschriebener Syntax-Highlighter, der nahezu jede relevante Sprache unterstützt – selbst esoterische Merkwürdigkeiten wie Brainfuck.

  • Redcarpet wurde in Ruby verfasst und bietet einen sehr leicht erweiter- und modifizierbaren Markdown-Renderer.

Gerade für ein Blog-System wie CodrPress liegt es nahe, beide zu kombinieren und damit zumindest teilweise GitHub flavoured Markdown zu unterstützen.

Wie bekomme ich also drei Programmiersprachen unter einen Hut, ohne dass CodrPress nur auf angepassten Server-Konfigurationen läuft? Ganz einfach: Services!

Pygmentizr

Pygmentizr ist logischerweise in Python geschrieben, um Pygments nutzen zu können.

Per POST-Anfrage auf die verlinkte URL erreicht man den eigentlichen Service, der als Parameter die Sprache und den Quelltext erwartet. Zurück kommt HTML, das nur noch per CSS hübsch gemacht werden muss.

Ein entsprechendes Stylesheet für den bekannten Monokai-Stil ist auf der Seite verlinkt oder im GitHub-Repository zu finden.

Pygmentizr bei GitHub

Amplifyr

Amplifyr nutzt Redcarpet und bindet Pygmentizr als Syntax-Highlighter ein.

Wie Pygmentizr lässt sich Amplifyr per POST-Anfrage ansprechen und gibt den in HTML konvertierten Markdown-Quelltext zurück.

Amplifyr bei GitHub

Beide Dienste laufen auf der Cloud-Plattform Heroku.

CodrPress-Integration

Um beide Services in CodrPress nutzen können, habe ich in SilexMarkdown ein paar Umbauten vorgenommen. Beim Registrieren des Service-Providers in einer Silex-Applikation, lässt sich nun ganz einfach übergeben, ob der eingebaute Renderer samt Radiant oder Amplifyr genutzt werden soll. Eine entsprechende Anleitung findet sich in der ReadMe-Datei des SilexMarkdown-Repositories bei GitHub.

Beide Dienste sind bei Heroku untergebracht und kosten mich keinen Cent. daher gebe ich die Nutzung für jeden frei. Viel Spaß!

Array almighty

Wenn man sich zulange nur mit PHP beschäftigt vergisst man schnell, dass man oft Dinge tut, die kaum in andere Sprachen übertragbar sind.

Letztens habe ich mir Scala etwas näher angesehen. Kurz am Rande: eine schöne Sprache, wenn auch die verschiedenen Syntax-Modi etwas verwirrend oder zumindest recht gewöhnungsbedürftig sind.

Vorteil PHP

Scala bietet wie fast jede andere typisierte Sprache verschiedene Listen-Klassen für diverse Nutzungsfälle. In PHP gibt es das nicht. Man hat sein Array, das jederzeit veränderlich ist, jede noch so wilde Mischung von Datentypen akzeptiert und assoziative Schlüssel erlaubt. Es ist einfach umgemein praktisch.

Vorteil Scala

Da PHP leider weit davon entfernt ist vollständig objekt-orientiert zu sein und darum ein Array leider keine Objekt ist, kann man Arrays nur mit diversen Funktionen bearbeiten.

Zwar funktioniert das einwandfrei, ist aber umständlich. Ein Array-Objekt, das entsprechende Methoden bietet, die sich am besten auch noch verkettet aufrufen lassen, wäre doch toll.

PHP goes Scala/Java/Objective-C

Daher habe ich mich ans Werk gemacht und die bereits existierende Klasse IterateableList in MongoAppKit in drei neue Klassen des Namespaces \MongoAppKit\Collection aufgeteilt: MutableMap und ArrayMap.

Die Namen orientieren sich an ihren Pendants in Scala, Java oder auch Objective-C. Während alle die SPL-Interfaces Countable und IteratorAggregate implementieren, verwendet ArrayMap zusätzlich das Interface ArrayAccess und kann damit wie ein PHP-Array verwendet werden.

Außerdem implementieren alle drei die Magic Methods __get(), __set(), __isset() und __unset. Das erleichtert z.B. die Verwendung einer Liste in Twig, in dem keine Methode mehr angesprochen werden muss, um innerhalb eines Templates auf die Inhalte zuzugreifen.

Um diverse Array-Funktionen von PHP abzubilden implementieren alle drei die Methoden:

  • first(): gibt das erste Element der Liste zurück
  • last(): gibt das letzte Element der Liste zurück
  • reverse(): dreht die Reihenfolge der Elemente innerhalb der Liste um
  • each(): wendet eine Callback-Funktion mittels array_walk auf alle Elemente an, in der auch auf die Schlüssel zugegriffen werden kann
  • map(): wendet eine Callback-Funktion mittels array_map auf alle Elemente an
  • slice(): schneidet einen Teil der Elemente heraus und gibt sie in einem neuen Listen-Objekt zurück
  • filter(): filtert die Elemente einer Liste anhand einer Callback-Funktion und gibt das Ergebnis in einem neuen Listen-Objekt zurück

Fluent Interface

Um eine Verkettung von Methodenaufrufen zu ermöglichen gibt jede Methode, die sonst keinen Rückgabewert hätte, eine Referenz auf ihre Klasse zurück. Nur slice() und filter() geben eine neue Liste mit den herausgeschnittenen bzw. gefilterten Werten zurück.

Hier ein kleines Beispiel aus CodrPress, was man damit alles anstellen kann:

<?php

Post::where()->each(function($document) use ($app) {
    $md = $document->getProperty('body');
    $html = $app['markdown']->transform($md);
    $document->set('body_html', $html)->save();
});

Die statische Methode Post::where() liefert ohne Quert alle Posts als MutableMap-Objekt zurück. Auf die Rückgabe lässt sich sofort each() anwenden, das alle Elemente der Liste iteriert und die definierte Closure auf jedes Element einzeln anwendet.

In diesem Fall wird das rohe Markdown aus dem Feld body in HTML transformiert und im Feld body_html abgespeichert.

Fazit

MutableMap und seine Sub-Klassen sparen viel Schreibarbeit durch ein simples und komfortables Fluent Interface – einer Vorgehensweise, der in PHP leider viel zu wenig Beachtung geschenkt wird.

Download

Die drei Klassen sind nicht länger Teil von MongoAppKit. Ich habe sie in ein separates GitHub-Repository und Composer-Paket ausgelegt, um eine unkomplizierte Nutzung ohne MongoAppKit zu ermöglichen. Viel Spaß!

PythonPress

Da eine neue Sprache nicht genug ist, beschäftige ich mich neben Ruby neuerdings auch noch mit Python.

Als Lernprojekt setze ich aktuell CodrPress als Python-Version um. Natürlich will ich das nicht das Rad neu erfinden, daher setze ich auf zwei Frameworks, dank denen ich sehr schnell ein vorzeigbares Ergebnis zusammenbauen konnte:

  • Flask ist ein Micro-Framework vergleichbar mit Sinatra (Ruby) oder Silex (PHP). Es kümmert sich also um alles, was man braucht, um eine Website zu bauen. Vom Routing bis hin zur Template Engine (Jinja2).

  • MongoEngine bietet einen ODM (Object Document Mapper) vergleichbar mit Mongoid (Ruby) oder meinem eigenen Projekt MongoAppKit in PHP.

Routen-Definitionen mit Flask

from flask import Flask

app = Flask(__name__)

@app.route('/hello/<name>')
def hello(name):
    return 'Hello %s!' % name

app.run()

Zu Beginn wird die Klasse Flask aus dem Package flask importiert und anschließend eine Instanz erstellt.

Im Gegensatz zu PHP oder anderen C-Syntax-Sprachen kennt Python das Schlüsselwort new nicht. Um ein neues Objekt zu instanziieren reicht es den Klassennamen samt den Klammern und ggf. den Constructor-Argumenten zu schreiben.

Es folgt die Routen-Definition. Variable Werte werden in spitze Klammern gesetzt und der anschließenden Methode mit gleichem Namen als Parameter übergeben.

Wie auch in Silex oder Sinatra wird der Rückgabewert einer Routen-Methode zurück an den Browser geschickt. In diesem Fall ist das nur ein simpler String-Wert.

Templates in Flask

Flask nutzt die Template Engine Jinja2. Wer aus der PHP-Welt Twig kennt fühlt sich sofort heimisch. Die Sprachelemente sind nahezu identisch.

Datei: ./templates/hello.html

<h1>Hello {{ name }}!</h1>  

In obiger Route müsste die Methode nun so aussehen:

from flask import Flask, render_template
...
def hello(name):
    return render_template('hello.html', name = name)
...

Nicht vergessen: render_template muss zusätzlich importiert werden!

MongoEngine

from mongoengine import *

connect('test')

class Post(Document):
    _id = ObjectIdField()
    created_at = DateTimeField()
    published = BooleanField()
    title = StringField()
    body = StringField()

Der Aufruf von connect stellt eine Verbindung zur Datenbank test her. Da keine Verbindungsdaten angegeben werden, geht MongoEngine automatisch von einem lokalen MongoDB-Server auf dem Standard-Port aus.

Die Klasse Post ist eine Sub-Klasse von Document aus MongoEngine. Anschließend werden die Felder der Klasse definiert. MongoEngine stellt für jeden von MongoDB unterstützten Datentyp entsprechende Klassen zur Verfügung.

Sofern nicht über das Attribut meta eine andere Collection definiert wird, greift MongoEngine auf den Klassennamen in Kleinbuchstaben als Collection zu.

Um ein neues Dokument von Post zu erstellen und zu speichern, reicht schon folgender Code:

post = Post()
post.published = True
post.title = 'Hello World!'
post.body = 'Hallo, ich ein Test.'
post.save()

Abfragen mit MongoEngine

Als vollständiger ODM bietet MongoEngine natürlich auch die Möglichkeit vorhandene Daten abzufragen. In folgendem Beispiel werden die letzten zehn veröffentlichten Einträge absteigend nach der Erstelldatum sortiert, in ein Array geschrieben.

posts = Post.objects(published = True).order_by('-created_at').limit(10)

Abfragen erfolgen statisch, daher ist keine Instanz nötig. Die Methode objects() enthält die Bedingungen, also in diesem Fall, dass ein Eintrag veröffentlicht wurde. order_by() erwartet den Feldnamen mit der Sortierrichtung als Präfix. Hierbei steht + für aufsteigend und - für absteigend. Zu guter letzt wird das Ergebnis mit limit() auf 10 Dokumente eingeschränkt.

Mit diesem Wissen lässt sich nun ganz schnell eine Basis-Applikation bauen, die aus der vorhandenen CodrPress-Collection Einträge ausliest und anzeigt.

Der bisherige Stand ist natürlich bei GitHub.

CodrPress

Ich bin mal wieder so wahnsinnig und arbeite an einem Blog-System. Diesmal will ich das Rad aber nicht neu erfinden und ein zweites Wordpress bauen. Stattdessen orientiert sich CodrPress an Schnitzelpress.

Da Schnitzelpress auf Ruby basiert und primär für den Einsatz auf Heroku ausgelegt ist, habe ich mich dazu entschieden mit CodrPress quasi eine PHP-Version von Schnitzelpress zu entwickeln.

Natürlich ist das wieder mal einfacher gesagt als getan, vor allem da es für diverse Ruby Gems, die Schnitzelpress nutzt, in der PHP-Welt kaum brauchbaren Ersatz gibt.

Mit Redcarpet und CodeRay hat Ruby zwei wundervolle Gems, die sich um Markdown-Rendering bzw. Syntax-Highlighting kümmern.

CodrPress basiert auf meinem Projekt MongoAppKit, das widerrum auf Silex sowie Twig setzt und seine Abhängigkeiten mit Composer regelt. Keine der PHP-basierten Lösungen, um diese zwei Ruby Gems zu ersetzen, bietet Composer-Unterstützung an und die Strukturen sind z.T. auch nicht PSR-0-kompatibel, so dass ein Autoloading der Klassen nicht möglich ist.

Daher habe ich zwei neue Projekte aus der Taufe gehoben, die genau diesen Mangel beseitigen:

SilexMarkdown

Da ich keine Lust und Zeit habe, selbst einen Markdown-Renderer zu schreiben, basiert SilexMarkdown auf php-markdown von Michel Fortin.

Ich musste es erstmal in brauchbare Struktur bringen, da das Original leider weder Namespaces nutzt und sogar zwei Klassen in einer Datei besitzt.

SilexMarkdown stellt nun eine Service-Prodiver-Klasse für Silex und eine entsprechende Twig-Extension zur Verfügung. Dazu wurde es noch mit einer Unterstützung für Code-Blöcke angereichert, um Syntax Highlighting wie in GitHub nutzen zu können.

Radiant

Die Kern-Komponente von Radiant ist ebenfalls nicht auf meinem Mist gewachsen und stammt aus dem Projekt Nijikodo von Clint Campbell.

Immerhin war die Grundlage schon mal PSR-0-kompatibel und damit auch relativ leicht Composer-tauglich zu machen.

Meine Arbeit bestand zum Großteil darin, entsprechende Unit-Tests zu schreiben und einige Fehler zu beseitigen und es in SilexMarkdown einzubinden.

Qualität

Alle genannten Projekte, also MongoAppKit, SilexMarkdown, Radiant und CodrPress werden mittels PHPUnit laufend von mir und automatisiert via Travis CI getestet. Abgesehen von SilexMarkdown beträgt die Code-Coverage zwischen 70 - 90%.

Style

Aktuell ist CodrPress mit dem vollständigen Twitter Bootstrap versehen, um auch in der Entwicklunsphase ein halbwegs ahnsehnliches Design zu haben. Später werde ich nur ein paar Komponenten aus Bootstrap nutzen, z.B. das Grid und die responiven Fähigkeiten.

Für das Syntax-Highlighting habe ich ein Farb-Theme basierend auf meinem Farbschema von PhpStorm geschrieben, das auch Radiant beiliegt. Dank einer recht einfachen Struktur kann man sich auch sehr schnell ein eigenes Theme zusammenstellen.

Ausblick

Die Frontend-Funktionen von CodrPress sind mit einer gefüllten Datenbank (Schnitzelpress-kompatibel) schon nutzbar. Homepage, Einzeldarstellung von Einträgen, eigene Seiten und das Markdown-Rendering mit Syntax-Highlighting funktionieren soweit einwandfrei.

Als nächstes werde ich einem Admin-Bereich und anschließend einem ansprechenden Design widmen.

Menlo Park, start your photocopiers ...

… oder warum Software-Patente und Patentkriege scheiße sind.

Gestern habe für die Share-Funktionen von Twitter, Google+ und Facebook jeweils ein Modul nach dem CommonJS-Standard gebaut, um sie in meinem privaten Weblog zu nutzen.

Daran ist nun nichts besonders, wenn ich nicht eine kleine Entdeckung gemacht hätte. Offenbar hat Facebook den nötigen JavaScript-Code von Twitter kopiert oder Twitter von Facebook.

Quelltext vom Twitter

!function(d, s, id) {
	var js, fjs = d.getElementsByTagName(s)[0];

	if(!d.getElementById(id)) {
		js = d.createElement(s);
		js.id = id;
		js.src = "//platform.twitter.com/widgets.js";
		fjs.parentNode.insertBefore(js, fjs);
	}
}(document, "script", "twitter-wjs");

Quelltext von Facebook:

(function(d, s, id) {
	var js, fjs = d.getElementsByTagName(s)[0];
	if(d.getElementById(id)) return;
	js = d.createElement(s);
	js.id = id;
	js.src = "//connect.facebook.net/de_DE/all.js#xfbml=1";
	fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));

Zwecks der Lesbarkeit habe ich die Funktionen entsprechend formatiert.

Selbst Nicht-Programmierern dürften die Ähnlichkeiten kaum entgehen. Die Variablennamen sind identisch und sogar die Art der URL-Angabe ohne Protokoll. Selbst das if-Conditional und damit die Methode das externe JavaScript nicht zweimal einzubinden, stimmen überein – nur die Schreibweise ist etwas anders.

Aus meiner Sicht geht dieses Vorgehen das vollkommen in Ordnung. Man muss nicht ständig das Rad neu erfinden. Gerade Programmierer tun das sehr gerne, obwohl es nur selten notwendig ist.

Twitter und Facebook sind Technologie-Vorreiter, neben Google die zwei wichtigsten im gesamten Netz – warum sollten sie also nicht gegenseitig voneinander profitieren? Auch wenn es nur um einen Code-Schnippsel geht, der externe JavaScripts lädt.

Andere Firmen (Hallo, Oracle!) holen selbst bei wesentlich geringeren Quelltext-Ähnlichkeiten gleich die Klage-Keule raus. Durch die Möglichkeit in den USA Patente auf Software zu bekommen, ist sowas sogar oft von Erfolg gekrönt …

Ich bin kein Verfechter von Open Source, auch wenn ich es grundsätzlich für eine gute Sache halte. Noch bin ich der Meinung, dass Software ein Allgemeingut wäre und jedem kostenlos zur Verfügung stehen müsse.

Jedem Entwickler muss das Recht zustehen, sein Produkt zu verkaufen und es schützen zu dürfen. Im Fall von Trivial-Patenten, geht es nicht mehr darum.

Man will nur noch der Konkurrenz schaden und Geld rausholen, obwohl man selbst oft mehr als genug hat. Firmen werden gekauft, um an die Patente zu kommen und anschließend andere Firmen mit Klagen zu überziehen.

Egal, ob Apple, Samsung, Motorola (Google), Nokia oder sonst wer. Hört endlich auf damit! Keiner eurer Kunden will Import-Verbote, absurd hohe Patentabgaben für verkaufte Geräte oder sonstige Auswüchse euer Advokaten-Armeen.

Aus Apples Sicht ist Android ein geklautes Produkt. Objektiv gesehen kann man dem sogar in Teilen zustimmen. Nur: na und?

Apple hat gute Ideen, Google hat gute Ideen. Nutzt sie, um euch gegenseitig zu verbessern und stellt diese lächerlichen Grabenkämpfe ein, die euch letztlich mehr schaden als nützen.

Responsive Bilder mit WordPress

Aktuell wage ich erste Gehversuche mit responsiven Layouts in meinem WordPress-Theme. Ziel der Übung ist ein smartphone-taugliches Layout. Leider macht einem WordPress die Arbeit bei Bildern unnötig schwer.

Automatische Bildskalierung mit CSS

Bilder müssen in responsiven Layouts automatisch mit der Breite des Anzeigegeräts skalieren. Feste Breiten würden hier zwangsläufig zu Darstellungsproblemen führen. Das klingt nun komplizierter als es ist. Mit drei Zeilen CSS lassen sich Bilder abhängig von der Breite ihres Eltern-Elements automatisch skalieren.

img {
	max-width: 100%;
}

Ein Bild darf also maximal so breit werden, wie seine vorgesehene Weite. Schrumpft das Eltern-Element durch Verkleinern des Viewports, wird das Bild automatisch mitskaliert. Wir müssen uns also um nichts weiter kümmern, da die Browser den Rest erledigen.

Problemfall WordPress

Leider klappt die automatische Skalierung in WordPress nicht. Wenn man in einem Beitrag Bilder einfügt, setzt WordPress automatisch das width- bzw. height-Attribut auf das img-Element. Sobald auch nur eines von beiden gesetzt ist, wird eine automatische Größenanpassung verhindert. Die Attribute müssen also weg.

Wie immer, gibt es dafür zig verschiedene Möglichkeiten. Beispielsweise könnte man die überflüssigen Element-Eigenschaften per jQuery-Einzeiler entfernen. Wirklich schön ist das aber nicht. Es wäre doch viel besser, wenn man WordPress dazu bringen könnte, den Quelltext gleich ohne width und height auszuliefern.

Dank des Hook-Systems in WordPress geht das mit ein paar Zeilen Code in der Datei functions.php des Themes:

add_filter('the_content', 'removeImageDimensions');

function removeImageDimensions($html) {
	return preg_replace('/(width|height)=\"\d*\"\s/', '', $html);
}

Die Funktion removeImageDimensions() entfernt per regulärem Ausdruck unsere unerwünchten Gäste width und height. Mittels add_filter() wird der WordPress-Funktion the_content() (gibt den Inhalt eines Beitrags aus) unsere neue Funktion als Ausgabefilter zugewiesen. WordPress führt nun bei jedem Aufruf von the_content() unsere neue Funktion removeImageDimensions() aus, die den Rückgabewert von the_content() entsprechend verändert.

Damit steht responsiven Bildbreiten nun nichts mehr im Weg.

Retina-Display-taugliche Icons mit CSS-Hintergrundbildern

Besitzer von Apple-Geräten mit Retina-Displays kennen das Dilemma: auf vielen Seiten sehen Hintergrundbilder, insbesondere Icons, reichlich unscharf aus. So erging es mir gleich doppelt mit meinem privaten Blog. Dank neuem iPad und MacBook Pro, vermatschen die Icons für externe Links.

Es gibt verschiedene Lösungsansätze für dieses Problem, beispielsweise Icons in vektorbasierten Formaten (SVG), die beliebig in jeder Pixeldichte skalieren können.

Da ich die verwendeten Icons nur als Bilder vorliegen habe, kommt diese Lösung nicht in Betracht. Dank CSS-Media-Queries ist das aber kein großes Problem.

Media-Queries?

Ein Media-Query ermöglicht es, innerhalb eines Stylesheets diverse Informationen zum aktuellen Anzeigegerät abzufragen. Dazu gehören unter Anderem die Minimal-Breite, die Ausrichtung (Portrait, Landscape), der Gerätetyp (Screen, Projection etc.), das Bildverhältnis oder in diesem Fall besonders wichtig, das Verhältnis zwischen vorhandenen und tatsächlich dargestellten Pixeln.

Was machen eigentlich Retina-Displays?

Retina-Displays verdoppeln die Auflösung, während die dargestellten Elemente gleich groß bleiben. Bei normalen Displays ist dieses Verhältnis 1:1. Eine Grafik mit 100 Pixeln Breite wird also mit 100 Pixeln auf dem Monitor dargestellt. Auf Apple-Geräten mit Retina-Displays verdoppeln sich die 100 Pixel auf 200 Pixel – das Verhältnis beträgt also 2:1.

Ist eine Grafik in der notwendigen Auflösung nicht verfügbar, wird das vorhandene Bild hochgerechnet und wirkt unscharf. Mit einem Media-Query können wir dem Browser eine höher aufgelöste Version zur Verfügung stellen, die genau das verhindert.

An die Arbeit

@media only screen and (min--moz-device-pixel-ratio: 2),
only screen and (-o-min-device-pixel-ratio: 2),
only screen and (-webkit-min-device-pixel-ratio: 2),
only screen and (min-device-pixel-ratio: 2) {
	#content article .content p a.external {
		background-image: url("icons/external-url-32.png");
		background-size: 16px auto;
	}
}

Da die Media-Query-Eigenschaft min-device-pixel-ratio noch nicht vollständig in allen Browsern implementiert ist, setze ich die entsprechenden Präfix-Versionen vorher ein. So kann man sichergehen, dass die proprietäre als auch die standardisierte Eigenschaft greifen – je nach aktuellem Stand der Browser-Implementation.

Mozilla greift hier zu einer recht seltsamen Präfix-Syntax, während Opera und Webkit sich an das bewährte Schema halten. Ob und wann der Internet Explorer die Eigenschaft unterstützt, konnte ich bisher nicht herausfinden.

Wie oben schon beschrieben, ist das Verhältnis von tatsächlichen Pixeln zu dargestellten Pixeln 2:1, daher wird es in der Bedingung mit einer 2 angegeben.

Innerhalb des Media-Queries kann ganz normales CSS verwendet werden. Ich tausche nun einfach das bisherige Hintergrundbild (16 x 16 Pixel) durch eine größere Version (32 x 32 Pixel) aus und setze die Größe des Hintergrundbildes auf 16 Pixel. Ansonsten würde der Browser eine falsche Annahme treffen und das Bild auf 64 x 64 Pixel hochrechnen. Damit wäre alles für die sprichwörtliche Katz.

Das war’s schon. Sofern man ein passendes Gerät hat und der Browser die Media-Query-Eigenschaft unterstützt, bekommt man nun ein schön hoch aufgelöstes Icon zu sehen, das um Welten besser aussieht als der hochgerechnete Pixelmatsch.

PHP-Autoloader nach dem PSR-0-Standard

Wenn’s um das Schreiben eines Autoloaders in PHP geht, kochen viele Entwickler gern ihr eigenes Süppchen. Sofern nun mehrere gleichzeitig aktiv sind, kann das zu Problemen führen und ggf. sogar dafür sorgen, dass eine Alternative gesucht werden muss.

Die PHP Framework Interoperability Group (kurz FIG) hat sich dieses Problems angenommen und eine Spezifikation für Autoloader entwickelt, die Interoperabilität sicherstellt.

Der PSR-0-Standard besteht aus ein paar recht simplen Regeln, die sich sehr einfach umsetzen lassen und z.T. sicher schon von vielen genutzt wurden:

  • Ein qualifizierter Namespace hat folgende Struktur \<Vendor Name>\(<Namespace>\)*<Class Name>
  • Jeder Namespace hat einen Haupt-Namespace (Vendor Name)
  • Jeder Namespace kann beliebig viele Unter-Namespaces besitzen
  • Jeder Namespace-Separator wird in einen DIRECTOR_SEPARATOR konvertiert, wenn aus dem Dateisystem geladen wird
  • Das Zeichen “_” (Underscore) wird in einen DIRECTORY_SEPARATOR konvertiert und hat keine spezielle Bedeutung.
  • Der qualifizierte Namespace inkl. Klasse bekommt die Endung “.php” angehängt, um die Datei zu laden.
  • Namespaces, Vendor Names und Klassennamen dürfen alphabetische Zeichen in jeder Kombination aus Groß- und Kleinschreibung enthalten.

Beispiel-Implementation

<?php

namespace WebCodr;

class Loader {

    public static function registerAutoloader() {
        return spl_autoload_register(array ('WebCodr\\Loader', 'load'));
    }

    public static function load($class) {
        if(substr($class, 0, 7) !== 'WebCodr') {
            return;
        }

        $libraryRoot = realpath(__DIR__ . '/../');
        $classFileName = str_replace(array('\\', '_'), DIRECTORY_SEPARATOR, $class) . '.php';
        $fileName = realpath($libraryRoot . DIRECTORY_SEPARATOR . $classFileName);

        if(is_readable($fileName)) {
            include_once($fileName);
        }
    }
}

Die Klasse stellt zwei statische Methoden bereit. Mit Loader::registerAutoloader() wird die Methode Loader::load() als SPL-Autoloader registriert.

Loader::load() prüft zuerst, ob sich die angeforderte Klasse überhaupt in Namespace WebCodr befindet. Falls dies nicht der Fall ist, wird durch den leeren Rückgabewert signalisiert, dass die Klasse mit diesem Autoloader nicht geladen werden kann und die SPL geht zum nächsten registrierten Autoloader über.

Anschließend wird der Pfad zur Klasse zusammengesetzt und die Datei mittels include_once() eingebunden. Optinal könnte man im Fehlerfall natürlich noch eine Exception werfen.

Aufruf des Autoloaders

<?php

include_once('Loader.php');
\WebCodr\Loader::registerAutoloader();

Fazit

PSR-0 ist schnell und einfach implementiert. Für neue Projekte gibt es also keinen Grund, sich nicht daran zu halten. In bestehendem Code könnte es recht aufwendig sein, den Standard umzusetzen – je nach dem, welche Benamungsschemata und Verzeichnisstrukturen bereits verwendet werden.

Man sollte den Aufwand aber nicht scheuen. Was bringt einem schon die tollste Library oder ein cooles Framework, wenn es aufgrund eines schlecht implementierten Autoloaders, kaum eingesetzt werden kann?