<?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; CustomLibrary</title>
	<atom:link href="http://blog.ebene7.com/schlagwort/custom-library/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>Faule Models und große Datenmengen</title>
		<link>https://blog.ebene7.com/2010/12/13/faule-models-und-grosse-datenmengen/</link>
		<comments>https://blog.ebene7.com/2010/12/13/faule-models-und-grosse-datenmengen/#comments</comments>
		<pubDate>Mon, 13 Dec 2010 05:00:46 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[CustomLibrary]]></category>
		<category><![CDATA[Custom_Model]]></category>
		<category><![CDATA[Data Mapper]]></category>
		<category><![CDATA[Datenbank]]></category>
		<category><![CDATA[Entwurfsmuster]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[Model]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[OOP]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=1536</guid>
		<description><![CDATA[Unter verschiedenen Umständen kann es vorteilhaft sein, wenn Models nicht vollständig geladen und mit Daten befüllt werden, weil das Lesen zu komplex ist (Stichwort EAV-Model) oder wir mit sehr vielen Datensätzen arbeiten und dabei Speicherplatz sparen wollen/müssen. Gleichzeitig wollen wir &#8230; <a href="https://blog.ebene7.com/2010/12/13/faule-models-und-grosse-datenmengen/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Unter verschiedenen Umständen kann es vorteilhaft sein, wenn Models nicht vollständig geladen und mit Daten befüllt werden, weil das Lesen zu komplex ist (Stichwort EAV-Model) oder wir mit sehr vielen Datensätzen arbeiten und dabei Speicherplatz sparen wollen/müssen.</p>
<p>Gleichzeitig wollen wir aber zu jeder Zeit sicherstellen, dass wir das Model wie gewohnt vollständig abfragen und verwenden können. An dieser Stelle kommt eine Technik namens LazyLoading (lazy = engl. faul, träge) zum Einsatz.</p>
<p><span id="more-1536"></span></p>
<p>Nun konstruiere ich einfach ein Beispiel, um den Ablauf besser erklären zu können. In unserer Anwendung brauchen wir ein Model &#8220;Person&#8221;, das Informationen wie Name, Geburtstag und diverse andere speichern kann. Den Namen und den Geburtstag brauchen wir immer (z.B. in der Listenansicht) und die restlichen Felder nur wenn wir eine Detailansicht erstellen.</p>
<p>Wie kommt unser Model nun an die Daten? In der Regel wird sicherlich load() auf dem Modelobjekt aufgerufen oder eine vergleichbare Methode auf der jeweiligen Collection, dann werden die Daten über ein Resourcemodel geladen und letztendlich komplett auf die einzelnen Modelobjekte kopiert.</p>
<p>Um unser Vorhaben umzusetzen müssen wir das etwas abändern. Die Methode load() des Models funktioniert wie gewohnt und lädt alle Daten und die Collection nur die Nötigsten. Um nun sicherzustellen, dass wir trotzdem immer alles abrufen können, muss das Model etwas intelligenter werden.</p>
<p>Die Entwicklung des <a href="http://blog.ebene7.com/schlagwort/custom_model/" target="_self">Custom_Model</a>s hat der eine oder andere ja vielleicht mitbekommen und kennt den grundlegenden Aufbau. Relativ neu ist die Klasse Custom_Model_Persistent, durch die eine weitere Unterscheidung zwischen einfachen Datencontainern und speicherbaren Models möglich wird.</p>
<p>Für das automatische Nachladen muss die Modelklasse nun erweitert werden.</p>
<pre>&lt;?php
class Custom_Model_Persistent extends Custom_Model
{
  private $_isLoaded;

  // ...

  public function load($value = null, $field = 'id')
  {
    if (null === $value &amp;&amp; $this-&gt;_isset($field)) {
      $value = $this-&gt;_get($field);
    }

    $this-&gt;getResource()
         -&gt;loadModel($this, $value, $this-&gt;_mapKey($field))
         -&gt;markLoaded();

    return $this;
  }

  public function isLoaded()
  {
    return $this-&gt;_isLoaded;
  }

  public function markLoaded()
  {
    $this-&gt;_isLoaded = true;
    return $this;
  }

  protected function _get($key, $default = null)
  {
    if (!$this-&gt;_isset($key) &amp;&amp; !$this-&gt;isLoaded()) {
      $this-&gt;load();
    }
    return parent::_get($key, $default);
  }
}</pre>
<p>Die entscheidenen Stellen sind hier der überschriebene zentrale Getter, der ein das &#8220;Default-Load()&#8221; auslöst, wenn der Wert nicht gesetzt ist und die Daten auch noch nicht vollständig geladen wurden und die Methode load() mit optionalen Parameter $value.</p>
<p>Im Beispiel verlasse ich mich darauf, dass das Standardfeld schon gesetzt ist. Eine ordentliche Fehlerbehandlung muss aber unbedingt her, wenn wir das ganze produktiv einsetzen wollen.</p>
<p>Die Methoden isLoaded() bzw markLoaded() sind absichtlich public, damit sie z.B. aus einer Collection aufgerufen werden können, wenn das Model komplett geladen wurde. Eine weitere Möglichkeit wäre ein Vergleich mit einer Liste die gesetzt sein sollten.</p>
<p>Im Moment ist das noch etwas im Entwurf und sogar ungetestet. Wenn euch nun noch was dazu einfällt, dann schreibt einen Kommentar. Wo seht ihr für euch die Vor- oder evtl. auch die Nachteile?</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2010/12/13/faule-models-und-grosse-datenmengen/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Enums in PHP (sicher ist sicher)</title>
		<link>https://blog.ebene7.com/2010/10/08/enums-in-php-sicher-ist-sicher/</link>
		<comments>https://blog.ebene7.com/2010/10/08/enums-in-php-sicher-ist-sicher/#comments</comments>
		<pubDate>Fri, 08 Oct 2010 05:00:52 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Qualitätssicherung]]></category>
		<category><![CDATA[CustomLibrary]]></category>
		<category><![CDATA[Enum]]></category>
		<category><![CDATA[Magic Methods]]></category>
		<category><![CDATA[Reflection]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=1586</guid>
		<description><![CDATA[Wer hin und wieder auch mal in anderen Sprachen wie z.B. Java programmiert, dem werden Enums sicher nicht fremd sein. Wäre es nicht schön, ähnliches auch unter PHP zur Verfügung zu haben, um nicht jeden Status als String oder Int &#8230; <a href="https://blog.ebene7.com/2010/10/08/enums-in-php-sicher-ist-sicher/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Wer hin und wieder auch mal in anderen Sprachen wie z.B. Java programmiert, dem werden Enums sicher nicht fremd sein. Wäre es nicht schön, ähnliches auch unter PHP zur Verfügung zu haben, um nicht jeden Status als String oder Int zu übergeben? Tja, das Leben ist aber kein Ponyhof und wenn PHP das nicht anbietet, dann schaffen wir uns eben eine eigene Lösung um besser und (typ-)sicherer zu programmieren.<span id="more-1586"></span></p>
<p>Wir kennen es sicher alle: Wir haben irgendein Objekt und wollen dessen Status oder einen bestimmten Wert setzen oder abfragen. Was passiert sicher in 95% aller Fälle? Es wird ein String- oder Integer-Wert gesetzt oder verglichen. Aus meiner Sicht nicht besonders elegant und erst recht nicht sicher, da der Wert unnötig oft überprüft werden muss.</p>
<p>Mit Enums haben wir den Vorteil, dass wir bestimmte Werte vorgeben können und auch nur diese zu Verfügung stehen. Da wir unter PHP nur &#8220;normale&#8221; Klassen verwenden können, haben wir dadurch immer automatisch einen bestimmten Typen.</p>
<p>Wir wollen nun den Status eines Benutzers in unserem System definieren und legen uns dazu folgende Klasse mit den erforderlichen Werten an.</p>
<pre>&lt;?php
class UserStatus extends Custom_Enum
{
  const ACTIVE    = 1;
  const NOTACTIVE = 2;
  const DELETED   = 3;
}</pre>
<p>Damit können wir unseren Benutzern einen eindeutigen Status setzen.</p>
<pre>&lt;?php
class User
{
  public function setStatus(UserStatus $status)
  {
    // ..
  }
}

$user = new User();

$status = new UserStatus();
$user-&gt;setStatus($status-&gt;active());</pre>
<p>Durch das Type-Hinting können wir schon bei der Parameterübergabe den richtigen Objekttypen sicherstellen und müssen darauf später nicht mehr extra prüfen.</p>
<p>Die Klasse Custom_Enum funktioniert mit Reflektion und etwas PHP-Magie und ist bislang erst nur ein grober Entwurf. Ein paar Überprüfungen und eine bessere Fehlerbehandlung wären dann noch notwendige Maßnahmen.</p>
<pre>&lt;?php
abstract class Custom_Enum
{
  private $_constants;  // array
  private $_index;  // string

  public function  __construct()
  {
    $rc = new ReflectionClass($this);
    $this-&gt;_constants = $rc-&gt;getConstants();
  }

  public function __call($method, $args)
  {
    if (preg_match('/^is([a-zA-Z]*?)$/', $method, $matches)) {
      return $this-&gt;is($matches[1]);
    }
    $this-&gt;set($method);
    return $this;
  }

  public function __toString()
  {
    return (string)$this-&gt;getValue();
  }

  public function set($index)
  {
    $this-&gt;_index = strtoupper($index);
    return $this;
  }

  public function is($index)
  {
    return strtoupper($index) == $this-&gt;_index;
  }

  public function getValue()
  {
    return $this-&gt;_constants[$this-&gt;_index];
  }
}</pre>
<p>Ich finde das schon wesentlich besser als lose String- oder Integerwerte auszutauschen, aber vielleicht geht es ja noch besser und sicherer? Eure Ideen, Kritik, Fragen oder was auch immer sind dann in den Kommentaren gut aufgehoben. Also keine Scheu und diskutiert mit! <img src='https://blog.ebene7.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2010/10/08/enums-in-php-sicher-ist-sicher/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
		<item>
		<title>Weniger Code-Redundanz durch Design Patterns</title>
		<link>https://blog.ebene7.com/2010/08/27/weniger-code-redundanz-durch-design-patterns/</link>
		<comments>https://blog.ebene7.com/2010/08/27/weniger-code-redundanz-durch-design-patterns/#comments</comments>
		<pubDate>Fri, 27 Aug 2010 05:00:27 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Qualitätssicherung]]></category>
		<category><![CDATA[CustomLibrary]]></category>
		<category><![CDATA[Custom_Model]]></category>
		<category><![CDATA[Design Patterns]]></category>
		<category><![CDATA[Entwurfsmuster]]></category>
		<category><![CDATA[Factory]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[Strategy Pattern]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=1287</guid>
		<description><![CDATA[Heute habe ich eine Artikel für euch, der mir besonders gefällt, weil er auf einfache Weise mehrere interessante Themen vereint. Und, wie sollte es auch anders sein, geht es wieder um unsere Models, um Entwurfsmuster und den Weltfrieden. *hust* Bevor &#8230; <a href="https://blog.ebene7.com/2010/08/27/weniger-code-redundanz-durch-design-patterns/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Heute habe ich eine Artikel für euch, der mir besonders gefällt, weil er auf einfache Weise mehrere interessante Themen vereint. Und, wie sollte es auch anders sein, geht es wieder um unsere Models, um Entwurfsmuster und den Weltfrieden. *hust*</p>
<p>Bevor ich aber nun der Miss World 2010 die Scherpe streitig mache, fange ich lieber mal an&#8230;</p>
<p><span id="more-1287"></span>Stellen wir uns mal vor, wir haben ein Meta-Model, welches verschiedene allgemeine Daten zu einem anderen Objekt speichern kann.</p>
<pre>&lt;?php
class MetaModel extends Custom_Model
{
  protected $_ownerId;
  protected $_creatorId;
  protected $_modifierId;
  protected $_createDate;
  protected $_modifyDate;

  // Weitere Felder und Getter/Setter
}</pre>
<p>Die ersten drei Felder sind jeweils UserIds und die anderen zwei Datumswerte, die wir über gewöhnliche Getter und Setter verändern können. Damit können wir schonmal mit den Daten arbeiten, jedoch leider nicht objektorientiert navigieren.</p>
<p>Mit Navigation meine ich einen einfachen und für Menschen leicht lesbaren Zugriff auf die Objekte. Im Prinzip nur eine einfache Methodenverkettung.</p>
<pre>&lt;?php
$ownerName = $object-&gt;getMeta()-&gt;getOwner()-&gt;getName();</pre>
<p>Anders herum will ich vielleicht auch die Möglichkeit haben ein Datum als String oder als Objekt zu setzen und will ganz sicher nicht in jedem einzelnen Setter die Unterscheidung implementieren.</p>
<p>Die Lösung ist denkbar einfach. Wir lagern den benötigten Code einfach aus! Wer sich etwas mit Design Patterns beschäftigt, der erkennt sicher das <a href="http://de.wikipedia.org/wiki/Strategy_Pattern" target="_blank">Strategy Pattern</a> wieder.</p>
<p>Als erstes definieren wir eine einfache Schnittstelle und bauen uns dannach einen &#8220;Accessor&#8221;.</p>
<pre>&lt;?php
interface Custom_Model_Access_Interface
{
  public function get($value);
  public function set($value);
}</pre>
<pre>&lt;?php
class Custom_Model_Access_User implements Custom_Model_Access_Interface
{
  /**
   * @param int $value
   * @return UserModel
  public function get($value)
  {
    // UserModel laden ($value==ID)
  }

  /**
   * @param mixed int|UserModel
   * @return int (UserId)
   */
  public function set($value)
  {
    // $value-&gt;getId() zurückgeben, wenn $value ein UserModel ist, sonst $value
  }
}</pre>
<p>Damit haben wir, wenn auch stark vereinfacht, die Logik ausgelagert und können sie nun in der Modelklasse nutzen. Für viele dieser Access-Objekte reicht eine Instanz aus, die wir am besten über eine einfache <a href="http://de.wikipedia.org/wiki/Factory_Pattern" target="_blank">Factory</a> erzeugen.</p>
<p>In unserem Model sieht das dann wie folgt aus.</p>
<pre>&lt;?php
class MetaModel extends Custom_Model
{
  // ...
  private $_accessUser;

  public function init()
  {
    $this-&gt;_accessUser = Custom_Model_Access_Factory::singleton('User');
  }

  public function getOwner()
  {
    return $this-&gt;_accessUser-&gt;get( $this-&gt;getOwnerId() );
  }

  public function setOwner($owner)
  {
    return $this-&gt;setOwnerId( $this-&gt;_accessUser-&gt;set($owner) );
  }
}</pre>
<p>Nach diesem Muster würden nun auch die Methoden für creator und modifier geschrieben werden. An dieser Stelle wäre auch ein einfacher Cache möglich, damit das Objekt nicht bei jedem Aufruf erneut instanziiert werden muss.</p>
<p>Das Access-Objekt für das Datum könnte unter Umständen etwas umfangreicher werden.</p>
<p>Der Getter sollte uns ein Datums-Objekt zurückgeben anhand des in der Datenbank (oder wo auch immer) gespeicherten Werten, egal in welchem Format dieser vorliegt.</p>
<p>Der Setter auf der andern Seite könnte z.B. sämtlichen gängigen Datums-Objekte und Stringformate kennen und diese in das übliche Y-m-d H:i:s-Format übersetzen.</p>
<p>Zusammenfassend lässt sich festhalten, dass sich diese Technik für alle möglichen Bereiche geeignet ist, wenn man Objekte zu den Ids haben möchte oder auch Formate umwandeln will oder muss (Datum, IP-Adressen etc.).</p>
<p>Wenn euch noch etwas sinnvolles zur Verwendung einfällt oder einfach noch Fragen oder Kritik offen sind, dann freue ich mich über Kommentare.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2010/08/27/weniger-code-redundanz-durch-design-patterns/feed/</wfw:commentRss>
		<slash:comments>0</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>
