<?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 &#187; API</title>
	<atom:link href="http://blog.ebene7.com/schlagwort/api/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>Implementieren einer einfachen Plugin-Schnittstelle</title>
		<link>https://blog.ebene7.com/2010/05/12/implementieren-einer-einfachen-plugin-schnittstelle/</link>
		<comments>https://blog.ebene7.com/2010/05/12/implementieren-einer-einfachen-plugin-schnittstelle/#comments</comments>
		<pubDate>Wed, 12 May 2010 05:00:26 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Custom_Model]]></category>
		<category><![CDATA[Design Patterns]]></category>
		<category><![CDATA[Entwurfsmuster]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[Magic Methods]]></category>
		<category><![CDATA[Model]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[OOP]]></category>
		<category><![CDATA[Plugin]]></category>
		<category><![CDATA[SPL]]></category>
		<category><![CDATA[Strategy Pattern]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=766</guid>
		<description><![CDATA[Heute geht es darum, wie wir uns eine einfache Plugin-Schnittstelle für unsere Objekte bauen können. Als Beispiel, wie sollte es auch anders sein, eignet sich unsere Custom_Model-Klasse aus meinen vergangenen Artikeln. Und schon wieder die Frage, was kann unsere Klasse &#8230; <a href="https://blog.ebene7.com/2010/05/12/implementieren-einer-einfachen-plugin-schnittstelle/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Heute geht es darum, wie wir uns eine einfache Plugin-Schnittstelle für unsere Objekte bauen können. Als Beispiel, wie sollte es auch anders sein, eignet sich unsere Custom_Model-Klasse aus meinen <a href="http://blog.ebene7.com/2010/04/29/es-ist-ein-model-und-es-sieht-gut-aus/" target="_self">vergangenen Artikeln</a>.</p>
<p><span id="more-766"></span>Und schon wieder die Frage, was kann unsere Klasse dann mehr? Oder warum machen wir das?</p>
<p>Oftmals haben wir Objekte, die eine gewisse Menge identischer Methoden benötigen, jedoch nicht aus einer Vererbungslinie stammen.</p>
<p>Durch die Plugins können wir dann quasi Funktionen an unsere Objekte dran kleben und nutzen. Diesen Code müssen wir nur einmal schreiben, haben auch nur eine Stelle im Code zu pflegen und können dadurch sicherstellen, dass alles gleich funktioniert.</p>
<p>So erweitern wir nun also zuerst wie gewohnt unser <code>Custom_Model</code> um ein paar neue Methoden und Eigenschaften.</p>
<pre>&lt;?php
class Custom_Model implements Custom_Model_Interface
{
  // ...
  protected $_plugins;

  public function registerPlugin() {}
  public function unregisterPlugin() {}
  // ...
}</pre>
<p>Und das Interface für die Plugins.</p>
<pre>&lt;?php
interface Custom_Model_Plugin_Interface {}</pre>
<p>Beim Speichern der Plugins kommt wieder die Klasse <a href="http://de3.php.net/manual/de/class.splobjectstorage.php" target="_blank">SplObjectStorage</a> zum Einsatz, welche wir ja schon bei der <a href="http://blog.ebene7.com/2010/05/07/es-ist-ein-model-und-es-sieht-gut-aus-der-observer/" target="_self">Implementierung des Obeservers</a> verwendet haben. Demnach ist es auch nicht überraschend, dass die Registrierung an die Abmeldung der Plugins sehr einfach wird.</p>
<pre>public function registerPlugin(Custom_Model_Plugin_Interface $plugin)
{
  $this-&gt;_plugins-&gt;attach($plugin);
  return $this;
}

public function unregisterPlugin(Custom_Model_Plugin_Interface $plugin)
{
  $this-&gt;_plugins-&gt;detach($plugin);
  return $this;
}</pre>
<p>Die Models müssen das Interface <code>Custom_Model_Plugin_Interface</code> implementieren. Dieses Interface ist lediglich ein Flag- oder Marker-Interface, d.h. es schreibt keine Methoden vor.</p>
<p>Jetzt noch eine kleine Änderung an der Methode <code>__call()</code> und wir können schon mit dem Beispiel experimentieren.</p>
<pre>public function __call($method, $args)
{
  // Magie für die Getter &amp; Setter

  foreach($this-&gt;_plugins as $plugin) {
    if(method_exists($plugin, $method)) {
      array_unshift($args, $this);
      return call_user_func_array(array($plugin, $method), $args);
    }
  }

  // Fehlerbehandlung
}</pre>
<p>Durch <code>__call()</code> können wir unsere Plugin-Methoden so nutzen, als gehörten sie direkt zum Objekt. Die Art wie die Plugins verwendet werden  hat Vor-, aber auch Nachteile.</p>
<p>Die Liste der Plugins wird der Reihe nach durchlaufen und die erstbeste passende Methode wird aufgerufen. Auch die Getter oder Setter könnten wir nicht mehr überschreiben. Wenn das alles jedoch gewollt ist, dann lässt sich das aber auch mit wenigen Handgriffen erweitern.</p>
<p>Nun aber mal was praktisches zum Anschauen: Angenommen wir haben eine Model-Klasse mit Abhängigkeit zu anderen Objekten.</p>
<pre>&lt;?php
class Book extends Custom_Model
{
  protected $_id;
  protected $_title;
  protected $_ownerId;
}</pre>
<p>Nun wollen wir nicht nur die ID des Besitzers erfahren, sondern auch das Objekt das bekommen können. Dafür spendieren wir ein Plugin.</p>
<pre>&lt;?php
class GetOwnerPlugin implements Custom_Model_Plugin_Interface
{
  public function getOwner($sender)
  {
    $id = $sender-&gt;getOwnerId();

    // lade User-Objekt $owner anhand der $id

    return $owner;
  }
}</pre>
<p>Auf die Fehlerbehandlung habe ich an der Stelle mal verzichtet, sollte jedoch unbedingt stattfinden.</p>
<pre>&lt;?php
$book = new Book();
$book-&gt;registerPlugin(new GetOwnerPlugin());
$book-&gt;setOwnerId(42);
$owner = $book-&gt;getOwner();</pre>
<p>Spätestens hier fällt sicher nicht nur mir auf, dass das Konzept noch Lücken hat. Theoretisch kann es sein, dass zu verschiedenen IDs ein User-Objekt nachgeladen werden soll (<code>getAuthor()</code>, <code>getModifier()</code>, <code>getLastVisitor()</code>&#8230;) und dann bräuchten wir sämtliche Methoden in unserem Plugin oder verschiedene Plugins.</p>
<p>Dann hätten wir aber auch wieder mehrfachen Code und nichts gewonnen. Daher werde ich die Pluginschnittstelle noch etwas aufbohren und das Ergebnis dann in einem meiner nächsten Artikel vorstellen.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2010/05/12/implementieren-einer-einfachen-plugin-schnittstelle/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Es ist ein Model und es sieht gut aus &#8211; Der Observer</title>
		<link>https://blog.ebene7.com/2010/05/07/es-ist-ein-model-und-es-sieht-gut-aus-der-observer/</link>
		<comments>https://blog.ebene7.com/2010/05/07/es-ist-ein-model-und-es-sieht-gut-aus-der-observer/#comments</comments>
		<pubDate>Fri, 07 May 2010 05:00:06 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[CustomLibrary]]></category>
		<category><![CDATA[Custom_Model]]></category>
		<category><![CDATA[Data Mapper]]></category>
		<category><![CDATA[Design Patterns]]></category>
		<category><![CDATA[Entwurfsmuster]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[Listeners]]></category>
		<category><![CDATA[Model]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[Observable]]></category>
		<category><![CDATA[Observer]]></category>
		<category><![CDATA[SPL]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=434</guid>
		<description><![CDATA[Zum Abschluss dieser Woche werden wir heute noch schnell das Observer-Pattern verbauen und dazu das passende Interface SplSubject implementieren. In dem Zusammenhang findet dann auch die Klasse SplObjectStorage eine sinnvolle Verwendung. Zuerst erweitern wir das Interface Custom_Model_Interface um SplSubject und &#8230; <a href="https://blog.ebene7.com/2010/05/07/es-ist-ein-model-und-es-sieht-gut-aus-der-observer/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Zum Abschluss dieser Woche werden wir heute noch schnell das <a href="http://de.wikipedia.org/wiki/Observer_%28Entwurfsmuster%29" target="_blank">Observer-Pattern</a> verbauen und dazu das passende <a href="http://www.php.net/manual/de/class.splsubject.php" target="_blank">Interface SplSubject</a> implementieren. In dem Zusammenhang findet dann auch die Klasse <a href="http://www.php.net/manual/de/class.splobjectstorage.php" target="_blank">SplObjectStorage</a> eine sinnvolle Verwendung.</p>
<p><span id="more-434"></span>Zuerst erweitern wir das Interface Custom_Model_Interface um SplSubject und ein paar eigene Methoden.</p>
<pre>&lt;?php
interface Custom_Model_Interface
    extends ArrayAccess,
            Iterator,
            Countable,
            SplSubject
{
  public function mark();
  public function modified();
  public function cleanModified();
  public function modifiedKeys();
}</pre>
<p>Anschliessend kümmern wir uns um die Klassen Custom_Model und bauen alles Nötige ein.</p>
<pre>&lt;?php
class Custom_Model implements Custom_Model_Interface
{
  // ...
  protected $_observers;
  protected $_modified;

  public function attach(SplObserver $observer) {}
  public function detach(SplObserver $observer) {}
  public function notify() {}

  public function mark() {}
  public function modified() {}
  public function cleanModified() {}
  public function modifiedKeys() {}
  // ...
}</pre>
<p>So weit, so gut! Die ersten drei Methoden <code>attach()</code>, <code>detach()</code> und <code>notify()</code> werden durch das Interface SplSubject vorgeschrieben und sind die Schnittstelle, um Observer am Objekt zu registrieren, sie zu entfernen oder zu benachrichtigen.</p>
<p>Mit den vier weiteren können wir den Status des Objektes setzen oder kontrollieren. Die beiden protected Eigenschaften enthalten eine Liste von Typ SplObjectStorage für die Observer und ein einfaches Array für den jeweiligen Status eines Feldes.</p>
<p>Bevor wir das verwenden können, müssen wir es im Konstruktor initialisieren.</p>
<pre>public final function __construct()
{
  $this-&gt;_observers = new SplObjectStorage();
  $this-&gt;cleanModified();
  // ...
}</pre>
<p>Der Vorteil von SplObjectStorage ist der, dass jedes Objekt nur einmal darin vorkommen kann und wir uns um die Steuerung keine Gedanken machen müssen. Das macht dann auch das Hinzufügen und Entfernen eines Observers sehr einfach.</p>
<pre>public function attach(SplObserver $observer)
{
  $this-&gt;_observers-&gt;attach($observer);
  return $this;
}

public function detach(SplObserver $observer)
{
  $this-&gt;_observers-&gt;detach($observer);
  return $this;
}</pre>
<p>Mir zaubert das immer ein breites Grinsen ins Gesicht, wenn eine Aufgabe mit so wenig Code gelöst werden kann und der Doc-Block teilweise länger ist als die Funktion.</p>
<p>Aber nun wieder zum Thema. Bevor wir uns an die wirklich einfache Benachrichtigung machen, werde ich noch schnell auf die Sache mit der Statuskontrolle eingehen. Eine Aktion, z.B. <code>_set()</code> setzt den &#8220;modified&#8221;-Status eines Feldes, so dass jeder Schreibzugriff auf das Modell erkennbar wird.</p>
<p>Dadurch haben wir später die Möglichkeit, nur zu benachrichtigen, wenn es nötig ist oder auch nur die Felder zu speichern, die sich verändert haben.</p>
<p>Um eine Änderung bekannt zu machen verwenden wir <code>mark()</code>.</p>
<pre>public function mark($key)
{
  if($this-&gt;keyExists($key)) {
    $this-&gt;_modified[$this-&gt;_mapKey($key)] = true;
  }
  return $this;
}</pre>
<p>Die Methode erwartet den Namen eines existierenden Feldes und setzt ein Flag im Array.</p>
<p>Um den Status des Objektes oder eines einzelnen Feldes abfragen zu können haben wir dann <code>modified()</code>.</p>
<pre>public function modified($key = null)
{
  if(null !== $key) {
    return isset($this-&gt;_modified[$this-&gt;_mapKey($key)]);
  }
  return count($this-&gt;_modified) &gt; 0;
}</pre>
<p>Durch die Angabe des Parameters $key wird ein Feld abgefragt, ansonsten der Gesamtstatus. Nach dem selben Prinzip funktioniert dann auch <code>cleanModified()</code>, um den Status wieder zurück zu setzen.</p>
<pre>public function cleanModified($key = null)
{
  if(null != $key) {
    unset($this-&gt;_modified[$this-&gt;_mapKey($key)]);
  } else {
    $this-&gt;_modified = array();
  }
  return $this;
}</pre>
<p>Falls wir eine Liste der veränderten Felder brauchen, dann ist dafür <code>modifiedKeys()</code> vorgesehen.</p>
<pre>public function modifiedKeys()
{
  $keys = array();

  foreach($this-&gt;_keys as $key) {
    if($this-&gt;modified($key)) {
      $keys[] = $key;
    }
  }

  return $keys;
}</pre>
<p>Nachdem wir das alles durch haben, können wir uns nun <code>notify()</code> widmen, bevor wir unser Werk an ein paar Beispielen testen können.</p>
<pre>public function notify()
{
  if($this-&gt;modified()) {
    foreach($this-&gt;_observers as $observer) {
      $observer-&gt;update($this);
    }
  }
  $this-&gt;cleanModified();
  return $this;
}</pre>
<p>Die Methode macht im Prinzip nichts weiter, als bei allen in der Liste befindlichen Observer-Objekten <code>update()</code> aufzurufen und sich selbst als Parameter mitzugeben. Dadurch weiß die Observerklasse gleich, welches Objekt sich verändert hat.</p>
<p>Das folgende Beispiel zeigt einen einfachen Beobachter, der nur den Klassennamen von $subject ausgibt und eine Liste der geänderten Felder, wenn das Objekt vom Typ Custom_Model ist.</p>
<pre>class myObserver implements SplObserver
{
  public function update(SplSubject $subject)
  {
    echo get_class($subject) . ' hat sich verändert&lt;br/&gt;';
    if($subject instanceof Custom_Model) {
      print_r($subject-&gt;modifiedKeys());
    }
  }
}

$model = new Person();
$model-&gt;attach(new myObserver());
$model-&gt;setId(42)
      -&gt;setVorname('Bart');

$model-&gt;notify();</pre>
<p>Das interessante an dem Observer-Muster ist die lose Kopplung der Objekte und die Tatsache, dass ein Observer beliebig viele Subjekte beobachten kann und umgekehrt ein Subjekt beliebig viele Observer haben kann.</p>
<p>So, das war es dann auch schon für diese Woche und zu diesem Thema. Wie ich einst schon sagte, ist es ein sehr ergiebiges Thema, weil sich viele Techniken in sinnvoller Verbindung anwenden lassen. Bislang haben wir trotzdem erst nur einen Datenklumpen mit etwas Dekoration.</p>
<p>Richtig interessant wird es dann, wenn wir die Models über Mapper-Klassen laden und speichern können, aber das wird dann evtl. das Thema einer neuen Serie&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2010/05/07/es-ist-ein-model-und-es-sieht-gut-aus-der-observer/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Es ist ein Model und es sieht gut aus &#8211; Iterator</title>
		<link>https://blog.ebene7.com/2010/05/06/es-ist-ein-model-und-es-sieht-gut-aus-iterator/</link>
		<comments>https://blog.ebene7.com/2010/05/06/es-ist-ein-model-und-es-sieht-gut-aus-iterator/#comments</comments>
		<pubDate>Thu, 06 May 2010 05:00:37 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Countable]]></category>
		<category><![CDATA[CustomLibrary]]></category>
		<category><![CDATA[Custom_Model]]></category>
		<category><![CDATA[Foreach]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[Iterator]]></category>
		<category><![CDATA[Model]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[Schleife]]></category>
		<category><![CDATA[SPL]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=430</guid>
		<description><![CDATA[Nachdem sich unsere Klasse Custom_Model während der letzten Artikel gut entwickelt hat, werden wir daran heute gleich anknüpfen und das Iterator-Interface implementieren. Was kann unser Model dann, was es vorher noch nicht konnte? Durch die Verwendung des Interfaces können wir &#8230; <a href="https://blog.ebene7.com/2010/05/06/es-ist-ein-model-und-es-sieht-gut-aus-iterator/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Nachdem sich unsere Klasse Custom_Model während der letzten Artikel gut entwickelt hat, werden wir daran heute gleich anknüpfen und das <a href="http://www.php.net/manual/de/class.iterator.php" target="_blank">Iterator-Interface</a> implementieren.</p>
<p>Was kann unser Model dann, was es vorher noch nicht konnte? Durch die Verwendung des Interfaces können wir die gespeicherten Daten in einer foreach-Schleife verarbeiten. Das kann z.B. beim erzeugen von Tabellen erforderlich sein.</p>
<p><span id="more-430"></span>Wie immer beginne ich mit einer Skizze der heutigen Erweiterungen.</p>
<pre>&lt;?php
interface Custom_Model_Interface
  extends ArrayAccess,
          Iterator,
          Countable
{
}</pre>
<p>Unser Interface Custom_Model_Interface erweitert zunächst das Iterator-Interface und auch <a href="http://www.php.net/manual/de/class.countable.php" target="_blank">Countable</a>. Dadurch lassen sich dann die Elemente des Objektes zählen und in Verbindung mit ArrayAccess auch beliebig in einer for-Schleife verarbeiten.</p>
<p>In unserer Klasse müssen wir nun die entsprechenden Methoden deklarieren.</p>
<pre>&lt;?php
class Custom_Model implements Custom_Model_Interface
{
  // ...

  public function current() {}
  public function key() {}
  public function next() {}
  public function rewind() {}
  public function valid() {}
  public function count() {}

// ...
}</pre>
<p>Jedem, der lange genug mit PHP arbeitet sollte nun was auffallen. Richtig! Wir halten unsere &#8220;Feldnamen&#8221; in einem Array und zu fast jeder Methode gibt es eine gleichnamige <a href="http://de3.php.net/manual/de/ref.array.php" target="_blank">Array-Funktion</a>.</p>
<p>Da wir aber an meistens an die Werte und nicht an die Namen der Felder wollen, müssen wir etwas tricksen.</p>
<p>Die erste Methode <code>current()</code> gibt das jeweilige Element an der Position des internen Zeigers zurück und entspricht damit der gleichnamigen Array-Funktion <a href="http://de3.php.net/manual/de/function.current.php" target="_blank"><code>current()</code></a>.</p>
<pre>public function current()
{
  return $this-&gt;_get(current($this-&gt;_keys));
}</pre>
<p>Das Gegenstück dazu stellt quasi <code>key()</code> dar, da es den Feldnamen der Position liefert.</p>
<pre>public function key()
{
  return $this-&gt;_keys[key($this-&gt;_keys)];
}</pre>
<p>Auf den ersten Blick mag diese Schreibweise vielleicht etwas verwirren, aber nur so bekommen wir den richtigen Schlüssel. <a href="http://de3.php.net/manual/de/function.key.php" target="_blank"><code>key()</code></a> gibt uns den aktuellen Schlüssel von $this-&gt;_keys zurück, wir wollen den Wert der jeweiligen Position haben.</p>
<p>Um nun in der Schleife den internen Zeiger bewegen zu können, brauchen wir <a href="http://de3.php.net/manual/de/function.next.php" target="_blank"><code>next()</code></a>.</p>
<pre>public function next()
{
  next($this-&gt;_keys);
}</pre>
<p>Wird das Objekt ein weiteres Mal mit foreach verarbeitet, so muss der interne Zeiger wieder auf die erste Position zurückgesetzt werden. Das Iterator-Interface schreibt dafür die Methode <code>rewind()</code> vor, die dann intern <a href="http://de3.php.net/manual/de/function.reset.php" target="_blank"><code>reset()</code></a> verwenden kann.</p>
<pre>public function rewind()
{
  reset($this-&gt;_keys);
}</pre>
<p>Innerhalb der Schleife wir überprüft, ob weitere Elemente vorhanden sind. Dazu wird <code>valid()</code> verwendet.</p>
<pre>public function valid()
{
  return current($this-&gt;_keys) !== false;
}</pre>
<p>Damit haben wir alles notwendige eingebaut, damit unser Model in einer foreach-Schleife ausgelesen werden kann.</p>
<pre>foreach($model as $key=&gt;$value) {
  echo $key . ' = ' . $value . '&lt;br/&gt;';
}</pre>
<p>Zuletzt gibt es dann auch noch die Methode <code>count()</code> des Countable-Interfaces, damit wir beliebig mit for-Schleifen über das Objekt iterieren können.</p>
<pre>public function count()
{
  return count($this-&gt;_keys);    
}</pre>
<p>und</p>
<pre>for($i=0; $i&lt;count($model); $i++) {
  echo $i . ' = ' . $model[$i] . '&lt;br/&gt;';
}</pre>
<p>Damit wären wir auch schon wieder am Ende. Beim nächsten Mal geht es dann weiter mit dem <a href="http://blog.ebene7.com/2010/05/07/es-ist-ein-model-und-es-sieht-gut-aus-der-observer/" target="_self">Observer-Pattern</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2010/05/06/es-ist-ein-model-und-es-sieht-gut-aus-iterator/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
