<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Pluginentwicklung on markob.de</title><link>https://markob.de/thema/pluginentwicklung/</link><description>Recent content in Pluginentwicklung on markob.de</description><generator>Hugo</generator><language>de-DE</language><lastBuildDate>Sat, 09 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://markob.de/thema/pluginentwicklung/index.xml" rel="self" type="application/rss+xml"/><item><title>Das LimeSurvey Plugin-Event-System – eine kritische Betrachtung</title><link>https://markob.de/limesurvey/plugin-event-kritik/</link><pubDate>Sat, 09 May 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/plugin-event-kritik/</guid><description>&lt;p&gt;LimeSurvey verfügt über ein event-basiertes Plugin-System. Plugins abonnieren Events, reagieren darauf, und können Daten zurückgeben. Das Konzept ist solide – und weit verbreitet in modernen Frameworks. Die Implementierung erzählt eine andere Geschichte.&lt;/p&gt;
&lt;h2 id="was-ein-event-system-leisten-soll"&gt;Was ein Event-System leisten soll&lt;/h2&gt;
&lt;p&gt;Ein Event kommuniziert, dass etwas passiert ist oder passieren wird. Der Name beschreibt das Ereignis. Die Parameter sind bekannt und garantiert. Der Empfänger reagiert – er fragt nicht erst nach, ob die Daten überhaupt vorhanden sind.&lt;/p&gt;</description></item><item><title>newDirectRequest – vollständige Webanwendungen im LimeSurvey-Plugin</title><link>https://markob.de/limesurvey/newdirectrequest-event/</link><pubDate>Sat, 09 May 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/newdirectrequest-event/</guid><description>&lt;p&gt;Der &lt;a href="https://markob.de/limesurvey-direct-event"&gt;&lt;code&gt;direct&lt;/code&gt;-Event&lt;/a&gt; ist der CLI-Einstiegspunkt für LimeSurvey-Plugins. &lt;code&gt;newDirectRequest&lt;/code&gt; ist sein HTTP-Pendant: ein Plugin wird über den Browser angesprochen, bekommt einen vollständigen HTTP-Request, und kann eine vollständige HTTP-Response zurückgeben.&lt;/p&gt;
&lt;p&gt;Was LimeSurvey dabei nicht mitliefert, ist Routing. Der Event landet im Plugin – was danach passiert, ist vollständig in der Verantwortung des Plugin-Entwicklers.&lt;/p&gt;
&lt;h2 id="wie-newdirectrequest-funktioniert"&gt;Wie &lt;code&gt;newDirectRequest&lt;/code&gt; funktioniert&lt;/h2&gt;
&lt;p&gt;Die URL, unter der ein Plugin erreichbar ist, folgt diesem Schema:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;https://example.com/index.php/plugins/direct/plugin/MeinPlugin
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Das Plugin abonniert den Event in &lt;code&gt;init()&lt;/code&gt; und prüft das Target – analog zu &lt;code&gt;direct&lt;/code&gt;, aber case-insensitiv, da URL-Parameter in der Praxis nicht immer exakt geschrieben werden:&lt;/p&gt;</description></item><item><title>Der direct-Event, gezielter CLI-Einstieg für LimeSurvey-Plugins</title><link>https://markob.de/limesurvey/direct-event/</link><pubDate>Fri, 08 May 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/direct-event/</guid><description>&lt;p&gt;Wenn ein Plugin nicht auf eine Benutzeraktion im Browser reagieren soll, sondern auf der Kommandozeile aufgerufen werden – für einen Cronjob, einen Datenexport, eine nächtliche Bereinigung –, dann ist &lt;code&gt;direct&lt;/code&gt; der richtige Einstiegspunkt.&lt;/p&gt;
&lt;h2 id="das-minimalbeispiel"&gt;Das Minimalbeispiel&lt;/h2&gt;
&lt;p&gt;Ein LimeSurvey-Plugin besteht aus mindestens zwei Dateien:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;upload/plugins/HelloWorld/
 config.xml
 HelloWorld.php
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Der Verzeichnisname, der Klassenname und der &lt;code&gt;&amp;lt;name&amp;gt;&lt;/code&gt;-Eintrag in der &lt;code&gt;config.xml&lt;/code&gt; müssen identisch sein.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;config&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;metadata&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;HelloWorld&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;type&amp;gt;&lt;/span&gt;plugin&lt;span class="nt"&gt;&amp;lt;/type&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.0.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;author&amp;gt;&lt;/span&gt;My Name&lt;span class="nt"&gt;&amp;lt;/author&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;description&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;![CDATA[Hello World via CLI]]&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/metadata&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;compatibility&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;6.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;5.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/compatibility&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/config&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HelloWorld&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;PluginBase&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$storage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;LimeSurvey\PluginManager\DbStorage&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;HelloWorld&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;HelloWorld&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;direct&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;direct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getEvent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;target&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;get_class&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;HELLO WORLD&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;PHP_EOL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nach der Aktivierung im Plugin-Manager wird das Plugin so aufgerufen:&lt;/p&gt;</description></item></channel></rss>