<?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>http://blog.ebene7.com</link>
	<description></description>
	<lastBuildDate>Mon, 30 Apr 2012 04:00:46 +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>Das &#8220;CRUD-Pattern&#8221;, oder wie Konventionen das Leben einfacher machen können</title>
		<link>http://blog.ebene7.com/2012/04/30/das-crud-pattern-oder-wie-konventionen-das-leben-einfacher-machen-koennen/</link>
		<comments>http://blog.ebene7.com/2012/04/30/das-crud-pattern-oder-wie-konventionen-das-leben-einfacher-machen-koennen/#comments</comments>
		<pubDate>Mon, 30 Apr 2012 04:00:46 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Controller]]></category>
		<category><![CDATA[CRUD]]></category>
		<category><![CDATA[Design Patterns]]></category>
		<category><![CDATA[Entwurfsmuster]]></category>
		<category><![CDATA[MVC]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=3709</guid>
		<description><![CDATA[Heute geht es wiedermal um eine alltägliche Aufgabe bei der Entwicklung von (Web-)Software: CRUD. Vielen wird es sicherlich ein Begriff sein, denn wir wenden es, wenn vielleicht auch nicht bewusst, jeden Tag an. Dabei geht es um die verschiedenen Schritte, &#8230; <a href="http://blog.ebene7.com/2012/04/30/das-crud-pattern-oder-wie-konventionen-das-leben-einfacher-machen-koennen/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Heute geht es wiedermal um eine alltägliche Aufgabe bei der Entwicklung von (Web-)Software: <a href="http://de.wikipedia.org/wiki/CRUD">CRUD</a>. Vielen wird es sicherlich ein Begriff sein, denn wir wenden es, wenn vielleicht auch nicht bewusst, jeden Tag an.</p>
<p>Dabei geht es um die verschiedenen Schritte, wie Daten bearbeitet werden können. CRUD ansich ist erstmal kein Designmuster im herkömmlichen Sinne, aber es lässt sich für verschiedene Arten von Datenmodellen eine immer wiederkehrendes Muster erkennen.</p>
<p><span id="more-3709"></span>In vielen Projekten habe ich erlebt, dass für jedes Modell oder Entity mindestens ein Kontroller implementiert wurde, um die irgendwie manipulieren und anzeigen zu können.</p>
<p>Oftmals werden bekannte und gut geprüfte Frameworks eingesetzt, um die Arbeit zu erleichtern und einheitliche Standards zu nutzen.</p>
<p>Warum also nicht auch einfach hier fertige Module nutzen oder sollte es tatsächlich nichts fertiges geben, einfach gute eigene Basiskontroller verwenden?</p>
<p>Der Ausgangspunkt ist erstmal klar und einfach: CRUD, d.h. C &#8211; create (erzeugen), R &#8211; read (lesen/anzeigen), U &#8211; update (bearbeiten) und D &#8211; delete (löschen).</p>
<p>Damit haben wir schon unsere ersten Controller-Actions zusammen. Ich halte den Code allgemein wie möglich, da sich das auf sämtliche Frameworks übertragen lässt.</p>
<pre>&lt;?php
class CrudController {
  public function indexAction() {}
  public function viewAction() {}
  public function editAction() {}
  public function deleteAction() {}
}</pre>
<p>Bei den Actions folge ich nicht ganz dem &#8220;CRUD-Muster&#8221;. Die Edit-Action vereint in diesem Beispiel &#8220;create&#8221; und &#8220;update&#8221;, da die dahinterstehende Logik oft fast identisch ist.</p>
<p>Kümmern wir uns doch aber erstmal um die einfachen Actions. Die index-Action soll uns eine Liste der verfügbaren Datensätze anzeigen.</p>
<p>Dafür laden wir eine Collection des jeweiligen Typs und rendern das passende Template. Wenn wir in der Benennung aller Klassen einer bestimmten Namenskonvention folgen, können wir z.B. vom Namen der Kontrollerklasse auf den des jeweiligen Models schließen.</p>
<pre>class CrudController {
  public function indexAction() {
    $collection = $this-&gt;getCollection();
    return $this-&gt;render( $this-&gt;getListTemplate(), $collection );
  }
}

class UserController extend CrudController() {
}</pre>
<p>Nach ähnlichem Muster würde dann auch die View-Action arbeiten. Den Namen des Templates leiten wir aus dem Klassennamen des Controllers ab. Das Wichtige und Interessante dabei ist natürlich, dass eigentlich alles im CrudController passiert und nicht immer wieder neu geschrieben werden soll. Die erbenden Controller geben dann nur noch ihren Namen her und passen hier und da etwas an.</p>
<pre>class CrudController {
  public function viewAction($id) {
    $model = $this-&gt;getModel()-&gt;find($id);
    return $this-&gt;render( $this-&gt;getViewTemplate(), array('model' =&gt; $model) );
  }
}</pre>
<p>Beim Löschen verhält es sich ähnlich einfach, nur dass hier noch ein weiterer Parameter gebraucht wird.</p>
<pre>class CrudController {
  public function deleteAction($id, $confirm = false) {
    $model = $this-&gt;getModel()-&gt;find($id);

    if(!$confirm) {
      return $this-&gt;render( $this-&gt;getDeleteConfirmTemplate(), array('model' =&gt; $model) );
    }

    $model-&gt;delete();
    return $this-&gt;render( $this-&gt;getDeleteSuccessTemplate(), array('model' =&gt; $model) );
  }
}</pre>
<p>Den meisten Aufwand haben wir beim Bearbeiten von Datensätzen.</p>
<pre>class CrudController {
  public function editAction($id = false) {
    $request = $this-&gt;getRequest();
    $form = $this-&gt;getForm();

    // model bleibt leer, wenn nichts geladen werden kann
    $model = $this-&gt;getModel()-&gt;find($id);

    if($request-&gt;isPost()) {
      if($form-&gt;isValid( $request )) {
        $model-&gt;setData( $form-&gt;getData() );
        $model-&gt;save();
        $this-&gt;setFlashMsg( 'Speichern ok' );
        return $this-&gt;redirect( $this-&gt;getListUrl() );
      }
    }

    return $this-&gt;render( $this-&gt;getEditTemplate(), array('form' =&gt; $form) );
  }
}</pre>
<p>Das Beispiel ist natürlich nicht komplett, soll aber zeigen, wieviel arbeit wir uns täglich sparen können und gleichzeitig durch einheitliche Standards ein flexibles und stabiles Produkt schaffen.</p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-center sexy-bookmarks-bg-caring-old">
<ul class="socials">
		<li class="sexy-comfeed">
			<a href="http://blog.ebene7.com/2012/04/30/das-crud-pattern-oder-wie-konventionen-das-leben-einfacher-machen-koennen/feed" rel="nofollow" class="external" title="Abonniere die Kommentare für diesen Beitrag">Abonniere die Kommentare für diesen Beitrag</a>
		</li>
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=Das+%22CRUD-Pattern%22%2C+oder+wie+Konventionen+das+Leben+einfacher+machen+k%C3%B6nnen+-+http://bit.ly/Ikk5Ia+&amp;source=shareaholic" rel="nofollow" class="external" title="Twittere diesen Artikel!">Twittere diesen Artikel!</a>
		</li>
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://blog.ebene7.com/2012/04/30/das-crud-pattern-oder-wie-konventionen-das-leben-einfacher-machen-koennen/&amp;t=Das+%22CRUD-Pattern%22%2C+oder+wie+Konventionen+das+Leben+einfacher+machen+k%C3%B6nnen" rel="nofollow" class="external" title="Empfehle diesen Artikel bei Facebook">Empfehle diesen Artikel bei Facebook</a>
		</li>
		<li class="sexy-misterwong">
			<a href="http://www.mister-wong.de/addurl/?bm_url=http://blog.ebene7.com/2012/04/30/das-crud-pattern-oder-wie-konventionen-das-leben-einfacher-machen-koennen/&amp;bm_description=Das+%22CRUD-Pattern%22%2C+oder+wie+Konventionen+das+Leben+einfacher+machen+k%C3%B6nnen&amp;plugin=sexybookmarks" rel="nofollow" class="external" title="Füge hinzu zu Mister Wong">Füge hinzu zu Mister Wong</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://blog.ebene7.com/2012/04/30/das-crud-pattern-oder-wie-konventionen-das-leben-einfacher-machen-koennen/&amp;title=Das+%22CRUD-Pattern%22%2C+oder+wie+Konventionen+das+Leben+einfacher+machen+k%C3%B6nnen" rel="nofollow" class="external" title="Empfehle diesen Artikel bei del.icio.us">Empfehle diesen Artikel bei del.icio.us</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://blog.ebene7.com/2012/04/30/das-crud-pattern-oder-wie-konventionen-das-leben-einfacher-machen-koennen/" rel="nofollow" class="external" title="Empfehle diesen Artikel bei Technorati">Empfehle diesen Artikel bei Technorati</a>
		</li>
		<li class="sexy-stumbleupon">
			<a href="http://www.stumbleupon.com/submit?url=http://blog.ebene7.com/2012/04/30/das-crud-pattern-oder-wie-konventionen-das-leben-einfacher-machen-koennen/&amp;title=Das+%22CRUD-Pattern%22%2C+oder+wie+Konventionen+das+Leben+einfacher+machen+k%C3%B6nnen" rel="nofollow" class="external" title="Bei StumbleUpon einstellen">Bei StumbleUpon einstellen</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://blog.ebene7.com/2012/04/30/das-crud-pattern-oder-wie-konventionen-das-leben-einfacher-machen-koennen/&amp;title=Das+%22CRUD-Pattern%22%2C+oder+wie+Konventionen+das+Leben+einfacher+machen+k%C3%B6nnen" rel="nofollow" class="external" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-myspace">
			<a href="http://www.myspace.com/Modules/PostTo/Pages/?u=http://blog.ebene7.com/2012/04/30/das-crud-pattern-oder-wie-konventionen-das-leben-einfacher-machen-koennen/&amp;t=Das+%22CRUD-Pattern%22%2C+oder+wie+Konventionen+das+Leben+einfacher+machen+k%C3%B6nnen" rel="nofollow" class="external" title="Sende dies zu MySpace">Sende dies zu MySpace</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://blog.ebene7.com/2012/04/30/das-crud-pattern-oder-wie-konventionen-das-leben-einfacher-machen-koennen/&amp;title=Das+%22CRUD-Pattern%22%2C+oder+wie+Konventionen+das+Leben+einfacher+machen+k%C3%B6nnen&amp;summary=Heute%20geht%20es%20wiedermal%20um%20eine%20allt%C3%A4gliche%20Aufgabe%20bei%20der%20Entwicklung%20von%20%28Web-%29Software%3A%20CRUD.%20Vielen%20wird%20es%20sicherlich%20ein%20Begriff%20sein%2C%20denn%20wir%20wenden%20es%2C%20wenn%20vielleicht%20auch%20nicht%20bewusst%2C%20jeden%20Tag%20an.%0D%0A%0D%0ADabei%20geht%20es%20um%20die%20verschiedenen%20Schritte%2C%20wie%20Daten%20bearbeitet%20werden%20k%C3%B6nnen.%20CR&amp;source=ebene7" rel="nofollow" class="external" title="Empfehle diesen Artikel bei LinkedIn">Empfehle diesen Artikel bei LinkedIn</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://blog.ebene7.com/2012/04/30/das-crud-pattern-oder-wie-konventionen-das-leben-einfacher-machen-koennen/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfony2: Einfaches Eventhandling, die Zweite&#8230;</title>
		<link>http://blog.ebene7.com/2012/03/20/symfony2-einfaches-eventhandling-die-zweite/</link>
		<comments>http://blog.ebene7.com/2012/03/20/symfony2-einfaches-eventhandling-die-zweite/#comments</comments>
		<pubDate>Tue, 20 Mar 2012 05:00:18 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[Frameworks]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Event]]></category>
		<category><![CDATA[Eventhandling]]></category>
		<category><![CDATA[Factory]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[Observer]]></category>
		<category><![CDATA[Symfony2]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=3528</guid>
		<description><![CDATA[Gesagt, getan&#8230; Wie im letzten Artikel geht es wieder um einfaches Eventhandling mit Symfony2. Trotz, oder gerade wegen, der großen Flexibilität fehlte mir die Information welches Event ausgelöst wurde. Sicherlich wird man es in der Regel wissen, da meist nur &#8230; <a href="http://blog.ebene7.com/2012/03/20/symfony2-einfaches-eventhandling-die-zweite/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Gesagt, getan&#8230; Wie im letzten Artikel geht es wieder um <a href="http://blog.ebene7.com/2012/03/19/symfony2-einfaches-eventhandling/">einfaches Eventhandling mit Symfony2</a>. Trotz, oder gerade wegen, der großen Flexibilität fehlte mir die Information welches Event ausgelöst wurde.<br />
<span id="more-3528"></span><br />
Sicherlich wird man es in der Regel wissen, da meist nur ein Event zu einer Listenermethode registriert wird, aber falls nicht, kommt man eben nicht mehr dran.</p>
<p>Als erstes habe ich eine eigene Eventklasse abgeleitet, die den Eventnamen speichern kann. Da dieser ja nun beim Dispatch irgendwie mitgegeben werden muss, hatte ich drei Möglichkeiten:</p>
<ol>
<li>Vor dem Dispatch jedesmal den Eventnamen per Setter übergeben</li>
<li>Den Dispatcher ableiten und die Methode dispatch() überschreiben</li>
<li>Meinem Event eine eigene Dispatchmethode geben</li>
</ol>
<p>Die erste Variante ist natürlich schon ausgeschieden, bevor die Idee ausgeschrieben war, da es zum einen unhandlich ist, unnötigen Code erzeugt und auch ein großes Fehlerpotential bildet.</p>
<p>Den Dispatcher zu überschreiben wäre sicher auch ein einfacher Weg gewesen, dennoch habe ich mich dann doch für die dritte Möglichkeit entschieden.</p>
<p>Eine eigene Klasse für das Event wurde ohnehin schon gebaut und so kann diese auch noch etwas mehr machen. Auf Typehints usw. habe ich für die Übersicht hier mal verzichtet.</p>
<pre>&lt;?php
namespace E7\EventDispatcher;

//use ...\EventDispatcher as ED;

class Event extends ED\Event {
  private $eventDispatcher;
  private $eventName;

  public function getEventDispatcher() {
    return $this-&gt;eventDispatcher;
  }

  public function setEventDispatcher($eventDispatcher) {
    $this-&gt;eventDispatcher = $eventDispatcher;
    return $this;
  }

  public function getEventName() {
    return $this-&gt;eventName;
  }

  public function setEventName($eventName) {
    $this-&gt;eventName = $eventName;
    return $this;
  }

  public function dispatch($eventName) {
    $this-&gt;setEventName($eventName);
    $this-&gt;getDispatcher()-&gt;dispatch($eventName, $this);
    return $this;
  }
}</pre>
<p>Viel gewonnen haben wir so aber leider nicht. Der Aufruf passiert nun direkt auf dem Event, aber statt dem Setter für den Eventnamen müssten wir nun den Setter für den EventDispatcher aufrufen.</p>
<p>Meine Lösung hierfür ist eine Factory für Eventobjekte. Das ganze schafft uns bei der Verwendung weitere Vorteile.</p>
<ol>
<li>Nur die Factory muss den EventDispatcher kennen und übergibt diesen an die Eventobjekte. Jede Änderung bei der Erzeugung der Events muss nun nur noch an einer Stelle gemacht werden.</li>
<li>Durch die Factory fällt der new-Operator weg und damit auch die Abhängigkeit zu speziellen Typen. Wir programmieren ab hier noch gegen das Interface</li>
</ol>
<p>Die Factory lässt sich entweder mit einem statischem Aufruf verwenden oder man registriert sie als Service und holt sie sich über den Container. Bei Interesse kann ich auch gerne dazu noch was schreiben.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-center sexy-bookmarks-bg-caring-old">
<ul class="socials">
		<li class="sexy-comfeed">
			<a href="http://blog.ebene7.com/2012/03/20/symfony2-einfaches-eventhandling-die-zweite/feed" rel="nofollow" class="external" title="Abonniere die Kommentare für diesen Beitrag">Abonniere die Kommentare für diesen Beitrag</a>
		</li>
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=Symfony2%3A+Einfaches+Eventhandling%2C+die+Zweite...+-+http://bit.ly/GzPDZA+&amp;source=shareaholic" rel="nofollow" class="external" title="Twittere diesen Artikel!">Twittere diesen Artikel!</a>
		</li>
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://blog.ebene7.com/2012/03/20/symfony2-einfaches-eventhandling-die-zweite/&amp;t=Symfony2%3A+Einfaches+Eventhandling%2C+die+Zweite..." rel="nofollow" class="external" title="Empfehle diesen Artikel bei Facebook">Empfehle diesen Artikel bei Facebook</a>
		</li>
		<li class="sexy-misterwong">
			<a href="http://www.mister-wong.de/addurl/?bm_url=http://blog.ebene7.com/2012/03/20/symfony2-einfaches-eventhandling-die-zweite/&amp;bm_description=Symfony2%3A+Einfaches+Eventhandling%2C+die+Zweite...&amp;plugin=sexybookmarks" rel="nofollow" class="external" title="Füge hinzu zu Mister Wong">Füge hinzu zu Mister Wong</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://blog.ebene7.com/2012/03/20/symfony2-einfaches-eventhandling-die-zweite/&amp;title=Symfony2%3A+Einfaches+Eventhandling%2C+die+Zweite..." rel="nofollow" class="external" title="Empfehle diesen Artikel bei del.icio.us">Empfehle diesen Artikel bei del.icio.us</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://blog.ebene7.com/2012/03/20/symfony2-einfaches-eventhandling-die-zweite/" rel="nofollow" class="external" title="Empfehle diesen Artikel bei Technorati">Empfehle diesen Artikel bei Technorati</a>
		</li>
		<li class="sexy-stumbleupon">
			<a href="http://www.stumbleupon.com/submit?url=http://blog.ebene7.com/2012/03/20/symfony2-einfaches-eventhandling-die-zweite/&amp;title=Symfony2%3A+Einfaches+Eventhandling%2C+die+Zweite..." rel="nofollow" class="external" title="Bei StumbleUpon einstellen">Bei StumbleUpon einstellen</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://blog.ebene7.com/2012/03/20/symfony2-einfaches-eventhandling-die-zweite/&amp;title=Symfony2%3A+Einfaches+Eventhandling%2C+die+Zweite..." rel="nofollow" class="external" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-myspace">
			<a href="http://www.myspace.com/Modules/PostTo/Pages/?u=http://blog.ebene7.com/2012/03/20/symfony2-einfaches-eventhandling-die-zweite/&amp;t=Symfony2%3A+Einfaches+Eventhandling%2C+die+Zweite..." rel="nofollow" class="external" title="Sende dies zu MySpace">Sende dies zu MySpace</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://blog.ebene7.com/2012/03/20/symfony2-einfaches-eventhandling-die-zweite/&amp;title=Symfony2%3A+Einfaches+Eventhandling%2C+die+Zweite...&amp;summary=Gesagt%2C%20getan...%20Wie%20im%20letzten%20Artikel%20geht%20es%20wieder%20um%20einfaches%20Eventhandling%20mit%20Symfony2.%20Trotz%2C%20oder%20gerade%20wegen%2C%20der%20gro%C3%9Fen%20Flexibilit%C3%A4t%20fehlte%20mir%20die%20Information%20welches%20Event%20ausgel%C3%B6st%20wurde.%0D%0A%0D%0ASicherlich%20wird%20man%20es%20in%20der%20Regel%20wissen%2C%20da%20meist%20nur%20ein%20Event%20zu%20einer%20Listenermethod&amp;source=ebene7" rel="nofollow" class="external" title="Empfehle diesen Artikel bei LinkedIn">Empfehle diesen Artikel bei LinkedIn</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://blog.ebene7.com/2012/03/20/symfony2-einfaches-eventhandling-die-zweite/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfony2: Einfaches Eventhandling</title>
		<link>http://blog.ebene7.com/2012/03/19/symfony2-einfaches-eventhandling/</link>
		<comments>http://blog.ebene7.com/2012/03/19/symfony2-einfaches-eventhandling/#comments</comments>
		<pubDate>Mon, 19 Mar 2012 05:00:21 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[Frameworks]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Event]]></category>
		<category><![CDATA[Eventhandling]]></category>
		<category><![CDATA[Observer]]></category>
		<category><![CDATA[Symfony2]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=3502</guid>
		<description><![CDATA[Beim letzten Mal habe ich ja schon über Eventregistrierung über Annotations mit Symfony2 geschrieben und will heute an das Thema Eventhandling anknüpfen. Der Umgang mit dem Symfony2 Eventhandling ist wie schon erwähnt sehr einfach und flexibel und das macht wirklich &#8230; <a href="http://blog.ebene7.com/2012/03/19/symfony2-einfaches-eventhandling/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Beim letzten Mal habe ich ja schon über <a href="http://blog.ebene7.com/2012/02/27/symfony2-event-listener-ueber-annotations-registrieren/">Eventregistrierung über Annotations</a> mit Symfony2 geschrieben und will heute an das Thema Eventhandling anknüpfen.</p>
<p>Der Umgang mit dem Symfony2 Eventhandling ist wie schon erwähnt sehr einfach und flexibel und das macht wirklich Freude damit zu arbeiten.<br />
<span id="more-3502"></span><br />
Aktuell habe ich es mit verschiedenen Datenmodellen zu tun, die zwar irgendwie miteinander zu tun haben, jedoch über keine direkte Verbindung verfügen. Jedes dieser Datenmodelle kann geladen, gespeichert und auch wieder gelöscht werden.</p>
<p>Zu jeder Aktion gehört noch ein Zeitpunkt, d.h. der oder die Listener können vorher oder nachher benachrichtigt werden und beim Speichern wollen unsere Listener vielleicht sogar wissen, ob der Datensatz neu erstellt wurde oder ob es sich nur um ein Update handelt.</p>
<p>Diese Anforderungen sind ansich recht übersichtlich, aber doch komplex genug, um ein wenig darüber zu schreiben.</p>
<p>Alle Modelle werden durch ein Resource-Modell verarbeitet und an dieser Stelle werden auch die Events ausgelöst. Es gibt für jede Aktion eine eigene EventKlasse die von einer ModelEvent-Klasse erbt und diese wiederum von Symfony-Event.</p>
<pre>                        +-------------+
                        |    Event    |
                        +-------------+
                               |
                      +-----------------+
                      |    ModelEvent   |
                      +-----------------+
                      | get/setModel()  |
                      +-----------------+
                               |
         +---------------------+----------------------+
         |                     |                      |
+-----------------+   +-----------------+   +-------------------+
| ModelFindEvent  |   | ModelSaveEvent  |   | ModelDeleteEvent  |
+-----------------+   +-----------------+   +-------------------+
                      | - bool:isNew    |
                      | bool:isCreate() |
                      | bool:isUpdate() |
                      +-----------------+</pre>
<p>Mein einfaches ASCI-Art UML verrät ja nun auch schon ein wenig darüber, wie die Aufgaben im System verteilt werden. Da beim Speichern das meiste passiert, sehen wir uns einfach mal die Save-Methode des Resourcen-Modells an. Die verwendeten Methoden, z.B. triggerEvent() sind in den Elternklassen definiert und nutzen den globalen Event-Dispatcher.</p>
<pre>&lt;?php
// ...
public function save(Model\Model $model) {
    $event = new Event\ModelSaveEvent($model);

    $this-&gt;triggerEvent('model.save.before', $event);
    $this-&gt;executeSave($model);
    $this-&gt;triggerEvent('model.save.after', $event);

    return $this;
}
// ...</pre>
<p>Zuerst wird ein ModelSaveEvent-Object mit der Modelinstanz erzeugt und das erste Event (model.save.before) ausgelöst. Die ModelSaveEvent-Klasse erkennt nun anhand einer Methode im Model, ob dieses neu ist oder ein weiteres Mal gespeichert werden soll und merkt sich diesen anfänglichen Zustand. Dadurch kann dann auch nach dem Speichern noch festgestellt werden was passiert ist.</p>
<p>Danach wird eine protected Methode executeSave() aufgerufen die sich um die eigentliche Arbeit kümmert und anschliessend wird das zweite Event (model.save.after) ausgelöst.</p>
<p>Was haben wir dadurch nun erreicht? Wie ich im letzten Artikel schon beschrieben habe, lassen sich ja ganz einfach mehrere Events von einem Listener überwachen.</p>
<p>In der jeweiligen Methode könnten wir dann allgemein auf alle ModelEvents reagieren oder auch nur auf spezielle. Da wir mit dem Event auch eine Modelinstanz übergeben, können wir auch hier anhand des Types weitere Unterscheidungen machen, falls wir das müssen.</p>
<p>Leider geht uns bei einer Methode für alles das auslösende Event (z.B. &#8220;model.save.before&#8221;) verloren und damit auch der Zeitpunkt, wann was passiert ist.</p>
<p>Hier fände ich es angenehm, wenn der Symfony-Event-Dispatcher diese Information mit den Events mitgeben würde, aber man kann ja nicht alles haben und zur Not baut man es eben selbst dran. <img src='http://blog.ebene7.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>&nbsp;</p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-center sexy-bookmarks-bg-caring-old">
<ul class="socials">
		<li class="sexy-comfeed">
			<a href="http://blog.ebene7.com/2012/03/19/symfony2-einfaches-eventhandling/feed" rel="nofollow" class="external" title="Abonniere die Kommentare für diesen Beitrag">Abonniere die Kommentare für diesen Beitrag</a>
		</li>
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=Symfony2%3A+Einfaches+Eventhandling+-+http://bit.ly/AeT6Tb+&amp;source=shareaholic" rel="nofollow" class="external" title="Twittere diesen Artikel!">Twittere diesen Artikel!</a>
		</li>
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://blog.ebene7.com/2012/03/19/symfony2-einfaches-eventhandling/&amp;t=Symfony2%3A+Einfaches+Eventhandling" rel="nofollow" class="external" title="Empfehle diesen Artikel bei Facebook">Empfehle diesen Artikel bei Facebook</a>
		</li>
		<li class="sexy-misterwong">
			<a href="http://www.mister-wong.de/addurl/?bm_url=http://blog.ebene7.com/2012/03/19/symfony2-einfaches-eventhandling/&amp;bm_description=Symfony2%3A+Einfaches+Eventhandling&amp;plugin=sexybookmarks" rel="nofollow" class="external" title="Füge hinzu zu Mister Wong">Füge hinzu zu Mister Wong</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://blog.ebene7.com/2012/03/19/symfony2-einfaches-eventhandling/&amp;title=Symfony2%3A+Einfaches+Eventhandling" rel="nofollow" class="external" title="Empfehle diesen Artikel bei del.icio.us">Empfehle diesen Artikel bei del.icio.us</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://blog.ebene7.com/2012/03/19/symfony2-einfaches-eventhandling/" rel="nofollow" class="external" title="Empfehle diesen Artikel bei Technorati">Empfehle diesen Artikel bei Technorati</a>
		</li>
		<li class="sexy-stumbleupon">
			<a href="http://www.stumbleupon.com/submit?url=http://blog.ebene7.com/2012/03/19/symfony2-einfaches-eventhandling/&amp;title=Symfony2%3A+Einfaches+Eventhandling" rel="nofollow" class="external" title="Bei StumbleUpon einstellen">Bei StumbleUpon einstellen</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://blog.ebene7.com/2012/03/19/symfony2-einfaches-eventhandling/&amp;title=Symfony2%3A+Einfaches+Eventhandling" rel="nofollow" class="external" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-myspace">
			<a href="http://www.myspace.com/Modules/PostTo/Pages/?u=http://blog.ebene7.com/2012/03/19/symfony2-einfaches-eventhandling/&amp;t=Symfony2%3A+Einfaches+Eventhandling" rel="nofollow" class="external" title="Sende dies zu MySpace">Sende dies zu MySpace</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://blog.ebene7.com/2012/03/19/symfony2-einfaches-eventhandling/&amp;title=Symfony2%3A+Einfaches+Eventhandling&amp;summary=Beim%20letzten%20Mal%20habe%20ich%20ja%20schon%20%C3%BCber%20Eventregistrierung%20%C3%BCber%20Annotations%20mit%20Symfony2%20geschrieben%20und%20will%20heute%20an%20das%20Thema%20Eventhandling%20ankn%C3%BCpfen.%0D%0A%0D%0ADer%20Umgang%20mit%20dem%20Symfony2%20Eventhandling%20ist%20wie%20schon%20erw%C3%A4hnt%20sehr%20einfach%20und%20flexibel%20und%20das%20macht%20wirklich%20Freude%20damit%20zu%20arbeiten.%0D&amp;source=ebene7" rel="nofollow" class="external" title="Empfehle diesen Artikel bei LinkedIn">Empfehle diesen Artikel bei LinkedIn</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://blog.ebene7.com/2012/03/19/symfony2-einfaches-eventhandling/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Symfony2: Event-Listener über Annotations registrieren</title>
		<link>http://blog.ebene7.com/2012/02/27/symfony2-event-listener-ueber-annotations-registrieren/</link>
		<comments>http://blog.ebene7.com/2012/02/27/symfony2-event-listener-ueber-annotations-registrieren/#comments</comments>
		<pubDate>Mon, 27 Feb 2012 05:00:04 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[Frameworks]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Annotations]]></category>
		<category><![CDATA[Eventhandling]]></category>
		<category><![CDATA[Observer]]></category>
		<category><![CDATA[Reflection]]></category>
		<category><![CDATA[Symfony2]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=3449</guid>
		<description><![CDATA[In den letzten Monaten habe ich hier leider nicht sehr viel geschrieben und freue mich daher um so mehr, wenn ich dann mal wieder über ein spanndendes Thema schreiben kann. So dann auch, wie ich finde, heute. Es geht um &#8230; <a href="http://blog.ebene7.com/2012/02/27/symfony2-event-listener-ueber-annotations-registrieren/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In den letzten Monaten habe ich hier leider nicht sehr viel geschrieben und freue mich daher um so mehr, wenn ich dann mal wieder über ein spanndendes Thema schreiben kann. So dann auch, wie ich finde, heute.</p>
<p>Es geht um zwei einfache, aber zugleich sehr nützliche Dinge, die das PHP-Framework Symfony2 mitbringt: Ein einfaches, flexibles Event-Handling und Annotations.<span id="more-3449"></span></p>
<p>Für mich waren die letzten drei Wochen auch die ersten Gehversuche mit Symfony2 und bislang wurden alle meine Erwartungen bestätigt. Das Framework ist sehr flexibel, aber auch recht komplex. Wer allerdings andere MVC-Frameworks wie Zend kennt, der wird sich auch hier schnell zurecht finden.</p>
<p>So, genug Lob an der Stelle. Neben der positiven Eigenschafft eines Eventhandlingsystems fiel mir auch gleich die Art auf, wie sich in Symfony2 Controllerrouten mit Annotations konfigurieren lassen.</p>
<p>Leider habe ich nichts Vergleichbares für Eventlistener gefunden und die klassische Konfiguration über YML gefiel mir dann auch nicht mehr so recht. Das nahm ich dann also gleich mal als praxisnahes Kennenlernbeispiel her und habe mir da was gebaut.</p>
<p>Als erstes braucht es immer einen Auslöser, damit die Annotations verarbeitet werden. Dafür habe ich mich an das Event &#8220;kernel.request&#8221; gehängt, das noch vor dem Kontrolleraufruf verarbeitet werden kann.</p>
<p>Einen speziellen Listener hatte ich erst dazwischen, habe es dann später aber wieder etwas vereinfacht. Mein Code entspricht vielleicht nicht allen Symfony-Richtlinien, aber zum Arbeiten und Erklären reicht es aus.</p>
<p>Zum Verarbeiten der Annotations habe ich eine einfache Klasse aufgebaut und mich dabei an den &#8220;Route()&#8221;-Annotations orientiert. Die Methode &#8220;findClass()&#8221; ist aus bestehendem Code &#8220;recycled&#8221;, da sie anders schwerer erreichbar wäre.</p>
<pre>&lt;?php
namespace MyNamespace\Annotations;

use Doctrine\Common\Annotations\Reader;
use Symfony\Component\EventDispatcher\EventDispatcher;

class AnnotatedEventClassLoader
{
  private $reader;
  private $eventDispatcher;
  private $eventAnnotationClass  = 'MyNamespace\\Annotations\\Event';

  /**
   * Constructor
   *
   * @param    Reader $reader
   * @param    EventDispatcher $eventDispatcher
   * @return    void
   */
  public function __construct(
    Reader $reader, EventDispatcher $eventDispatcher) {
    $this-&gt;reader = $reader;
    $this-&gt;eventDispatcher = $eventDispatcher;
  }

  public function init() {
    $listenersDir = realpath(__DIR__ . '/../../Listener');

    $iterator = new \RecursiveIteratorIterator(
      new \RecursiveDirectoryIterator($listenersDir),
        \RecursiveIteratorIterator::LEAVES_ONLY);

    foreach ($iterator as $file) {
      if (!$file-&gt;isFile() || '.php' !== substr($file-&gt;getFilename(), -4)) {
        continue;
      }

      if ($class = $this-&gt;findClass($file)) {
        $reflClass = new \ReflectionClass($class);
        if ($reflClass-&gt;isAbstract()) { continue; }

        foreach($reflClass-&gt;getMethods() as $method) {
          $annotation = $this-&gt;reader-&gt;getMethodAnnotation($method, $this-&gt;eventAnnotationClass);
          if (!$annotation instanceof Event || empty($annotation)) { continue; }
          $this-&gt;registerEvents($annotation, $class, $method-&gt;getName());
        }
      }
    }
  }

  /**
   *
   * @param    \MyNamespace\Annotations\Event $eventAnnotation
   * @param    string|object $class
   * @param    string $method
   * @return   \MyNamespace\Annotations\AnnotatedEventClassLoader
   */
  public function registerEvents($eventAnnotation, $class, $method) {
    $listener = is_object($class) ? $class : new $class();

    foreach ($eventAnnotation-&gt;getEvents() as $event) {
      $this-&gt;eventDispatcher-&gt;addListener(
        $event, array($listener, $method), $eventAnnotation-&gt;getPriority()
      );
    }
    return $this;
  }

  /**
   * Returns the full class name for the first class in the file.
   *
   * @param string $file A PHP file path
   *
   * @return string|false Full class name if found, false otherwise
   */
  protected function findClass($file) {
    $class = false;
    $namespace = false;
    $tokens = token_get_all(file_get_contents($file));
    for ($i = 0, $count = count($tokens); $i &lt; $count; $i++) {
      $token = $tokens[$i];

      if (!is_array($token)) { continue; }

      if (true === $class &amp;&amp; T_STRING === $token[0]) {
        return $namespace.'\\'.$token[1];
      }

      if (true === $namespace &amp;&amp; T_STRING === $token[0]) {
        $namespace = '';
        do {
          $namespace .= $token[1];
          $token = $tokens[++$i];
         } while ($i &lt; $count &amp;&amp; is_array($token) &amp;&amp; in_array($token[0], array(T_NS_SEPARATOR, T_STRING)));
       }

       if (T_CLASS === $token[0]) {
         $class = true;
       }

       if (T_NAMESPACE === $token[0]) {
         $namespace = true;
       }
     }

     return false;
   }
}</pre>
<p>Damit der Loader später auch seinen Dienst tut, muss er noch als Listener für das &#8220;kernel.request&#8221;-Event bekannt gemacht werden. Dafür habe ich die Datei &#8220;app/config/annotations.xml&#8221; mit folgendem Inhalt angelegt.</p>
<pre>&lt;?xml version="1.0" ?&gt;

&lt;container xmlns="http://symfony.com/schema/dic/services"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"&gt;

  &lt;parameters&gt;
    &lt;parameter key="myapp.event.loader.class"&gt;MyNamespace\Annotations\AnnotatedEventClassLoader&lt;/parameter&gt;
  &lt;/parameters&gt;

  &lt;services&gt;
    &lt;service id="myapp.event.loader"&gt;
      &lt;tag name="kernel.event_listener" event="kernel.request" method="init" /&gt;
      &lt;argument type="service" id="annotation_reader" /&gt;
      &lt;argument type="service" id="event_dispatcher" /&gt;
    &lt;/service&gt;
  &lt;/services&gt;
&lt;/container&gt;</pre>
<p>Die Konfiguration muss dann auch noch der AppKernel-Klasse mitgeteilt werden und damit ist der Loader eingebunden.</p>
<pre>class AppKernel extends Kernel {
  // other methods...

  public function registerContainerConfiguration(LoaderInterface $loader) {
    // ...
    $loader-&gt;load(__DIR__ . '/config/annotations.xml');
  }
}</pre>
<p>Annotations werden durch eigene Klassen verarbeitet und können dadurch mit beliebiger Logik versehen werden. Alles was einer Annotation als Parameter mitgegeben wird, bekommt die Klasse als Array im Constructor übergeben.</p>
<p>Für die Registrierung von Eventlistener brauchte ich nur die Events, die hier kommasepariert übergeben werden und gegebenenfalls noch die Priotität, in dem Fall optional. Die Klasse selber wird auch durch eine Annotation als solche gekennzeichnet.</p>
<pre>&lt;?php
namespace MyNamespace\Annotations;

/**
 * @Annotation
 */
class Event {
  private $events = array();
  private $priority = 0;

  public function __construct($options) {
    if (isset($options['value'])) {        
      $this-&gt;setEvents($options['value']);
    }

    $this-&gt;setPriority(
      isset($options['priority']) ? $options['priority'] : 0 );
  }

  public function getEvents() {
    return $this-&gt;events;
  }

  public function setEvents($events) {
    if(!is_array($events)) {
      $events = array_map('trim', explode(',', $events));
    }
    $this-&gt;events = $events;
    return $this;
  }

  public function getPriority() {
    return $this-&gt;priority;
  }

  public function setPriority($priority) {
    $this-&gt;priority = (int)$priority;
      return $this;
  }
}</pre>
<p>Nun sollte alles an PHP-Code und Konfiguration an seinem Platz sein, aber wie funktioniert das jetzt genau?</p>
<p>Durch das Event wird der Loader benachrichtigt, dass die Listener initialisiert werden sollen. Dazu wird das Verzeichnis &#8220;Listener&#8221; nach Klassen mit Annotations durchsucht, welche dann von der Annotation-Event-Klasse verarbeitet werden. Innerhalb des Loader werden dann die Listener für die Events registriert und können von da an verwendet werden.</p>
<p>Die Untersuchung des PHP-Codes funktioniert mit Reflections, was ansich immer den Ruf hat langsam zu sein. Der AnnotationReader verfügt über ein eigenes Caching und macht sich daher zeitlich nicht negativ bemerkbar.</p>
<p>Der Loader durchsucht das gesamte Verzeichnis in beliebiger Tiefe nach Dateien, daher bleibt man in der Namensvergabe frei.</p>
<p>Ein Listener könnte dann zum Beispiel so aussehen:</p>
<pre>&lt;?php
namespace MyNamespace\Bundle\Listener\Deep\Folder\Structure\Test;

use MyNamespace\Annotations\Event;

class Listener {
    /**
     * @Event("foo.bar, bar.foo", priority="1")
     * @param type $event
     */
    public function onFooBar1($event) {
        echo __METHOD__;
    }

    /**
     * @Event("foo.bar", priority="20")
     * @param type $event
     */
    public function onFooBar2($event) {
        echo __METHOD__;
    }
}</pre>
<p>Ein Aufruf aus dem Kontroller funktioniert dann wie gewohnt über den EventDispatcher, der fast überall als Service erreichbar ist.</p>
<pre>public function indexAction() {        
  $this-&gt;get('event_dispatcher')-&gt;dispatch('foo.bar');
}

// oder</pre>
<pre>public function indexAction() {
  $someEvent = new SomeEvent();       
  $this-&gt;get('event_dispatcher')-&gt;dispatch('foo.bar', $someEvent);
}</pre>
<p>Wie gesagt sind das meine ersten Versuche mit Symfony und der Code ist nicht optimiert. Die Funktionen des Loaders sollten noch weiter in Unterobjekte verteilt werden, damit das ganze noch flexibler wird und auch der gecodete Teil mit dem Verzeichnisnamen ist verbesserungfähig.</p>
<p>Ich konnte dabei wieder ein paar Sachen lernen und vielleich spart es ja dem einen oder anderen von euch etwas Zeit, falls ihr das braucht.</p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-center sexy-bookmarks-bg-caring-old">
<ul class="socials">
		<li class="sexy-comfeed">
			<a href="http://blog.ebene7.com/2012/02/27/symfony2-event-listener-ueber-annotations-registrieren/feed" rel="nofollow" class="external" title="Abonniere die Kommentare für diesen Beitrag">Abonniere die Kommentare für diesen Beitrag</a>
		</li>
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=Symfony2%3A+Event-Listener+%C3%BCber+Annotations+registrieren+-+http://bit.ly/Aevpyd+&amp;source=shareaholic" rel="nofollow" class="external" title="Twittere diesen Artikel!">Twittere diesen Artikel!</a>
		</li>
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://blog.ebene7.com/2012/02/27/symfony2-event-listener-ueber-annotations-registrieren/&amp;t=Symfony2%3A+Event-Listener+%C3%BCber+Annotations+registrieren" rel="nofollow" class="external" title="Empfehle diesen Artikel bei Facebook">Empfehle diesen Artikel bei Facebook</a>
		</li>
		<li class="sexy-misterwong">
			<a href="http://www.mister-wong.de/addurl/?bm_url=http://blog.ebene7.com/2012/02/27/symfony2-event-listener-ueber-annotations-registrieren/&amp;bm_description=Symfony2%3A+Event-Listener+%C3%BCber+Annotations+registrieren&amp;plugin=sexybookmarks" rel="nofollow" class="external" title="Füge hinzu zu Mister Wong">Füge hinzu zu Mister Wong</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://blog.ebene7.com/2012/02/27/symfony2-event-listener-ueber-annotations-registrieren/&amp;title=Symfony2%3A+Event-Listener+%C3%BCber+Annotations+registrieren" rel="nofollow" class="external" title="Empfehle diesen Artikel bei del.icio.us">Empfehle diesen Artikel bei del.icio.us</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://blog.ebene7.com/2012/02/27/symfony2-event-listener-ueber-annotations-registrieren/" rel="nofollow" class="external" title="Empfehle diesen Artikel bei Technorati">Empfehle diesen Artikel bei Technorati</a>
		</li>
		<li class="sexy-stumbleupon">
			<a href="http://www.stumbleupon.com/submit?url=http://blog.ebene7.com/2012/02/27/symfony2-event-listener-ueber-annotations-registrieren/&amp;title=Symfony2%3A+Event-Listener+%C3%BCber+Annotations+registrieren" rel="nofollow" class="external" title="Bei StumbleUpon einstellen">Bei StumbleUpon einstellen</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://blog.ebene7.com/2012/02/27/symfony2-event-listener-ueber-annotations-registrieren/&amp;title=Symfony2%3A+Event-Listener+%C3%BCber+Annotations+registrieren" rel="nofollow" class="external" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-myspace">
			<a href="http://www.myspace.com/Modules/PostTo/Pages/?u=http://blog.ebene7.com/2012/02/27/symfony2-event-listener-ueber-annotations-registrieren/&amp;t=Symfony2%3A+Event-Listener+%C3%BCber+Annotations+registrieren" rel="nofollow" class="external" title="Sende dies zu MySpace">Sende dies zu MySpace</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://blog.ebene7.com/2012/02/27/symfony2-event-listener-ueber-annotations-registrieren/&amp;title=Symfony2%3A+Event-Listener+%C3%BCber+Annotations+registrieren&amp;summary=In%20den%20letzten%20Monaten%20habe%20ich%20hier%20leider%20nicht%20sehr%20viel%20geschrieben%20und%20freue%20mich%20daher%20um%20so%20mehr%2C%20wenn%20ich%20dann%20mal%20wieder%20%C3%BCber%20ein%20spanndendes%20Thema%20schreiben%20kann.%20So%20dann%20auch%2C%20wie%20ich%20finde%2C%20heute.%0D%0A%0D%0AEs%20geht%20um%20zwei%20einfache%2C%20aber%20zugleich%20sehr%20n%C3%BCtzliche%20Dinge%2C%20die%20das%20PHP-Framework%20Sy&amp;source=ebene7" rel="nofollow" class="external" title="Empfehle diesen Artikel bei LinkedIn">Empfehle diesen Artikel bei LinkedIn</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://blog.ebene7.com/2012/02/27/symfony2-event-listener-ueber-annotations-registrieren/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>CakePHP: Model innerhalb eines anderen Models verwenden</title>
		<link>http://blog.ebene7.com/2012/02/02/cakephp-model-innerhalb-eines-anderen-models-verwenden/</link>
		<comments>http://blog.ebene7.com/2012/02/02/cakephp-model-innerhalb-eines-anderen-models-verwenden/#comments</comments>
		<pubDate>Thu, 02 Feb 2012 15:30:55 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[Frameworks]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Snippets]]></category>
		<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[Model]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=3431</guid>
		<description><![CDATA[Um ein Model im Cake-Framework innerhalb eines anderen Models nutzen zu können, muss dieses offensichtlich manuell instantiiert werden. &#60;?php App::import('model','Bar'); class Foo extends AppModel { public $Bar;            public function __construct($id = false, $table = null, $ds &#8230; <a href="http://blog.ebene7.com/2012/02/02/cakephp-model-innerhalb-eines-anderen-models-verwenden/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Um ein Model im Cake-Framework innerhalb eines anderen Models nutzen zu können, muss dieses offensichtlich manuell instantiiert werden.</p>
<pre>&lt;?php
App::import('model','Bar');

class Foo extends AppModel {
  public $Bar;
        
  public function __construct($id = false, $table = null, $ds = null) {
    parent::__construct($id, $table, $ds);
    $this-&gt;Bar = new Bar();
  }      
}</pre>
<p>Danach wie gewohnt aufrufen.</p>
<pre>&lt;?php
$this-&gt;Bar-&gt;find();</pre>
<p>&nbsp;</p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-center sexy-bookmarks-bg-caring-old">
<ul class="socials">
		<li class="sexy-comfeed">
			<a href="http://blog.ebene7.com/2012/02/02/cakephp-model-innerhalb-eines-anderen-models-verwenden/feed" rel="nofollow" class="external" title="Abonniere die Kommentare für diesen Beitrag">Abonniere die Kommentare für diesen Beitrag</a>
		</li>
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=CakePHP%3A+Model+innerhalb+eines+anderen+Models+verwenden+-+http://bit.ly/AjD6YU+&amp;source=shareaholic" rel="nofollow" class="external" title="Twittere diesen Artikel!">Twittere diesen Artikel!</a>
		</li>
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://blog.ebene7.com/2012/02/02/cakephp-model-innerhalb-eines-anderen-models-verwenden/&amp;t=CakePHP%3A+Model+innerhalb+eines+anderen+Models+verwenden" rel="nofollow" class="external" title="Empfehle diesen Artikel bei Facebook">Empfehle diesen Artikel bei Facebook</a>
		</li>
		<li class="sexy-misterwong">
			<a href="http://www.mister-wong.de/addurl/?bm_url=http://blog.ebene7.com/2012/02/02/cakephp-model-innerhalb-eines-anderen-models-verwenden/&amp;bm_description=CakePHP%3A+Model+innerhalb+eines+anderen+Models+verwenden&amp;plugin=sexybookmarks" rel="nofollow" class="external" title="Füge hinzu zu Mister Wong">Füge hinzu zu Mister Wong</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://blog.ebene7.com/2012/02/02/cakephp-model-innerhalb-eines-anderen-models-verwenden/&amp;title=CakePHP%3A+Model+innerhalb+eines+anderen+Models+verwenden" rel="nofollow" class="external" title="Empfehle diesen Artikel bei del.icio.us">Empfehle diesen Artikel bei del.icio.us</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://blog.ebene7.com/2012/02/02/cakephp-model-innerhalb-eines-anderen-models-verwenden/" rel="nofollow" class="external" title="Empfehle diesen Artikel bei Technorati">Empfehle diesen Artikel bei Technorati</a>
		</li>
		<li class="sexy-stumbleupon">
			<a href="http://www.stumbleupon.com/submit?url=http://blog.ebene7.com/2012/02/02/cakephp-model-innerhalb-eines-anderen-models-verwenden/&amp;title=CakePHP%3A+Model+innerhalb+eines+anderen+Models+verwenden" rel="nofollow" class="external" title="Bei StumbleUpon einstellen">Bei StumbleUpon einstellen</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://blog.ebene7.com/2012/02/02/cakephp-model-innerhalb-eines-anderen-models-verwenden/&amp;title=CakePHP%3A+Model+innerhalb+eines+anderen+Models+verwenden" rel="nofollow" class="external" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-myspace">
			<a href="http://www.myspace.com/Modules/PostTo/Pages/?u=http://blog.ebene7.com/2012/02/02/cakephp-model-innerhalb-eines-anderen-models-verwenden/&amp;t=CakePHP%3A+Model+innerhalb+eines+anderen+Models+verwenden" rel="nofollow" class="external" title="Sende dies zu MySpace">Sende dies zu MySpace</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://blog.ebene7.com/2012/02/02/cakephp-model-innerhalb-eines-anderen-models-verwenden/&amp;title=CakePHP%3A+Model+innerhalb+eines+anderen+Models+verwenden&amp;summary=Um%20ein%20Model%20im%20Cake-Framework%20innerhalb%20eines%20anderen%20Models%20nutzen%20zu%20k%C3%B6nnen%2C%20muss%20dieses%20offensichtlich%20manuell%20instantiiert%20werden.%0D%0A%26lt%3B%3Fphp%0D%0AApp%3A%3Aimport%28%27model%27%2C%27Bar%27%29%3B%0D%0A%0D%0Aclass%20Foo%20extends%20AppModel%20%7B%0D%0A%20%20public%20%24Bar%3B%0D%0A%C2%A0%C2%A0%20%C2%A0%C2%A0%C2%A0%20%C2%A0%0D%0A%C2%A0%20public%20function%20__construct%28%24id%20%3D%20false%2C%20%24table%20%3D%20null%2C%20&amp;source=ebene7" rel="nofollow" class="external" title="Empfehle diesen Artikel bei LinkedIn">Empfehle diesen Artikel bei LinkedIn</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://blog.ebene7.com/2012/02/02/cakephp-model-innerhalb-eines-anderen-models-verwenden/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Closures in PHP</title>
		<link>http://blog.ebene7.com/2012/01/30/closures-in-php/</link>
		<comments>http://blog.ebene7.com/2012/01/30/closures-in-php/#comments</comments>
		<pubDate>Mon, 30 Jan 2012 05:00:58 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Callback]]></category>
		<category><![CDATA[Closure]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[SPL]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=3364</guid>
		<description><![CDATA[Ab der Version 5.3 bietet auch PHP, wie auch schon viele andere Sprachen, die Möglichkeit mit anonymen Funktionen zu arbeiten. Dadurch können z.B. Callback-Funktionen zur Filterung o.Ä. implementiert werden, ohne dass man sich dafür tolle Namen ausdenken muss. Aber was &#8230; <a href="http://blog.ebene7.com/2012/01/30/closures-in-php/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Ab der Version 5.3 bietet auch PHP, wie auch schon viele andere Sprachen, die Möglichkeit mit <a href="http://www.php.net/manual/de/functions.anonymous.php" target="_blank">anonymen Funktionen</a> zu arbeiten. Dadurch können z.B. Callback-Funktionen zur Filterung o.Ä. implementiert werden, ohne dass man sich dafür tolle Namen ausdenken muss. Aber was kann man damit noch machen?</p>
<p><span id="more-3364"></span>Bislang musste man Callback-Funktionen gewöhnlich definieren, bevor man sie verwenden konnte.</p>
<pre>&lt;?php
function myCallback($output) {
  return '##' . $output . '##';
}

echo call_user_func('myCallback', 'Hallo Welt');

// Ausgabe:
##Hallo Welt##</pre>
<p>Als Closure geschrieben sähe das dann so aus:</p>
<pre>&lt;?php
echo call_user_func(
  function($output) { return '##' . $output . '##'; },
  'Hallo Welt');

// Ausgabe:
##Hallo Welt##</pre>
<p>Zugegeben, dieses Beispiel hätte man durch einfache Stringverkettung wesentlich einfacher schreiben können und eigentlich war das mit <a href="http://de2.php.net/manual/de/function.create-function.php" target="_blank">create_function()</a> auch schon unter PHP4 möglich.</p>
<p>Wir können die Funktion natürlich wie früher auch schon in einer Variablen speichern und dann weiter verwenden.</p>
<pre>&lt;?php
$myFunction = function($output) {
  return '##' . $output . '##';
};

echo call_user_func($myFunction, 'Hallo Welt') . '&lt;br/&gt;';
echo $myFunction('Hallo Welt') . '&lt;br/&gt;';

//Ausgabe:
##Hallo Welt##
##Hallo Welt##</pre>
<p>Und auch das ist ja noch nichts Neues. Mit Closures haben wir nun aber auch die Möglichkeit, teile unserer &#8220;Umgebung&#8221; zum Zeitpunkt der Funktionsdefinition zu konservieren.</p>
<p>Dazu müssen wir nur die Definition etwas erweitern.</p>
<pre>&lt;?php
$before = '&gt;';
$after = '&lt;';

$myFunction = function($output) use ($before, $after) {
    return $before . $output . $after;
};

echo $myFunction('Hallo Welt') . '&lt;br/&gt;';

//Ausgabe:
&gt;Hallo Welt&lt;</pre>
<p>An dieser Stelle frieren wir mit &#8220;use&#8221; sozusagen die Werte für $before und $after innerhalb unserer Funktion ein. Spätere Änderungen der beiden Variablen haben keine Auswirkungen auf die Funktion.</p>
<pre>$before = 'foo';
$after = 'bar';
echo $myFunction('Hallo Welt') . '&lt;br/&gt;';

//Ausgabe:
&gt;Hallo Welt&lt;</pre>
<p>In PHP wir mittlerweile sehr viel mit Standardinterfaces und -klassen (SPL) abgedeckt und so ist es auch in diesem Fall. In der Variablen $myFunction ist ein Objekt vom Typ &#8220;<a href="http://de2.php.net/manual/en/class.closure.php" target="_blank">Closure</a>&#8221; gespeichert.</p>
<pre>&lt;?php
echo '&lt;pre&gt;' . print_r($myFunction, true) . '&lt;/pre&gt;';

//Ausgabe:
Closure Object
(
  [static] =&gt; Array
    (
      [before] =&gt; &gt;
      [after] =&gt; &lt;
    )
  [parameter] =&gt; Array
    (
      [$output] =&gt;
    )
)</pre>
<p>Will man eigene Objekte wie Funktionen aufrufen, dann geht das mit der magischen Methode <a href="http://de2.php.net/manual/de/language.oop5.magic.php#language.oop5.magic.invoke" target="_blank">__invoke()</a>, die auch hier verwendet wird.</p>
<p>Anfangs erwähnte ich, dass Closure-Callbacks zur Filterung, aber auch zur Manipulation von Array verwendet werden können.</p>
<p>Wenn nur der Inhalt interessant ist, dann kommen wir mit array_map() und einem Parameter aus.</p>
<pre>&lt;?php
$values = array(
  array(
    'a' =&gt; array(
      'b' =&gt; 'foo'
    )
  ),
  array(
    'a' =&gt; array(
      'b' =&gt; 'bar'
    )
  ),
);

$filtered = array_map(
  function ($item) { return $item['a']['b']; },
  $values
);
echo '&lt;pre&gt;' . print_r($filtered, true) . '&lt;/pre&gt;';

// Ausgabe:
Array
(
  [0] =&gt; foo
  [1] =&gt; bar
)</pre>
<p>Wollen wir aber Werte im Array in Abhängigkeit zum Key/Index verändern, dann geht das mit array_walk und einem zweiten Parameter im Callback. Bei beiden kann natürlich auch &#8220;use&#8221; verwendet werden. Der Parameter $value wird dabei als Referenz übernommen.</p>
<pre>$values = array(
  'a' =&gt; 100,
  'b' =&gt; 200,
  'c' =&gt; 300,
);

array_walk(
  $values,
  function (&amp;$value, $key) {
    if ('b' == $key) {
      $value = 42;
    }
  }
);

echo '&lt;pre&gt;' . print_r($values, true) . '&lt;/pre&gt;';

// Ausgabe:
Array
(
  [a] =&gt; 100
  [b] =&gt; 42
  [c] =&gt; 300
)</pre>
<p>Ich hoffe, dass ich ein wenig Licht ins Dunkel bringen konnte und &#8220;Closure&#8221; nun kein geheimnisvolles Zauberwort mehr ist.</p>
<p>Wenn ihr noch gute Ergänzungen oder Anwendungbeispiele habt, dann immer her damit und bitte fleissig kommentieren. <img src='http://blog.ebene7.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-center sexy-bookmarks-bg-caring-old">
<ul class="socials">
		<li class="sexy-comfeed">
			<a href="http://blog.ebene7.com/2012/01/30/closures-in-php/feed" rel="nofollow" class="external" title="Abonniere die Kommentare für diesen Beitrag">Abonniere die Kommentare für diesen Beitrag</a>
		</li>
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=Closures+in+PHP+-+http://bit.ly/wcKw56+&amp;source=shareaholic" rel="nofollow" class="external" title="Twittere diesen Artikel!">Twittere diesen Artikel!</a>
		</li>
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://blog.ebene7.com/2012/01/30/closures-in-php/&amp;t=Closures+in+PHP" rel="nofollow" class="external" title="Empfehle diesen Artikel bei Facebook">Empfehle diesen Artikel bei Facebook</a>
		</li>
		<li class="sexy-misterwong">
			<a href="http://www.mister-wong.de/addurl/?bm_url=http://blog.ebene7.com/2012/01/30/closures-in-php/&amp;bm_description=Closures+in+PHP&amp;plugin=sexybookmarks" rel="nofollow" class="external" title="Füge hinzu zu Mister Wong">Füge hinzu zu Mister Wong</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://blog.ebene7.com/2012/01/30/closures-in-php/&amp;title=Closures+in+PHP" rel="nofollow" class="external" title="Empfehle diesen Artikel bei del.icio.us">Empfehle diesen Artikel bei del.icio.us</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://blog.ebene7.com/2012/01/30/closures-in-php/" rel="nofollow" class="external" title="Empfehle diesen Artikel bei Technorati">Empfehle diesen Artikel bei Technorati</a>
		</li>
		<li class="sexy-stumbleupon">
			<a href="http://www.stumbleupon.com/submit?url=http://blog.ebene7.com/2012/01/30/closures-in-php/&amp;title=Closures+in+PHP" rel="nofollow" class="external" title="Bei StumbleUpon einstellen">Bei StumbleUpon einstellen</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://blog.ebene7.com/2012/01/30/closures-in-php/&amp;title=Closures+in+PHP" rel="nofollow" class="external" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-myspace">
			<a href="http://www.myspace.com/Modules/PostTo/Pages/?u=http://blog.ebene7.com/2012/01/30/closures-in-php/&amp;t=Closures+in+PHP" rel="nofollow" class="external" title="Sende dies zu MySpace">Sende dies zu MySpace</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://blog.ebene7.com/2012/01/30/closures-in-php/&amp;title=Closures+in+PHP&amp;summary=Ab%20der%20Version%205.3%20bietet%20auch%20PHP%2C%20wie%20auch%20schon%20viele%20andere%20Sprachen%2C%20die%20M%C3%B6glichkeit%20mit%20anonymen%20Funktionen%20zu%20arbeiten.%20Dadurch%20k%C3%B6nnen%20z.B.%20Callback-Funktionen%20zur%20Filterung%20o.%C3%84.%20implementiert%20werden%2C%20ohne%20dass%20man%20sich%20daf%C3%BCr%20tolle%20Namen%20ausdenken%20muss.%20Aber%20was%20kann%20man%20damit%20noch%20machen&amp;source=ebene7" rel="nofollow" class="external" title="Empfehle diesen Artikel bei LinkedIn">Empfehle diesen Artikel bei LinkedIn</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://blog.ebene7.com/2012/01/30/closures-in-php/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Fundsachen KW04/2012</title>
		<link>http://blog.ebene7.com/2012/01/27/fundsachen-kw04-2012/</link>
		<comments>http://blog.ebene7.com/2012/01/27/fundsachen-kw04-2012/#comments</comments>
		<pubDate>Fri, 27 Jan 2012 11:00:31 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[Fundsachen]]></category>
		<category><![CDATA[Benchmark]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Online Tool]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Responsive Design]]></category>
		<category><![CDATA[Tool]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=3374</guid>
		<description><![CDATA[Hier die kleine Sammlung von interessanten Seiten, die ich in letzter Zeit gefunden habe. Onlinetool zum (Neu-)Formatieren von JavaScript-Code http://jsbeautifier.org/ PHP Benchmark gibt einen Überblick über die Performance vergleichbarer Operationen http://www.phpbench.com/ Responsive Design/Layout-Tester (siehe auch meinen Neujahrsartikel ) http://mattkersley.com/responsive/ Abonniere &#8230; <a href="http://blog.ebene7.com/2012/01/27/fundsachen-kw04-2012/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Hier die kleine Sammlung von interessanten Seiten, die ich in letzter Zeit gefunden habe.</p>
<ul>
<li>Onlinetool zum (Neu-)Formatieren von JavaScript-Code<br />
<a href="http://jsbeautifier.org/" target="_blank">http://jsbeautifier.org/</a></li>
<li>PHP Benchmark gibt einen Überblick über die Performance vergleichbarer Operationen<br />
<a href="http://www.phpbench.com/" target="_blank">http://www.phpbench.com/</a></li>
<li>Responsive Design/Layout-Tester (siehe auch meinen <a href="http://blog.ebene7.com/2012/01/01/gesundes-neues-jahr-und-zwei-jahre-ebene7/">Neujahrsartikel</a> <img src='http://blog.ebene7.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> )<br />
<a href="http://mattkersley.com/responsive/" target="_blank">http://mattkersley.com/responsive/</a></li>
</ul>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-center sexy-bookmarks-bg-caring-old">
<ul class="socials">
		<li class="sexy-comfeed">
			<a href="http://blog.ebene7.com/2012/01/27/fundsachen-kw04-2012/feed" rel="nofollow" class="external" title="Abonniere die Kommentare für diesen Beitrag">Abonniere die Kommentare für diesen Beitrag</a>
		</li>
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=Fundsachen+KW04%2F2012+-+UNKNOWN_ERROR+&amp;source=shareaholic" rel="nofollow" class="external" title="Twittere diesen Artikel!">Twittere diesen Artikel!</a>
		</li>
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://blog.ebene7.com/2012/01/27/fundsachen-kw04-2012/&amp;t=Fundsachen+KW04%2F2012" rel="nofollow" class="external" title="Empfehle diesen Artikel bei Facebook">Empfehle diesen Artikel bei Facebook</a>
		</li>
		<li class="sexy-misterwong">
			<a href="http://www.mister-wong.de/addurl/?bm_url=http://blog.ebene7.com/2012/01/27/fundsachen-kw04-2012/&amp;bm_description=Fundsachen+KW04%2F2012&amp;plugin=sexybookmarks" rel="nofollow" class="external" title="Füge hinzu zu Mister Wong">Füge hinzu zu Mister Wong</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://blog.ebene7.com/2012/01/27/fundsachen-kw04-2012/&amp;title=Fundsachen+KW04%2F2012" rel="nofollow" class="external" title="Empfehle diesen Artikel bei del.icio.us">Empfehle diesen Artikel bei del.icio.us</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://blog.ebene7.com/2012/01/27/fundsachen-kw04-2012/" rel="nofollow" class="external" title="Empfehle diesen Artikel bei Technorati">Empfehle diesen Artikel bei Technorati</a>
		</li>
		<li class="sexy-stumbleupon">
			<a href="http://www.stumbleupon.com/submit?url=http://blog.ebene7.com/2012/01/27/fundsachen-kw04-2012/&amp;title=Fundsachen+KW04%2F2012" rel="nofollow" class="external" title="Bei StumbleUpon einstellen">Bei StumbleUpon einstellen</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://blog.ebene7.com/2012/01/27/fundsachen-kw04-2012/&amp;title=Fundsachen+KW04%2F2012" rel="nofollow" class="external" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-myspace">
			<a href="http://www.myspace.com/Modules/PostTo/Pages/?u=http://blog.ebene7.com/2012/01/27/fundsachen-kw04-2012/&amp;t=Fundsachen+KW04%2F2012" rel="nofollow" class="external" title="Sende dies zu MySpace">Sende dies zu MySpace</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://blog.ebene7.com/2012/01/27/fundsachen-kw04-2012/&amp;title=Fundsachen+KW04%2F2012&amp;summary=Hier%20die%20kleine%20Sammlung%20von%20interessanten%20Seiten%2C%20die%20ich%20in%20letzter%20Zeit%20gefunden%20habe.%0D%0A%0D%0A%09Onlinetool%20zum%20%28Neu-%29Formatieren%20von%20JavaScript-Code%0D%0Ahttp%3A%2F%2Fjsbeautifier.org%2F%0D%0A%09PHP%20Benchmark%20gibt%20einen%20%C3%9Cberblick%20%C3%BCber%20die%20Performance%20vergleichbarer%20Operationen%0D%0Ahttp%3A%2F%2Fwww.phpbench.com%2F%0D%0A%09Responsive%20D&amp;source=ebene7" rel="nofollow" class="external" title="Empfehle diesen Artikel bei LinkedIn">Empfehle diesen Artikel bei LinkedIn</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://blog.ebene7.com/2012/01/27/fundsachen-kw04-2012/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

