<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ebene7</title>
	<atom:link href="http://blog.ebene7.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.ebene7.com</link>
	<description></description>
	<lastBuildDate>Tue, 04 Jun 2013 18:57:27 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Twig: Flexibel arbeiten mit Blöcken</title>
		<link>https://blog.ebene7.com/2013/03/10/twig-flexibel-arbeiten-mit-bloecken/</link>
		<comments>https://blog.ebene7.com/2013/03/10/twig-flexibel-arbeiten-mit-bloecken/#comments</comments>
		<pubDate>Sun, 10 Mar 2013 18:00:54 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Bootstrap]]></category>
		<category><![CDATA[Symfony2]]></category>
		<category><![CDATA[Template]]></category>
		<category><![CDATA[Twig]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=4025</guid>
		<description><![CDATA[Durch die Arbeit mit Symfony2 lerne ich immer mehr auch die Vorteile und hohe Flexibilität von Twig zu schätzen. Es bietet einfach eine Menge Funktionen von Hause aus und lässt sich zudem auch einfach erweitern. Aber das nur am Rande. &#8230; <a href="https://blog.ebene7.com/2013/03/10/twig-flexibel-arbeiten-mit-bloecken/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Durch die Arbeit mit Symfony2 lerne ich immer mehr auch die Vorteile und hohe Flexibilität von Twig zu schätzen. Es bietet einfach eine Menge Funktionen von Hause aus und lässt sich zudem auch einfach erweitern. Aber das nur am Rande.</p>
<p>In einem Projekt an dem ich gerade arbeite verwende ich ein Bootstrap-Grid und will gewisse Teile nur rendern, wenn sie verwendet werden bzw. Inhalte bereitstellen. Dazu müssen entsprechende Blöcke überprüft und CSS-Klassen angepasst werden.</p>
<p><span id="more-4025"></span>Erstmal das Basis-Template ohne irgendwelche Anpassungen (base.html.twig):</p>
<pre>&lt;html&gt;
  &lt;head&gt;...&lt;/head&gt;
  &lt;body&gt;
    &lt;div class="container-fluid"&gt;
      &lt;div class="row-fluid"&gt;

        &lt;div class="span3 sidebar-left"&gt;
        {% block sidebar_left %}{% endblock %}
        &lt;/div&gt;

        &lt;div class="span4 content"&gt;
        {% block content %}{% endblock %}
        &lt;/div&gt;

        &lt;div class="span3 sidebar-right"&gt;
        {% block sidebar_right %}{% endblock %}
        &lt;/div&gt;

      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre>
<p>Der Nachteil an diesem Konstrukt ist recht offensichtlich. Das Layout ist starr und leere Elemente würden viel Platz verschwenden. Um das zu vermeiden können wir das Template etwas intelligenter machen. Normalerweise hat Logik in Templates nichts zu suchen, aber in dem Fall geht es allein um die Anzeige.</p>
<p>Die Blöcke lassen sich in Variablen schreiben und dann prüfen.</p>
<pre>{% set sbleft = block('sidebar_left') %}

{% if sbleft is not empty %}
  {# mach irgendwas #}
{% endif %}</pre>
<p>Durch diesen einfachen Code lassen sich die einzelnen Teile im Template nun einfach steuern. Auch wenn es ein paar Zeilen Code braucht, aber das wird später vielfach wieder eingespart.</p>
<pre>{% set sbleft = block('sidebar_left') %}
{% set sbrigth = block('sidebar_right') %}

{% if sbleft is empty and sbright is empty %}
  {% set contentClass = 'span12' %}
{% elseif sbleft is empty or sbright is empty %}
  {% set contentClass = 'span8' %}
  {% set sidebarClass = 'span4' %}
{% else %}
  {% set contentClass = 'span6' %}
  {% set sidebarClass = 'span3' %}
{% endif %}

&lt;html&gt;
  &lt;head&gt;...&lt;/head&gt;
  &lt;body&gt;
    &lt;div class="container-fluid"&gt;
      &lt;div class="row-fluid"&gt;

        {% if sbleft is not empty %}
        &lt;div class="{{ sidebarClass }} sidebar-left"&gt;
        {% block sidebar_left %}{% endblock %}
        &lt;/div&gt;
        {% endif %}

        &lt;div class="span4 content"&gt;
        {% block content %}{% endblock %}
        &lt;/div&gt;

        {% if sbright is not empty %}
        &lt;div class="{{ sidebarClass }} sidebar-right"&gt;
        {% block sidebar_right %}{% endblock %}
        &lt;/div&gt;
        {% endif %}

      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre>
<p>Damit  ist dieses Template nun schlau genug und weiß wann welcher Bereich angezeigt werden soll und in welcher Größe. Die Klassen für die Sidebars können auch getrennt für jede Seite vergeben werden, wenn der Aufbau nicht symetrisch sein soll.</p>
<p>In einem anderen Template können wir wie gewohnt damit arbeiten.</p>
<pre>{% extends "::base.html.twig" %}

{% block content %}
Hier der Seiteninhalt.
{% endblock %}

{% block sidebar_right %}
Hier die rechte Sidebar.
{% endblock %}</pre>
<p>Viel Spaß beim Probieren! Kommentare, Anmerkungen oder Fragen sind wie immer willkommen.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2013/03/10/twig-flexibel-arbeiten-mit-bloecken/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>MySQL: Datenbank kopieren</title>
		<link>https://blog.ebene7.com/2013/02/05/mysql-datenbank-kopieren/</link>
		<comments>https://blog.ebene7.com/2013/02/05/mysql-datenbank-kopieren/#comments</comments>
		<pubDate>Tue, 05 Feb 2013 13:00:22 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[Datenbank]]></category>
		<category><![CDATA[Tipps und Tricks]]></category>
		<category><![CDATA[kopieren]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=4005</guid>
		<description><![CDATA[Bestehende Datenbank in Datei schreiben: mysqldump datenbank_orig &#62; datenbank_orig.sql -ubenutzername -p Neue Datenbank aus Datei befüllen: mysql -ubenutzername -p datenbank_kopie &#60; datenbank_orig.sql]]></description>
			<content:encoded><![CDATA[<p>Bestehende Datenbank in Datei schreiben:</p>
<pre>mysqldump datenbank_orig &gt; datenbank_orig.sql -ubenutzername -p</pre>
<p>Neue Datenbank aus Datei befüllen:</p>
<pre>mysql -ubenutzername -p datenbank_kopie &lt; datenbank_orig.sql</pre>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2013/02/05/mysql-datenbank-kopieren/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfony2: Custom ParamConverter für HTTP-Requests erstellen</title>
		<link>https://blog.ebene7.com/2013/01/31/symfony2-custom-paramconverter-fuer-http-requests-erstellen/</link>
		<comments>https://blog.ebene7.com/2013/01/31/symfony2-custom-paramconverter-fuer-http-requests-erstellen/#comments</comments>
		<pubDate>Thu, 31 Jan 2013 21:00:49 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Controller]]></category>
		<category><![CDATA[Converter]]></category>
		<category><![CDATA[Parameter]]></category>
		<category><![CDATA[Request]]></category>
		<category><![CDATA[Symfony2]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=3978</guid>
		<description><![CDATA[Eines der vielen kleinen Goodies die Symfony2 zu bieten hat ist der ParamConverter. Die ParamConverter übersetzen die Parameter beim HTTP-Request nach den gewünschten Vorgaben. So können zum Beispiel Datenmodelle direkt geladen oder Datum-Strings als DateTime-Objekte genutzt werden. Wenn man mit &#8230; <a href="https://blog.ebene7.com/2013/01/31/symfony2-custom-paramconverter-fuer-http-requests-erstellen/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Eines der vielen kleinen Goodies die Symfony2 zu bieten hat ist der ParamConverter. Die ParamConverter übersetzen die Parameter beim HTTP-Request nach den gewünschten Vorgaben. So können zum Beispiel Datenmodelle direkt geladen oder Datum-Strings als DateTime-Objekte genutzt werden. Wenn man mit einem Standardsetup arbeitet, sind diese Converter direkt dabei.</p>
<p>Aber auch eigene Converter sind schnell geschrieben und einsatzfähig. Sämtliche Möglichkeiten des <a href="http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html" target="_blank">ParamConverters</a> stehen in der Dokumentation.<br />
<span id="more-3978"></span></p>
<p>Als Ausgangspunkt haben wir in dem Beispiel eine Action, die mit einer ID aufgerufen wird.</p>
<pre>&lt;?php
namespace E7\DemoBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use E7\DemoBundle\Model\Post;

class DefaultController extends Controller {
    /**
     * @Route("/test/{postId}")
     * @ParamConverter()
     * @param   Post $post
     */
    public function testAction(Post $post) {
      // some usefull code
    }
}</pre>
<p>Über die Annotation @ParamConverter weiß das System nun, dass der Parameter übersetzt werden soll. Die bereits zu Beginn erwähnten Converter sind bereits registriert. Um nun eine eigene Logik zu verwenden, brauchen wir einen eigenen Übersetzter. Die Klasse muss das Interface ParamConverterInterface implementieren.</p>
<p>Die Schnittstelle ist sehr einfach gehalten und bietet alls was man braucht. Die Methode supports() muss ein TRUE oder FALSE zurückgeben, ob die Klasse die Anfrage übersetzen kann und apply() mach dann den Rest.</p>
<pre>&lt;?php
namespace E7\DemoBundle\Request\ParamConverter;

use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class ModelParamConverter implements ParamConverterInterface {
    function apply(Request $request, ConfigurationInterface $configuration) {
        $name = $configuration-&gt;getName();
        $idParam = $name . 'Id';
        $class = $configuration-&gt;getClass();

        if (!$request-&gt;attributes-&gt;has($idParam)) {
            return false;
        }

        $id = $request-&gt;attributes-&gt;get($idParam);

        $model = loadModelById($id);
        $request-&gt;attributes-&gt;set($param, $model);

        if (null === $model-&gt;getId()) {
            throw new NotFoundHttpException(sprintf('%s object not found.', $class));
        }

        return true;
    }

    function supports(ConfigurationInterface $configuration) {
        return modelClassExists($class);
    }
}</pre>
<p>Die Klasse soll schematisch zeigen, wie ein Converter funktionieren könnte. Die beiden Funktionen loadModelById() und modelClassExists() stehen nur als Pseudocode da. Alle verfügbaren Werte können über die Annotation $configuration abgerufen werden. Über $configuration kommen wir an den Namen des Parameter und den TypeHint.</p>
<pre>Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter Object
(
    [name:protected] =&gt; post
    [class:protected] =&gt; E7\DemoBundle\Model\Post
    [options:protected] =&gt; Array
        (
        )

    [optional:protected] =&gt;
    [converter:protected] =&gt; model
)</pre>
<p>Bevor unser Converter überhaupt beachtet wird, müssen wir ihn in der services.yml als Service registrieren.</p>
<pre>services:
    request.param_converter:
        class: E7\DemoBundle\Request\ParamConverter\ModelParamConverter
        tags:
            - { name: request.param_converter, converter: model }</pre>
<p>Ab jetzt sollte alles zusammenarbeiten und wir können nach belieben Requestparameter umformen. Viel Spaß!</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2013/01/31/symfony2-custom-paramconverter-fuer-http-requests-erstellen/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfony2: Globale Variablen in Routen</title>
		<link>https://blog.ebene7.com/2012/12/13/symfony2-globale-variablen-in-routen/</link>
		<comments>https://blog.ebene7.com/2012/12/13/symfony2-globale-variablen-in-routen/#comments</comments>
		<pubDate>Thu, 13 Dec 2012 05:00:17 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Annotations]]></category>
		<category><![CDATA[Konfiguration]]></category>
		<category><![CDATA[Routing]]></category>
		<category><![CDATA[Symfony2]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=3922</guid>
		<description><![CDATA[Für ein Projekt wollte ich ein Prefix für die Routen verwenden und dieses an einer zentralen Stelle konfigurieren können. In diesem Fall sollte damit der Admin-/Backendbereich abgegrenzt werden. Nach etwas Suchen fand ich eine Möglichkeit in der Symfony Dokumentation. Ab &#8230; <a href="https://blog.ebene7.com/2012/12/13/symfony2-globale-variablen-in-routen/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Für ein Projekt wollte ich ein Prefix für die Routen verwenden und dieses an einer zentralen Stelle konfigurieren können. In diesem Fall sollte damit der Admin-/Backendbereich abgegrenzt werden.</p>
<p>Nach etwas Suchen fand ich eine Möglichkeit in der <a href="http://symfony.com/doc/current/cookbook/routing/service_container_parameters.html" target="_blank">Symfony Dokumentation</a>.</p>
<p>Ab Version 2.1 kann ein Parameter in der Konfigurations-Datei gespeichert werden.</p>
<pre># app/config/config.yml
parameters:
    backend_prefix: admin</pre>
<p>Dieser Parameter kann dann z.B. in der Route-Annotation oder der Routing Konfiguration verwendet werden.</p>
<pre>/**
 * @Route("/%backend_prefix%/user")
 */
class UserBackendController extends Controller {
    /**
     * @Route("/")
     */
    public function indexAction() {
        /* do something */
    }
}</pre>
<p>Durch das Prefix ist dieser Bereich nicht nur optisch im URL abgehoben, sondern kann durch die <a href="http://symfony.com/doc/current/book/security.html" target="_blank">Security Konfiguration</a> auch leicht nur für einzelne Nutzergruppen freigegeben werden.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2012/12/13/symfony2-globale-variablen-in-routen/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Symfony Live 2012 in Berlin</title>
		<link>https://blog.ebene7.com/2012/11/26/symfony-live-2012-in-berlin/</link>
		<comments>https://blog.ebene7.com/2012/11/26/symfony-live-2012-in-berlin/#comments</comments>
		<pubDate>Mon, 26 Nov 2012 05:00:16 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[Events]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Symfony]]></category>
		<category><![CDATA[Symfony Live]]></category>
		<category><![CDATA[Symfony2]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=3861</guid>
		<description><![CDATA[In der vergangenen Woche fand am 22. und 23.11. 2012 die Symfony Live 2012 in Berlin statt. Ich hatte ein Ticket für den Freitag und will den Tag kurz für euch zusammenfassen. Das Event fand in einer Kirche statt und &#8230; <a href="https://blog.ebene7.com/2012/11/26/symfony-live-2012-in-berlin/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In der vergangenen Woche fand am 22. und 23.11. 2012 die <a href="http://berlin2012.live.symfony.com/index.html" target="_blank">Symfony Live 2012 in Berlin</a> statt.</p>
<p>Ich hatte ein Ticket für den Freitag und will den Tag kurz für euch zusammenfassen.<span id="more-3861"></span></p>
<p>Das Event fand in einer Kirche statt und startete nach dem Frühstücksbuffet fast pünktlich. Der Saal war gut besetzt und dank der Technik konnte man auch aus den hinteren Reihen den Vorträgen gut folgen. Wenn ich die Anmoderation richtig in Erinnerung habe, waren Besucher aus 19 Ländern dabei.</p>
<p>Die Sitzplätze fand ich etwas beengt und das kostenlose WLAN war leider die meiste Zeit überlastet, aber beides für mich eher nebensächlich.</p>
<p>Alle Vorträge und die Moderation wurden erwartungsgemäß auf Englisch gehalten und waren dank der erfahrenden Sprecher meist nicht nur informativ, sondern auch recht unterhaltsam.</p>
<p>Meine persönlichen Favoriten an dem Tag waren der Vortrag &#8220;Symfony2 Form Tricks&#8221; von Bernhard Schussek (symmetry <img src='https://blog.ebene7.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> ) und die Keynote von Fabien Potencier. Alle Themen der beiden Tage sind auch auf der <a href="http://berlin2012.live.symfony.com/sessions.html" target="_blank">Symfony-Seite</a> zu finden.</p>
<p>In vielen Vorträgen wurde gezeigt wie einfach verschiedenen Aufgaben in Symfony2 umgesetzt werden können und wie der Code wiederverwendbar bleibt. Nach dem Motto &#8220;Don&#8217;t Reinvent The Wheel&#8221;.</p>
<p>Vieles wird dabei über Konventionen vereinheitlicht und gleichzeitig vereinfacht und immer mehr Konfigurationseinstellungen können über Annotations im Code mitgegeben werden. Auch das Eventsystem und Listerners spielen weiter eine große Rolle.</p>
<p>Aus meiner Sicht hat sich der Tag gelohnt. Vieles war bei durch die Arbeit mit Symfony2 bereits bekannt, aber es war doch noch genug Neues dabei. Für mich ist es immer interessant zu sehen, wie andere Entwickler bestimmte Aufgaben lösen und warum der jeweilige Weg gewählt wurde.</p>
<p>Falls auch jemand von euch an einem der beiden Tage dabei war, schreibt gerne einen Kommentar wie es euch gefallen hat.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2012/11/26/symfony-live-2012-in-berlin/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfony2: Action in einem anderen Twig-Template ohne Layout rendern</title>
		<link>https://blog.ebene7.com/2012/09/28/symfony2-action-in-einem-anderen-twig-template-ohne-layout-rendern/</link>
		<comments>https://blog.ebene7.com/2012/09/28/symfony2-action-in-einem-anderen-twig-template-ohne-layout-rendern/#comments</comments>
		<pubDate>Fri, 28 Sep 2012 04:00:01 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Tipps und Tricks]]></category>
		<category><![CDATA[Layout]]></category>
		<category><![CDATA[Symfony2]]></category>
		<category><![CDATA[Twig]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=3818</guid>
		<description><![CDATA[Mit Twig hat man als Entwickler viele Freiheiten und kann sehr flexible Templates erstellen. So ist es auch möglich Seiten durch Vererbung in ein Layout zu packen oder über die Action das Template ohne Layout in ein anderes zu rendern. &#8230; <a href="https://blog.ebene7.com/2012/09/28/symfony2-action-in-einem-anderen-twig-template-ohne-layout-rendern/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Mit Twig hat man als Entwickler viele Freiheiten und kann sehr flexible Templates erstellen. So ist es auch möglich Seiten durch Vererbung in ein Layout zu packen oder über die Action das Template ohne Layout in ein anderes zu rendern.</p>
<p><span id="more-3818"></span>Dazu kann im Template die aufgerufene Route abgefragt werden, um gewisse Teile anzuzeigen oder nicht.</p>
<pre>{% extends app.request.attributes.get('_route') == '_internal' ?
'::empty.html.twig' :
'MyAppMyBundle::layout.html.twig' %}</pre>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2012/09/28/symfony2-action-in-einem-anderen-twig-template-ohne-layout-rendern/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sortieren mit PHP5 Closures und dem Java Comparator Pattern</title>
		<link>https://blog.ebene7.com/2012/08/31/sortieren-mit-php5-closures-und-dem-java-comparator-pattern/</link>
		<comments>https://blog.ebene7.com/2012/08/31/sortieren-mit-php5-closures-und-dem-java-comparator-pattern/#comments</comments>
		<pubDate>Fri, 31 Aug 2012 04:00:13 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Callback]]></category>
		<category><![CDATA[Closure]]></category>
		<category><![CDATA[Comparator]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Sortierung]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=3421</guid>
		<description><![CDATA[Was mich schon oft bei PHP ein wenig störte ist, dass es zum Sortieren nicht so schöne Comparatoren wie in Java gibt. Nun habe ich in der Vergangenheit ja schon das eine oder andere über Closures in PHP und Java &#8230; <a href="https://blog.ebene7.com/2012/08/31/sortieren-mit-php5-closures-und-dem-java-comparator-pattern/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Was mich schon oft bei PHP ein wenig störte ist, dass es zum Sortieren nicht so schöne Comparatoren wie in Java gibt.</p>
<p>Nun habe ich in der Vergangenheit ja schon das eine oder andere über <a href="http://blog.ebene7.com/2012/01/30/closures-in-php/">Closures in PHP</a> und <a href="http://blog.ebene7.com/2010/09/06/besser-sortieren-mit-php-dank-java-interfaces/">Java Comparatoren für PHP</a> geschrieben und wollte das nun mal zusammenbringen.</p>
<p><span id="more-3421"></span>Einige PHP-Sortierfunktionen erlauben Callbacks, um die Reihenfolge zu bestimmen. Da ich das Ganze aber gerne in gut testbaren OOP-Einheiten hätte, müssen wir einen kleinen Umweg gehen.</p>
<p>Zunächst das obligatorische Interface.</p>
<pre>namespace E7;

interface Comparator {
  public function compare($a, $b);
}</pre>
<p>Diese Schnittstelle implementieren wir mit einer abstrakten Klasse.</p>
<pre>namespace E7;

class BaseComparator implements Comparator {
  public function compare($a, $b) {
    if ($a == $b) { return 0; }
    return $a &lt; $b ? -1 : 1;
  }

  public function __invoke() {
    return call_user_func_array(array($this, 'compare'), func_get_args());
  }
}</pre>
<p>Und schon haben wir einen einfachen, und zugegebenermaßen nicht typsicheren, Comparator.</p>
<p>Durch die magische Methode __invoke() kann ein Objekt nun wie eine Callbackfunktion verwendet werden.</p>
<p>Für die Sortierung von Objekten kann das dann einfach erweitert werden.</p>
<pre>class PersonComparator extends BaseComparator {
  public function compare($a, $b) {
    // hier Prüfung auf Typ etc.
    return parent::compare($a-&gt;getId(), $b-&gt;getId());
  }    
}</pre>
<p>Um die Sortierreihenfolge negieren zu können, können wir einen einfachen Wrapper nutzen.</p>
<pre>class ReverseOrder implements Comparator {
  private $_comparator;

  public function __construct(Comparator $comparator) {
    $this-&gt;_comparator = $comparator;
  }

  public function compare($a, $b) {
    return $this-&gt;_comparator-&gt;compare($a, $b) * -1;
  }
}</pre>
<p>Beispiel&#8230;</p>
<pre>//--
$people = array();
for ($i = 0; $i &lt; 10; $i ++) {
  $people[] = new Person();
}

echo 'BEFORE&lt;br/&gt;';
foreach($people as $person) {
  echo "$person&lt;br/&gt;";
}

$comparator = new ReverseOrder( new PersonComparator() );

uasort($people, function($a, $b) use ($comparator) {
    return $comparator-&gt;compare($a, $b);
});

// oder

uasort($people, $comparator);

echo 'AFTER&lt;br/&gt;';
foreach($people as $person) {
  echo "$person&lt;br/&gt;";
}</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2012/08/31/sortieren-mit-php5-closures-und-dem-java-comparator-pattern/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
