<?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>Doctrine 2 | Nerdpress.org</title>
	<atom:link href="https://nerdpress.org/tag/doctrine-2/feed/" rel="self" type="application/rss+xml" />
	<link>https://nerdpress.org</link>
	<description>...dev, tech problems and solutions.</description>
	<lastBuildDate>Mon, 29 Aug 2011 18:39:56 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>[Symfony 2] Security Bundle &#8211; Benutzer mit username oder email anmelden.</title>
		<link>https://nerdpress.org/2011/08/12/symfony-2-security-bundle-benutzer-mit-username-oder-email-anmelden/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Fri, 12 Aug 2011 13:04:36 +0000</pubDate>
				<category><![CDATA[DB]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Project Setup]]></category>
		<category><![CDATA[Symfony]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Doctrine 2]]></category>
		<category><![CDATA[ORM]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[SecurityBundle]]></category>
		<category><![CDATA[symfony 2]]></category>
		<guid isPermaLink="false">https://nerdpress.org/?p=1566</guid>

					<description><![CDATA[<p>Augenscheinlich unterstützt das Security-Modul in der Standard-Konfiguration nur die Authentifizierung via Benutzername und Password. Wie man sich mit einem Benutzernamen ODER der E-Mail-Adresse und einem Passwort authentifiziert, ist ein wenig versteckt. Das ist die Anleitung, wie es funktioniert.</p>
The post <a href="https://nerdpress.org/2011/08/12/symfony-2-security-bundle-benutzer-mit-username-oder-email-anmelden/">[Symfony 2] Security Bundle – Benutzer mit username oder email anmelden.</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></description>
										<content:encoded><![CDATA[<p>Augenscheinlich unterstützt das Security-Module nur die Authentifizierung via Benutzername und Password. Wie man sich mit einem Benutzernamen ODER der E-Mail-Adresse und einem Password authentifiziert, ist ein wenig versteckt. So gehts:</p>
<p><span id="more-1566"></span></p>
<p>Schaut man sich den generischen EntityUserProvider an, so sieht man ab Zeile 46 sowas wie</p>
<pre class="brush: php; title: ; notranslate">
    /**
     * {@inheritdoc}
     */
    public function loadUserByUsername($username)
    {
        if (null !== $this-&gt;property) {
            $user = $this-&gt;repository-&gt;findOneBy(array($this-&gt;property =&gt; $username));
        } else {
            if (!$this-&gt;repository instanceof UserProviderInterface) {
                throw new InvalidArgumentException(sprintf('The Doctrine repository &quot;%s&quot; must implement UserProviderInterface.', get_class($this-&gt;repository)));
            }

            $user = $this-&gt;repository-&gt;loadUserByUsername($username);
        }

        if (null === $user) {
            throw new UsernameNotFoundException(sprintf('User &quot;%s&quot; not found.', $username));
        }

        return $user;
    }
</pre>
<p>Dieser Code besagt, dass nur dann, wenn die Konfigurationeinstellung &#8220;property&#8221; aus der security.yml entfernt wird (steht üblicherweise auf &#8220;username&#8221; und gibt das Datenbankattribut an, das eben den Benutzernamen hält), das entsprechende Doctrine-Entity &#8220;User&#8221; auch eine Repository-Class hat und diese darüber hinaus UserProviderInterface implementiert, man seine eigene loadUserByUsername()-Methode implementieren kann, die dann von der Firewall zur Identifizierung des Benutzer beim Login herangezogen wird (dieser Vorgang ist komplett intransparent, Symfony Magic).</p>
<p>Also aus seiner &#8220;alten&#8221; security.yml</p>
<pre class="brush: python; title: ; notranslate">
    providers:
        default:
            users:
                user:  { password: userpass, roles: &#x5B; 'ROLE_USER' ] }
                admin: { password: adminpass, roles: &#x5B; 'ROLE_ADMIN' ] }
            entity: { class: DvlpCoreBundleEntityUser, property: username }
</pre>
<p>sowas machen:</p>
<pre class="brush: python; title: ; notranslate">
     ...
            entity: { class: DvlpCoreBundleEntityUser }
</pre>
<p>Dann muss das zu User gehörtige UserRepository nur noch UserProviderInterface implementieren, bspw. so:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php

namespace DvlpCoreBundleEntity;

use DoctrineORMEntityRepository;
use SymfonyComponentSecurityCoreUserUserProviderInterface;
use SymfonyComponentSecurityCoreUserUserInterface;

/**
 * UserRepository
 *
 * This class was generated by the Doctrine ORM. Add your own custom
 * repository methods below.
 */
class UserRepository extends EntityRepository implements UserProviderInterface
{
    /**
     * {@inheritdoc}
     */
    public function loadUserByUsername($username)
    {
        return $this-&gt;getEntityManager()
            -&gt;createQuery('SELECT u FROM DvlpCoreBundle:User u JOIN u.Profile p WHERE u.username = :username OR p.email = :username')
            -&gt;setParameters(array(
                'username' =&gt; $username
            ))
            -&gt;getOneOrNullResult();
    }

    /**
     * {@inheritDoc}
     */
    public function refreshUser(UserInterface $user)
    {
        return $this-&gt;loadUserByUsername($user-&gt;getUsername());
    }

    /**
     * {@inheritDoc}
     */
    public function supportsClass($class)
    {
        // NEVER CALLED ...
        return $class === 'DvlpCoreBundleEntityUser';
    }
}
}
</pre>
<p>Schon kann man als Benutzernamen entweder den Username oder die E-Mail-Adresse des Users angeben.</p>The post <a href="https://nerdpress.org/2011/08/12/symfony-2-security-bundle-benutzer-mit-username-oder-email-anmelden/">[Symfony 2] Security Bundle – Benutzer mit username oder email anmelden.</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Symfony 2 Standard Edition released</title>
		<link>https://nerdpress.org/2011/03/07/symfony-2-standard-edition-released/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Mon, 07 Mar 2011 17:20:38 +0000</pubDate>
				<category><![CDATA[Doctrine ORM]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Software engineering]]></category>
		<category><![CDATA[Symfony]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[Doctrine]]></category>
		<category><![CDATA[Doctrine 2]]></category>
		<category><![CDATA[Standard Edition]]></category>
		<category><![CDATA[symfony 2]]></category>
		<guid isPermaLink="false">https://nerdpress.org/?p=1401</guid>

					<description><![CDATA[<p>Ab heute, dem 7. 3. 2011, steht auf http://symfony.com die &#8220;Standard-Edition&#8221; der neuesten Version 2 des populären RAD-Frameworks zum Download bereit. Bereits am vergangenen Wochenende ging die neue Website des Projekts online. Symfony 2 wird als Sammlung loser gekoppelter Komponenten &#8211; sog. &#8220;Bundles&#8221; &#8211; in mehreren Ausgaben erhältlich sein. Zum jetzigen Zeitpunkt existiert bereits eine &#8230; </p>
<p class="link-more"><a href="https://nerdpress.org/2011/03/07/symfony-2-standard-edition-released/" class="more-link">Continue reading<span class="screen-reader-text"> "Symfony 2 Standard Edition released"</span></a></p>
The post <a href="https://nerdpress.org/2011/03/07/symfony-2-standard-edition-released/">Symfony 2 Standard Edition released</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></description>
										<content:encoded><![CDATA[<p>Ab heute, dem 7. 3. 2011, steht auf http://symfony.com die &#8220;Standard-Edition&#8221; der neuesten Version 2 des populären RAD-Frameworks zum Download bereit. Bereits am vergangenen Wochenende ging die neue Website des Projekts online.<br />
<span id="more-1401"></span><br />
Symfony 2 wird als Sammlung loser gekoppelter Komponenten &#8211; sog. &#8220;Bundles&#8221; &#8211; in mehreren Ausgaben erhältlich sein. Zum jetzigen Zeitpunkt existiert bereits eine Sandbox und eine davon abgeleitete &#8220;Standard-Edition&#8221;, die wie gewohnt ein festes Code-Verzeichnislayout vorgeben.</p>
<p>Als zukünftige Ausgaben denkbar sind ein Symfony2-basierendes CMF (Content Management Framework) oder eine auf die speziellen Befürfnisse von Online-Shops zugeschnittene Bundle-Sammlung.</p>
<p>Der Code ist noch nicht als stabil deklariert. Die bereits vorhandene und wie immer intensiv gepflegte Referenz-Dokumentation lädt bereits jetzt zum Reinschnuppern und Ausprobieren ein.  </p>The post <a href="https://nerdpress.org/2011/03/07/symfony-2-standard-edition-released/">Symfony 2 Standard Edition released</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Symfony 2 PR3: doctrine:schema:create liefert &#8220;No Metadata Classes to process.&#8221;</title>
		<link>https://nerdpress.org/2010/10/17/symfony-2-pr3-doctrineschemacreate-liefert-no-metadata-classes-to-process/</link>
					<comments>https://nerdpress.org/2010/10/17/symfony-2-pr3-doctrineschemacreate-liefert-no-metadata-classes-to-process/#comments</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sun, 17 Oct 2010 16:33:42 +0000</pubDate>
				<category><![CDATA[Doctrine ORM]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Symfony]]></category>
		<category><![CDATA[active entity]]></category>
		<category><![CDATA[cli]]></category>
		<category><![CDATA[Doctrine 2]]></category>
		<category><![CDATA[ORM]]></category>
		<category><![CDATA[symfony 2]]></category>
		<guid isPermaLink="false">https://nerdpress.org/?p=1131</guid>

					<description><![CDATA[<p>Die Doku stellt in Aussicht, dass man den &#8220;normalen&#8221; Doctrine-Namespace-Shortcut benutzen kann, also bspw. @Entity anstelle von @DoctrineOrmMappingEntity. Funktioniert aber nicht, weil in irgend einer Service-Configuration dieser Namespace auf einen Alias gemapped wird, der da lautet &#8220;orm&#8221;. Die Syntax lautet aber nun auch nicht @ormEntity, sondern @orm:Entity. Schreibt man sein Model also bspw. so: &#60;?php &#8230; </p>
<p class="link-more"><a href="https://nerdpress.org/2010/10/17/symfony-2-pr3-doctrineschemacreate-liefert-no-metadata-classes-to-process/" class="more-link">Continue reading<span class="screen-reader-text"> "Symfony 2 PR3: doctrine:schema:create liefert &#8220;No Metadata Classes to process.&#8221;"</span></a></p>
The post <a href="https://nerdpress.org/2010/10/17/symfony-2-pr3-doctrineschemacreate-liefert-no-metadata-classes-to-process/">Symfony 2 PR3: doctrine:schema:create liefert “No Metadata Classes to process.”</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></description>
										<content:encoded><![CDATA[<p>Die <a href="http://docs.symfony-reloaded.org/guides/doctrine/orm/overview.html">Doku</a> stellt in Aussicht, dass man den &#8220;normalen&#8221; Doctrine-Namespace-Shortcut benutzen kann, also bspw. @Entity anstelle von @DoctrineOrmMappingEntity. Funktioniert aber nicht, weil in irgend einer Service-Configuration dieser Namespace auf einen Alias gemapped wird, der da lautet &#8220;orm&#8221;. Die Syntax lautet aber nun auch nicht @ormEntity, sondern @orm:Entity. Schreibt man sein Model also bspw. so:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php

namespace ApplicationHelloBundleEntity;

/**
 * ApplicationHelloBundleEntityUser
 *
 * @orm:Table(name=&quot;users&quot;)
 * @orm:Entity
 */
class User
{
  /**
   * @var integer $id
   *
   * @orm:Column(name=&quot;id&quot;, type=&quot;integer&quot;)
   * @orm:Id
   * @orm:GeneratedValue(strategy=&quot;AUTO&quot;)
   */
  protected $id;
</pre>
<p>sollten alle CLI-Tasks auch wunderbar funktionieren. Es bleibt zu hoffen, dass die DI-Services eine reichhaltige Parameter-Dokumentation spendiert kriegen und das ganze Bundle-System eine transparente, dokumentierte API erhalten (wo zum Teufel liegt in der Sandbox bitte der versprochene Doctrine-Controller?) </p>
<p>Die Einstellung findet sich übrigens in der Service-Configuration unter src/vendor/symfony/src/Symfony/Bundle/DoctrineBundle/Resources/config/orm.xml:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;service id=&quot;doctrine.orm.metadata_driver.annotation.reader&quot; class=&quot;%doctrine.orm.metadata.annotation_reader_class%&quot;&gt;
            &lt;call method=&quot;setAnnotationNamespaceAlias&quot;&gt;
              &lt;argument&gt;DoctrineORMMapping&lt;/argument&gt;
              &lt;argument&gt;orm&lt;/argument&gt;
            &lt;/call&gt;
        &lt;/service&gt;
</pre>
<p>Ist leicht zu finden, wenn man weiß, wonach man suchen muss. Ich denke, es ist am einfachsten, die Service-Definition des DI-Containers an entsprechender Stelle an seine eigenen Bedürfnisse anzupassen. Wie das zuverlässig und projektübergreifend funktioniert, erkläre ich vielleicht mal, wenn ich&#8217;s selbst gerafft hab.</p>
<p>Achso, <a href="http://groups.google.com/group/symfony-devs/browse_thread/thread/a2912efa4b64002a/4606d5407258dd2d?show_docid=4606d5407258dd2d">hier</a> noch der Nebensatz (etwas herunter scrollen), in dem gesagt wird, das Jonathan irgendwann mal das &#8220;orm:&#8221; Präfix einführt. Symfony 2 ist definitiv noch nicht ready for production (was aber auch niemand behauptet).</p>The post <a href="https://nerdpress.org/2010/10/17/symfony-2-pr3-doctrineschemacreate-liefert-no-metadata-classes-to-process/">Symfony 2 PR3: doctrine:schema:create liefert “No Metadata Classes to process.”</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></content:encoded>
					
					<wfw:commentRss>https://nerdpress.org/2010/10/17/symfony-2-pr3-doctrineschemacreate-liefert-no-metadata-classes-to-process/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Dependency Injection mit PHP 5.3, Runkit-Erweiterung und Doctrine 2-Annotationen</title>
		<link>https://nerdpress.org/2010/09/26/dependency-injection-mit-php-5-3-runkit-erweiterung-und-doctrine-2-annotationen/</link>
					<comments>https://nerdpress.org/2010/09/26/dependency-injection-mit-php-5-3-runkit-erweiterung-und-doctrine-2-annotationen/#comments</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sun, 26 Sep 2010 15:33:33 +0000</pubDate>
				<category><![CDATA[Doctrine ORM]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Software engineering]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Annotations]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Dependency Injection]]></category>
		<category><![CDATA[Doctrine 2]]></category>
		<category><![CDATA[IoC]]></category>
		<category><![CDATA[PHP 5.3]]></category>
		<category><![CDATA[Runkit]]></category>
		<guid isPermaLink="false">https://nerdpress.org/?p=1085</guid>

					<description><![CDATA[<p>Unter Dependency Injection versteht man heute nicht nur ein einfaches Entwurfsmuster, sondern vor allem Framework-gestützte Mechanismen, die den konkreten Implementierungsaufwand verringern (Entwicklungszeitoptimierung), dem Entwickler bessere Übersicht über Abhängigkeiten zu schaffen (Applicationdesignoptimierung) und die Anzahl der Instanzen gleichen Prototyps zu minimieren (Performanceoptimierung). Heute möchte ich einen alternativen, vielleicht pragmatischeren Ansatz als der andererer populärer Implementierungenn herbeispinnen, &#8230; </p>
<p class="link-more"><a href="https://nerdpress.org/2010/09/26/dependency-injection-mit-php-5-3-runkit-erweiterung-und-doctrine-2-annotationen/" class="more-link">Continue reading<span class="screen-reader-text"> "Dependency Injection mit PHP 5.3, Runkit-Erweiterung und Doctrine 2-Annotationen"</span></a></p>
The post <a href="https://nerdpress.org/2010/09/26/dependency-injection-mit-php-5-3-runkit-erweiterung-und-doctrine-2-annotationen/">Dependency Injection mit PHP 5.3, Runkit-Erweiterung und Doctrine 2-Annotationen</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></description>
										<content:encoded><![CDATA[<p>Unter <a href="http://de.wikipedia.org/wiki/Dependency_Injection">Dependency Injection</a> versteht man heute nicht nur ein einfaches Entwurfsmuster, sondern vor allem Framework-gestützte Mechanismen, die den konkreten Implementierungsaufwand verringern (Entwicklungszeitoptimierung), dem Entwickler bessere Übersicht über Abhängigkeiten zu schaffen (Applicationdesignoptimierung) und die Anzahl der Instanzen gleichen Prototyps zu minimieren (Performanceoptimierung).</p>
<p>Heute möchte ich einen alternativen, vielleicht pragmatischeren Ansatz als der andererer populärer Implementierungenn herbeispinnen, um Dependency Injection (DI) in PHP 5.3 zu realisieren.<br />
<span id="more-1085"></span><br />
Für diverse Programmiersprachen gibt es &#8211; auf den jeweiligen Anwendungsbereich mehr oder weniger spezialisierte &#8211; sogenannte Dependency-Injection (DI)-Container. Der DI-Container als solcher dient im Grunde als Manager oder Konfigurator, der das Zusammenspiel unserer Abhängigkeiten definiert &#8211; meist auf Grundlage einer Konfigurationsdatei, die bspw. in XML vorliegt:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
       xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;

  &lt;bean id=&quot;...&quot; class=&quot;...&quot;&gt;
    &lt;!-- collaborators and configuration for this bean go here --&gt;
  &lt;/bean&gt;

  &lt;bean id=&quot;...&quot; class=&quot;...&quot;&gt;
    &lt;!-- collaborators and configuration for this bean go here --&gt;
  &lt;/bean&gt;

  &lt;!-- more bean definitions go here... --&gt;

&lt;/beans&gt;
</pre>
<p>(Quelle: <a href="http://static.springsource.org/spring/docs/2.0.x/reference/beans.html">Springsource</a>)</p>
<p>Eine weitere Möglichkeit Abhängigkeiten zu definieren, bietet das <a href="http://en.wikipedia.org/wiki/Convention_over_configuration">Convention Over Configuration-Paradigma</a>: Heißt bspw. eine Member-Variable &#8220;Mailservice&#8221;, so kann der zugrundeliegende DI-Container entsprechend konfiguriert werden, sodass bei Instanziierung automatisch eine Klasse gleichen Namens (Mailservice) instanziiert und an das Objekt gebunden wird (so macht&#8217;s bspw. Grails in seinen MVC-Controller-Instanzen, wobei hier natürlich wieder das <a href="http://static.springsource.org/spring/docs/2.0.x/reference/beans.html">Spring IoC</a> (Das hat nichts mit dem internationalen olympischen Komitee zu tun, sondern ist die Abkürzung für &#8220;Inversion of Control&#8221; und steht gleichbedeutend für &#8220;Dependency Injection&#8221;). Diese Implementierung erfordert natürlich ausgereifte Introspektionsmechanismen der zugrundeliegenden Programmiersprache (Stichwort &#8220;<a href="http://de.wikipedia.org/wiki/Reflexion_(Programmierung)">Reflection</a>&#8220;), außerdem muss man dem DI bzw. IOC-Container vorher beigebracht haben, <em>welche</em> Klassen oder Verzeichnisstrukturen überhaupt durchsucht und unter &#8220;DI-Kontrolle&#8221; gestellt werden müssen &#8211; ein zusätzlicher Programmieraufwand ist also immer noch gegeben. Unvorhersehbarkeiten im Code und eine erhöhte WTF&#8217;s/min-Rate kommen dabei frei Haus.</p>
<p>PHP bieted zu dem ganzen Thema ab Werk erstmal &#8211; nix. Die <a href="http://php.net/manual/en/book.reflection.php">Reflection-API</a> ist aber schonmal ein ausgereiftes Werkzeug, um definierte Abhängigkeiten auszuwerten. Das allerdings ausschließlich mittels lesendem Zugriff auf Metadaten von bspw. Klassen, Methoden oder auch System- bzw. benutzerdefinierten Funktionen. Schreibende Operationen sind im Sprachkern erst einmal nicht vorgesehen. Es ist also prinzipiell möglich, zur Laufzeit Abhängigkeiten durch Konvention zu definieren, die Auflösung selbiger ist aber &#8220;mit Boardmitteln&#8221; nicht zu realisieren. </p>
<p>Ein eigenes Sprachkonstrukt wie <a href="http://de.wikipedia.org/wiki/Mixin">Mixins</a> ist auch (noch) nicht implementiert, und anonyme (&#8220;<a href="http://de.wikipedia.org/wiki/Lambda-Funktion">Lambda</a>&#8220;)-Funktionen lassen sich nicht wie in Javascript oder auch Groovy direkt an den Objekt-Prototypen hängen oder auch an einzelne Instanzen, sondern müssen mühsam &#8220;by reference&#8221; gezogen und dann erst ausgewertet werden.</p>
<p>Javascript:</p>
<pre class="brush: jscript; title: ; notranslate">
  var foo = function() { }
  foo.prototype.bar = function() { return &quot;bar&quot;; }
  foo.baz = foo.prototype.bar;

  var foobar = new foo;
  foo.bar(); // -&gt; &quot;bar&quot;
  foo.baz(); // -&gt; &quot;bar&quot;
</pre>
<p>PHP:</p>
<pre class="brush: php; title: ; notranslate">
  $foo = new stdClass();
  $foo-&gt;bar = function() 
  {
    return &quot;bar&quot;;
  }
  $foo-&gt;bar(); // method not found
   
  $bar = $foo-&gt;bar;
  $bar(); // -&gt; &quot;bar&quot;
</pre>
<p>Zugegeben: Gäbe es bereits Mixins oder Prototypen im PHP-Kontext, wäre die Implementierung eines DI-Containers wohl eher unspannend, mindestens aber überflüssig. Dennoch fehlt eine zuverlässige Möglichkeit, PHP-Instanzen zur Laufzeit mit neuen Methoden anreichern zu können. Daher gehen die meisten PHP-DI-Frameworks immer den Weg über einen recht aufgeblähten DI-Container. Dieser macht aber im Grunde nichts anderes, als Referenzen zu verwalten. Der Container selbst wird dann an die anzureichernde Instanz gebunden, im Idealfall eventuell aber noch via magischer Methode __call() verborgen. Dann aber muss die zu aufnehmende Instanz wiederum mindestens ein Interface &#8220;Injectable&#8221;  o.Ä. implementieren. Letzlich aber passiert am Ende immer folgendes:</p>
<pre class="brush: php; title: ; notranslate">
class myController extends Controller
{
  public function indexAction(HttpRequest $request)
  {
    $db = $this-&gt;getService('Database');
  }
}
</pre>
<p>Der Service-Container übernimmt also die klassische Aufgabe des &#8220;ApplicationContext&#8221;: Er managed Referenzen, rückt diese aber erst &#8220;on demand&#8221; heraus. Meiner Meinung hat man dabei nicht allzu viel gewonnen, vor allem, wenn das obige Codeschnippsel noch eine Menge Konfiguration, Code zum Bootstrappen des DI-Containers und/oder Caching voraussetzt.</p>
<p>Ich persönlich würde mir dann doch eher &#8220;ganz oldschool&#8221; ein paar getter/setter zusätzlich schreiben und mich einfach darauf verlassen, dass der gute, alte ApplicationContext sowieso (fast) alles enthält, was ich brauch&#8217;, mit der Konsequenz, dass dieser eben nicht gerade leichtgewichtig ist.</p>
<p>Wozu also das ganze?</p>
<h2>Ein alternativer DI-Container mit Doctrine 2 Annotations und Runkit</h2>
<p>Die Annotations-Implementierung von Doctrine 2 ist einfach und mächtig genug, um eine beliebigen Klasse mit Metainformationen auszustatten, die die zu injizierenden Abhängigkeiten definieren. Runkit ermöglicht es, auf Basis dieser Metadaten Abhänigkeiten an das ensprechende Objekt zu binden &#8211; zur Laufzeit und ohne zusätzliche Implementierung von Schnittstellen o.Ä. Vom Prinzip her sollte es also möglich sein, eine Klasse zu schreiben, diese zu annotieren und dann bei Instanziierung automatisch alle gewünschten Abhängigkeiten zur Verfügung stehen zu haben. Ein Codebeispiel:</p>
<p>index.php:</p>
<pre class="brush: php; title: ; notranslate">
  require __DIR__ . '/lib/vendor/doctrine-common/lib/Doctrine/Common/ClassLoader.php';

  use DoctrineCommonClassLoader;
  
  $classLoader = new ClassLoader('DoctrineCommon', __DIR__ . '/lib/vendor/doctrine-common/lib');
  $classLoader-&gt;register();

  $classLoader = new ClassLoader('deifschleife', __DIR__ . '/lib');
  $classLoader-&gt;register();

  // INITIALISIERUNG DES DI-CONTAINERS
  $di_container = new deifschleifediContainer;
  
  $di_container-&gt;setClassnames(array(
    'deifschleifeDITest'
  ));
  
  // &quot;AUFNEHMENDE&quot; KLASSE
  $test = new deifschleifeDITest();

  // GEHÖRT deifschleifeADependency
  echo $test-&gt;foo();
  
  // GEHÖRT deifschleifeAnotherDependency
  echo $test-&gt;bar();

  // GEHÖRT deifschleifeYetAnotherDependency
  echo $test-&gt;baz();
  
  // GIBT's NICHT, ÜBER __call() ABGEFANGEN
  echo $test-&gt;methodThatDoesNotExist();
</pre>
<p>Kurz erklärt:</p>
<pre class="brush: php; title: ; notranslate">
$di_container = new deifschleifediContainer;
$di_container-&gt;setClassnames(array(
    'deifschleifeDITest'
  ));
</pre>
<p>Instanziiert den DI-Container und stellt eine Klasse (deifschleifeDITest) unter seine &#8220;Kontrolle&#8221;.</p>
<pre class="brush: php; title: ; notranslate">
$test = new deifschleifeDITest();

  // GEHÖRT deifschleifeADependency
  echo $test-&gt;foo();
  
  // GEHÖRT deifschleifeAnotherDependency
  echo $test-&gt;bar();

  // GEHÖRT deifschleifeYetAnotherDependency
  echo $test-&gt;baz();
  
  // GIBT's NICHT, ÜBER __call() ABGEFANGEN
  echo $test-&gt;methodThatDoesNotExist();
</pre>
<p>Instanziiert die überwachte Klasse deifschleifeDITest und ruft einige Methoden auf, die sämtlich aus anderen Klassen nach DITest injiziert wurden. Die letze Methode ist nirgends existent. deifschleifeDITest implementiert ausschließlich __call(), ansonsten ist die Klasse (fast) leer:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
namespace deifschleife;

/**
 * @Services({
 *   @Service(
 *    class=&quot;deifschleifeADependency&quot;,
 *    constructorArgs={
 *      &quot;pong&quot;
 *    }
 *  ),
 *  @Service(
 *    class=&quot;deifschleifeAnotherDependency&quot;,
 *    constructor={&quot;deifschleifeAnotherDependency&quot;, &quot;getAnotherDependency&quot;}
 *  ),
 *  @Service(
 *    class=&quot;deifschleifeYetAnotherDependency&quot;,
 *    constructor=&quot;makeYetAnotherDependency&quot;
 *  )
 * })
 */
class DITest
{
  public function __call($method, $args)
  {
    return sprintf(&quot;Called __call, Method: %s, Args: %s&quot;, $method . '()', implode(', ', $args));
  }

  public function makeYetAnotherDependency()
  {
    return new YetAnotherDependency();
  }
}
</pre>
<p>Interessant sind die Klassen-Annotationen ganz oben: @Services teilt dem Doctrine 2 Annotation Parser mit, dass hier eine Reihe von PHP-Klassen, die zu injizierende Methoden enthalten, zusammenzusuchen sind. Jeder einzelne @Service in der Liste kann noch grob konfiguriert werden, so kann bspw. eine eigene Factory-Methode für jede Dependency angegeben werden.</p>
<p>Die einzelnen Dependencies sind &#8220;ganz normale&#8221; PHP-Klassen. Intern passiert folgendes: Die Runkit-Erweiterung dient dazu, über runkit_method_add() &#8220;on the fly&#8221; eine magische Methode __call() an die mit zusätzlcihen Methoden anzureichernde Klasse deifschleifeDITest zu binden. Existiert bereits eine entsprechende Methode __call(), wird diese intern via runkit_method_rename() umbenannt und am Ende von __call() (neu) aufgerufen. Das bedingt natürlich eine gewisse Rücksichtname bei zusätzlicher Verwendung von __call(). </p>
<p>Die Idee unterscheidet sch also nur unwesentlich von bereits vorhandenen Konzepten, spart aber einige Schritte ein:</p>
<p>1.) Man benötigt keine Abstrakte Klasse und/oder Interface, die dass die getService()-Logik bereitstellt.<br />
2.) Man benötigt kaum zusätzliche Konfigurationsaufwand &#8211; eine einfache Annotation im PHPDOc-Comment-Format reicht aus (es spricht allerdings nichts dagegen, je nach Gschmäckle einen Config-Adapter dazwischen zu schieben, der das Mapping via XML oder bspw. Yaml erlaubt)<br />
3.) Man kann auf Proxy-Instanzen verzichten, die __call() transparent bereitstellen.</p>
<p>Fazit: Es ist prinzipiell möglich, Dependency Injection &#8211; passender noch &#8220;Mixins&#8221; &#8211; mit PHP zu realisieren, ohne nennenswert viel Codeoverhead zu produzieren. </p>
<p>Allerdings muss man berücksichtigen, dass Runkit eine experimentelle Erweiterung ist, deren Zuverlässigkeit in komplexen Projekten nicht vorauszusehen ist. Außerdem wird es sehr wahrscheinlich in Bälde ein mächtiges, neues Sprachkonstrukt geben, das Mixins ermöglicht (siehe <a href="http://wiki.php.net/rfc/traits">RFC zu Traits</a>). Und natürlich kann ich mir auch totalen Murks zusammen gereimt haben, denn sicherlich sind die existierenden Implementierungen von fähigeren Architekten entworfen worden und haben bestimmt ihre Daseinsberechtigungen in einem Kontext, den ich vielleicht einfach noch nicht erfasst haben. Comments dazu wären wir sehr willkommen!</p>
<h2>Ausblick</h2>
<p>Die Lösung zentral über __call() ist die Schnelle, aber nicht optimale. Vorstellbar ist eine injizierung sämtlicher öffentlicher Methoden wie runkit_method_add, und ein globaler Accessor, der die Objektinstanz der Abhängigkeit liefert. Das ganze könnte man (optional) konfigurierbar gestalten (über Doctrine 2 Annotationen), um eventuellen Namenskonflikten auszuweichen.</p>
<h2>Test-Sourcen</h2>
<p>Die PHP-Quelltexte zu den obigen Beispielen kann man hier herunterladen:<br />
<a href="http://ifschleife.de/dependency_injection.tar.gz">http://ifschleife.de/dependency_injection.tar.gz</a></p>
<p>Ich habe die DoctrineCommon-Package bereits beigelegt, das Beispiel sollte also unter PHP5.3 funktionieren (bitte di.php aufrufen, der Rest ist noch durchsetzt mit Doctrine 2 Testklamotten).</p>
<p>Eine Anleitung, wie man Runkit unter php5.3 zum laufen kriegt, gibt es <a href="http://d.hatena.ne.jp/shimooka/20100729/1280379407">hier</a> (Japanisch, aber der Quelltext ist auf PHP ;))</p>
<p>Die Test-Sourcen liegen, wie in den obigen Codebeispielen beschrieben, unter lib/de/ifschleife. Ich möchte betonen, dass das nur eine Art Fallstudie ist, ich wäre aber über jeden Kommentar erfreut, der mir widerlegt oder bestätigt, ob man den programmatischen Ansatz vielleicht weiterverfolgen sollte. </p>
<p>Vielen Dank für die Aufmerksamkeit! :)</p>The post <a href="https://nerdpress.org/2010/09/26/dependency-injection-mit-php-5-3-runkit-erweiterung-und-doctrine-2-annotationen/">Dependency Injection mit PHP 5.3, Runkit-Erweiterung und Doctrine 2-Annotationen</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></content:encoded>
					
					<wfw:commentRss>https://nerdpress.org/2010/09/26/dependency-injection-mit-php-5-3-runkit-erweiterung-und-doctrine-2-annotationen/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
	</channel>
</rss>
