<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Thierry Feuzeu</title>
    <description>The latest articles on DEV Community by Thierry Feuzeu (@tiaya).</description>
    <link>https://dev.to/tiaya</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1601630%2F8855c307-86a6-4ac0-a769-430d2e2c618a.png</url>
      <title>DEV Community: Thierry Feuzeu</title>
      <link>https://dev.to/tiaya</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tiaya"/>
    <language>en</language>
    <item>
      <title>A real world case of recursion done right in PHP</title>
      <dc:creator>Thierry Feuzeu</dc:creator>
      <pubDate>Sun, 20 Sep 2026 09:51:49 +0000</pubDate>
      <link>https://dev.to/tiaya/a-real-world-case-of-recursion-done-right-in-php-428k</link>
      <guid>https://dev.to/tiaya/a-real-world-case-of-recursion-done-right-in-php-428k</guid>
      <description>&lt;p&gt;Nick Cosentino &lt;a href="https://x.com/DevLeaderCa" rel="noopener noreferrer"&gt;@DevLeaderCa&lt;/a&gt; posted this message about recursion on X, ex Twitter, in October 2025, which received over 460 replies.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1984123215170421060-448" src="https://platform.twitter.com/embed/Tweet.html?id=1984123215170421060"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1984123215170421060-448');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1984123215170421060&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;I quote an excerpt: &lt;em&gt;I've found that converting over to an iterative loop based approach is almost always more readable and easier to debug&lt;/em&gt;. He explains that in over 20 years of programming, he has never used recursion, thus questioning its usefulness.&lt;/p&gt;

&lt;p&gt;In this article, I show a real case where I used recursion, and where I think that it is much simpler than its iterative counterpart.&lt;/p&gt;

&lt;p&gt;But before going any further, let see what makes a recursive algorithm powerful.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fibonacci sequence
&lt;/h2&gt;

&lt;p&gt;To understand the value of recursion, let's look at the implementations with and without recursion of an algorithm very often used to illustrate it: the Fibonacci sequence.&lt;/p&gt;

&lt;p&gt;Here's the recursive algorithm.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if n = 0 or n = 1 then
    fib(n) = 1
else
    fib(n) = fib(n − 1) + fib(n − 2)
endif
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here's the iterative one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if n = 0 or n = 1 then
    fib(n) = 1
else
    a = 1
    b = 1
    for i in 2 .. n do
        c = a + b
        a = b
        b = c
    endfor
    fib(n) = c
endif
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This simple example demonstrates the advantages of recursion: no loops and no intermediate variables.&lt;/p&gt;

&lt;p&gt;This also gives us an indication of when recursion is advantageous, namely when the function can be defined with a simple expression depending on itself. This might not be the case for example when the data being processed is a graph instead of a tree.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our problem
&lt;/h2&gt;

&lt;p&gt;The library we'll be talking about is the &lt;a href="https://github.com/lagdo/ui-builder" rel="noopener noreferrer"&gt;PHP UI Builder&lt;/a&gt;. It builds application UIs using components, as defined by CSS frameworks. It provides a common API which defines the components, and from which specialized libraries can generate HTML code for a given CSS framework, like Bootstrap, Bulma or Tailwind CSS.&lt;/p&gt;

&lt;h3&gt;
  
  
  The UI components
&lt;/h3&gt;

&lt;p&gt;With its hierarchical component structure, a UI is particularly well-suited to a recursive algorithm. A component has properties, but can also contain components that themselves have some properties and can contain other components, and so on.&lt;/p&gt;

&lt;h3&gt;
  
  
  The virtual components
&lt;/h3&gt;

&lt;p&gt;When building a UI from data, the result can sometimes vary depending on their values. Some components will only be created under certain conditions, others are multiplied according to the entries in a list or loop, and others may be an aggregate of different components.&lt;/p&gt;

&lt;p&gt;To represent these cases, our library introduces the concept of virtual components. These are components that take a set of data as input and produce as output a set of zero or more components, which may or may not be virtual.&lt;/p&gt;

&lt;p&gt;There are 4 of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;When&lt;/strong&gt;: takes a condition as input and generates a component if it is met.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Each&lt;/strong&gt;: takes an array of data as input and generates a component for each element.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick&lt;/strong&gt;: takes a list of conditions as input and generates a different component depending on the first one that is true.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;List&lt;/strong&gt;: aggregates any set of components into one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A UI will ultimately consist of a tree structure of components, each of which can be virtual or real. A real component can have several children, each of which can be virtual or real, and a virtual component generates a list of components, each of which can be virtual or real.&lt;/p&gt;

&lt;p&gt;Here's an example of a function using the UI library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * @param array $collations
 *
 * @return string
 */&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;addDbForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$collations&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;form&lt;/span&gt;&lt;span class="p"&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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;row&lt;/span&gt;&lt;span class="p"&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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;col&lt;/span&gt;&lt;span class="p"&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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;label&lt;/span&gt;&lt;span class="p"&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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Name'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;col&lt;/span&gt;&lt;span class="p"&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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;setType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'text'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;when&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$collations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;setType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'hidden'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'collation'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;when&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$collations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;row&lt;/span&gt;&lt;span class="p"&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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;col&lt;/span&gt;&lt;span class="p"&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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;label&lt;/span&gt;&lt;span class="p"&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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Collation'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'collation'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;col&lt;/span&gt;&lt;span class="p"&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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'(collation)'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$collations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_collations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$group&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;pick&lt;/span&gt;&lt;span class="p"&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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;when&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$group&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_collations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$collation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$collation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                        &lt;span class="p"&gt;)&lt;/span&gt;
                                    &lt;span class="p"&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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;when&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;optgroup&lt;/span&gt;&lt;span class="p"&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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_collations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$collation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$collation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                            &lt;span class="p"&gt;)&lt;/span&gt;
                                        &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setLabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$group&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                    &lt;span class="p"&gt;)&lt;/span&gt;
                                &lt;span class="p"&gt;)&lt;/span&gt;
                            &lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'collation'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;width&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The processing algorithm
&lt;/h3&gt;

&lt;p&gt;To generate a UI from a component tree, we will use the following algorithm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function build(c)
    children = []
    expand(c, children)

    c.elements = []
    for child in children
        if child is a component then
            build(child)
            append child.elements to c.elements
        else
            append child to c.elements
        endif
    endfor
endfunction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function expand(c, children)
    if c is virtual then
        for child in c.children
            expand(child, children)
        endfor
    else
        append c to children
    endif
endfunction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we have here is actually a combination of two recursive functions.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;expand()&lt;/code&gt; function returns the list of real components generated by a virtual component. It will therefore iterate recursively over all its children as long as virtual components are present.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;build()&lt;/code&gt; function, which is the entry point for the process, first calls the &lt;code&gt;expand()&lt;/code&gt; function. Its list of children then consists only of real components, on which it executes recursively.&lt;/p&gt;

&lt;p&gt;The final result is in &lt;a href="https://github.com/lagdo/ui-builder-html/blob/main/src/Builder/Scope.php" rel="noopener noreferrer"&gt;the Scope class&lt;/a&gt;. In their PHP implementation, the recursive &lt;code&gt;expand()&lt;/code&gt; function is 15 lines of code long, and the &lt;code&gt;build()&lt;/code&gt; function is 40.&lt;/p&gt;

&lt;p&gt;Two extremely simple functions, which form the basis that allows the implementation in a single library of both the templating functionalities of libraries such as Twig or Blade, and the HTML code generation of libraries such as Spatie's &lt;a href="https://spatie.be/docs/laravel-html/v3/general-usage/html-builder" rel="noopener noreferrer"&gt;HTML Builder&lt;/a&gt; or Symfony's &lt;a href="https://symfony.com/doc/current/forms.html" rel="noopener noreferrer"&gt;Forms component&lt;/a&gt; (the rendering part).&lt;/p&gt;

&lt;p&gt;The UI library is used to build the &lt;a href="https://github.com/lagdo/jaxon-dbadmin/tree/main/app/Ui" rel="noopener noreferrer"&gt;Jaxon DbAdmin UI&lt;/a&gt;, demonstrating that it allows the construction of complex UIs, calling classes and their methods instead of writing HTML templates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo4rca0rouvf652rsj13n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo4rca0rouvf652rsj13n.png" alt="An overview of the Jaxon DbAdmin UI" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The limitations of recursion
&lt;/h2&gt;

&lt;p&gt;Nick Cosentino's message rightly points out two drawbacks of recursion, which we will briefly discuss here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Debugging
&lt;/h3&gt;

&lt;p&gt;First, it's absolutely true that recursion is difficult to debug, particularly because mentally unraveling the instructions executed by a recursive algorithm is very complex. However, at the same time, the simplicity of recursive algorithms leaves little chance for a bug to occur.&lt;/p&gt;

&lt;p&gt;Therefore, before choosing recursion, it's important to ensure that the algorithm being implemented can be expressed very simply in a recursive manner. This is indeed the case for the Fibonacci sequence and our library.&lt;/p&gt;

&lt;h3&gt;
  
  
  Memory usage
&lt;/h3&gt;

&lt;p&gt;Implementing a recursive algorithm can consume a significant amount of memory, depending on the level of nesting of the calls.&lt;br&gt;
For our UI library, the level of nesting of an application's UI components will always be very limited, and even more if it is built one part at a time, each in a separate recursive function call.&lt;/p&gt;

&lt;p&gt;Moreover, PHP imposes a limit on the number of nested calls within a recursive function, and the consequence of an overflow will be to fail a single call, not to crash the entire server.&lt;/p&gt;

&lt;h2&gt;
  
  
  The closing&amp;nbsp;word
&lt;/h2&gt;

&lt;p&gt;To answer Nick Cosentino's initial question, of course it is possible to create all sorts of complex software without using recursion.&lt;/p&gt;

&lt;p&gt;However, this doesn't mean it can always be replaced by an iterative version, but rather that cases where one can fully leverage all its advantages are not very common.&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>ui</category>
      <category>php</category>
      <category>recursion</category>
    </item>
    <item>
      <title>What if we improve the way developers are given access to databases</title>
      <dc:creator>Thierry Feuzeu</dc:creator>
      <pubDate>Fri, 03 Oct 2025 18:00:41 +0000</pubDate>
      <link>https://dev.to/tiaya/what-if-we-improve-the-way-developers-are-given-access-to-databases-3n0i</link>
      <guid>https://dev.to/tiaya/what-if-we-improve-the-way-developers-are-given-access-to-databases-3n0i</guid>
      <description>&lt;p&gt;Developers often need direct access to the databases used by the applications they work on, in virtually every environment of a project: development, testing, pre-production, and sometimes even in production.&lt;/p&gt;

&lt;p&gt;To do this, they use software such as &lt;a href="https://www.adminer.org/" rel="noopener noreferrer"&gt;Adminer&lt;/a&gt;, &lt;a href="https://www.phpmyadmin.net/" rel="noopener noreferrer"&gt;PhpMyAdmin&lt;/a&gt;, &lt;a href="https://dbeaver.io/" rel="noopener noreferrer"&gt;DBeaver&lt;/a&gt;, and many others, which share a common feature: they authenticate their users with database access parameters.&lt;br&gt;
This pushes teams within companies to share database access credentials with developers, which, in the best-case scenario, is done with a &lt;code&gt;password manager&lt;/code&gt; software.&lt;/p&gt;

&lt;p&gt;This sharing of database credentials can pose several risks.&lt;br&gt;
Accidental leaks of sensitive information, if a developer inadvertently shares this data with third parties.&lt;br&gt;
Reuse of credentials in inappropriate environments.&lt;br&gt;
Uncontrolled and untraceable access, due to the sharing of this information with multiple developers.&lt;br&gt;
Access by unauthorized individuals, when developers leave the company.&lt;/p&gt;

&lt;p&gt;Enforcing good security practices under these conditions will be difficult.&lt;/p&gt;

&lt;h3&gt;
  
  
  Jaxon DbAdmin
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Jaxon DbAdmin&lt;/strong&gt; is a web-based database management application that takes a different approach to user authentication and database connection.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foo8j4tl5xgp54si1fvul.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foo8j4tl5xgp54si1fvul.png" alt="Jaxon DbAdmin dashboard" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The application clearly separates the authentication of its users and the connections to databases. The parameters of the later are stored only in its configuration file on the server.&lt;/p&gt;

&lt;p&gt;When a user logs in, &lt;strong&gt;Jaxon DbAdmin&lt;/strong&gt; reads the list of databases they have access to from its configuration and presents it to them.&lt;br&gt;
And when the user performs an action on a database, &lt;strong&gt;Jaxon DbAdmin&lt;/strong&gt; reads the corresponding database credentials from its configuration, executes the action, and returns the result.&lt;br&gt;
This allows the user to access the database contents without having access to the database credentials.&lt;/p&gt;

&lt;p&gt;It's worth noting that this database access technique isn't exactly new.&lt;br&gt;
On the one hand, applications that use databases already store database credentials this way, and on the other, there are already database management applications that authenticate their users elsewhere than in the database.&lt;br&gt;
&lt;strong&gt;Jaxon DbAdmin&lt;/strong&gt; combines these two approaches to make it its default mode.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jaxon DbAdmin&lt;/strong&gt; is an open source software distributed under the BSD-3-Clause license: &lt;a href="https://github.com/lagdo/dbadmin-app" rel="noopener noreferrer"&gt;https://github.com/lagdo/dbadmin-app&lt;/a&gt;.&lt;br&gt;
A Docker image is also provided: &lt;a href="https://hub.docker.com/r/lagdo/jaxon-dbadmin" rel="noopener noreferrer"&gt;https://hub.docker.com/r/lagdo/jaxon-dbadmin&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Jaxon DbAdmin&lt;/strong&gt; is still actively developed, and some features are not yet available.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  The advantages
&lt;/h3&gt;

&lt;p&gt;Storing database credentials on the server only enhances security.&lt;br&gt;
Developers cannot copy, transfer, or expose credentials, even by mistake.&lt;br&gt;
Each request can be linked to a specific user or role, making it easy to audit who did what, and when.&lt;br&gt;
Login credentials are no longer scattered across development workstations, in configuration files, emails, or other communication tools. They can even be secured in a vault.&lt;/p&gt;

&lt;p&gt;Connection configuration is now managed at the platform or infrastructure level, not in the application code. This makes it easier to manage environments (dev, staging, production).&lt;br&gt;
Since users don't have access to the database credentials, they can be changed regularly without disrupting applications or developers.&lt;br&gt;
Similarly, if the credentials are compromised, the administrator won't have to change them on developer workstations. This is done in a single location, transparently for applications and users.&lt;/p&gt;

&lt;p&gt;There will also be better permission management based on the principle of least privilege: each user only has access to what he needs, regardless of the database credentials actually used.&lt;br&gt;
If a developer leaves, his access to the application can simply be revoked, without having to change the database password and impact all other applications and users.&lt;/p&gt;

&lt;p&gt;Finally, many security standards require strict data access management.&lt;br&gt;
Not sharing database credentials makes it easier to comply with these requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  The challenges
&lt;/h3&gt;

&lt;p&gt;Despite the above advantages, the use of existing tools that offer separate authentication is not common enough because it faces several challenges.&lt;/p&gt;

&lt;p&gt;Setting up and using a secrets management system (vault) or an API Gateway with the necessary permissions is complex. For a small team or on certain projects, this represents a significant overhead in terms of time, skills, and budget.&lt;br&gt;
On the other hand, tools such as &lt;a href="https://dbeaver.io/" rel="noopener noreferrer"&gt;DBeaver&lt;/a&gt; (Community) and &lt;a href="https://www.adminer.org/" rel="noopener noreferrer"&gt;Adminer&lt;/a&gt; are free and open-source.&lt;/p&gt;

&lt;p&gt;Certain complex tasks (analyzing indexes, optimizing queries, performing large-scale exports/imports) are much simpler with a graphical tool than with a command line or REST API.&lt;br&gt;
The same is true for analyzing the structure of a complex database with many tables.&lt;br&gt;
The user-friendliness of the graphical interface of tools like &lt;a href="https://dbeaver.io/" rel="noopener noreferrer"&gt;DBeaver&lt;/a&gt; or &lt;a href="https://www.adminer.org/" rel="noopener noreferrer"&gt;Adminer&lt;/a&gt; is a definite advantage.&lt;/p&gt;

&lt;p&gt;Experienced developers sometimes like to have direct control over the database.&lt;br&gt;
They appreciate the speed of an &lt;em&gt;ad hoc&lt;/em&gt; SQL query to explore a database schema, understand relationships between tables, or test complex logic before writing it in code.&lt;br&gt;
For occasional manipulations, connecting with a graphical tool seems faster.&lt;/p&gt;

&lt;p&gt;It is difficult to replicate an environment where direct access to the database is prohibited on a development workstation.&lt;br&gt;
Developers then need a local database to code on, and in this case, access security isn't a priority.&lt;br&gt;
&lt;a href="https://www.adminer.org/" rel="noopener noreferrer"&gt;Adminer&lt;/a&gt; or &lt;a href="https://dbeaver.io/" rel="noopener noreferrer"&gt;DBeaver&lt;/a&gt; are ideal for this, and the temptation is great to use the same tool for all environments.&lt;/p&gt;

&lt;p&gt;Many developers have always worked with direct database access.&lt;br&gt;
In many companies, sharing database access credentials is a historical and culturally entrenched practice. Changing this requires shifting processes and mindsets.&lt;br&gt;
Furthermore, not all developers are aware of the risks or alternative best practices.&lt;/p&gt;

&lt;h3&gt;
  
  
  In conclusion
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Jaxon DbAdmin&lt;/strong&gt; is a web-based database management application that separates user authentication and database connections, meaning that database credentials are not shared with users accessing them.&lt;br&gt;
Its configuration allows the administrator to define credentials for each user or group of users.&lt;/p&gt;

&lt;p&gt;It will therefore improve the security of access to databases, while maintaining the user-friendliness and simplicity of a graphical interface.&lt;/p&gt;

&lt;p&gt;Its code comes &lt;a href="https://github.com/vrana/adminer/" rel="noopener noreferrer"&gt;from Adminer&lt;/a&gt;, which has been refactored and modernized. Although its UI has also been modernized, it offers similar functions as &lt;a href="https://www.adminer.org/" rel="noopener noreferrer"&gt;Adminer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, &lt;strong&gt;Jaxon DbAdmin&lt;/strong&gt; is still actively developed, and some features are not yet available.&lt;/p&gt;

</description>
      <category>database</category>
      <category>security</category>
      <category>usermanagement</category>
      <category>webapp</category>
    </item>
    <item>
      <title>Announcing Jaxon version 5</title>
      <dc:creator>Thierry Feuzeu</dc:creator>
      <pubDate>Thu, 25 Sep 2025 17:44:56 +0000</pubDate>
      <link>https://dev.to/tiaya/announcing-jaxon-version-5-2m6k</link>
      <guid>https://dev.to/tiaya/announcing-jaxon-version-5-2m6k</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This post was originally published on the &lt;a href="https://www.jaxon-php.org/blog/2025/07/announcing-jaxon-version-5.html" rel="noopener noreferrer"&gt;Jaxon blog&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After more than two years of development, the version 5 of the Jaxon library is finally out!&lt;/p&gt;

&lt;p&gt;This release is an important step that I think will bring the Jaxon library to the next level, because it implements the features I hoped the library had when I started developing and using it more than ten years ago.&lt;/p&gt;

&lt;p&gt;So what's new in this release?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exported PHP classes are now called components, and they can be of three different types. Some components can be attached to DOM nodes, and used to set their content.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;call factories&lt;/code&gt; in PHP have been enriched, and now support calls to Javascript functions and event handlers, as well as their parameters.&lt;/li&gt;
&lt;li&gt;The command names and formats in responses are now more meaningful, and their processing in Javascript is improved. Deprecated commands have also been removed.&lt;/li&gt;
&lt;li&gt;The dialog libraries now contain only Javascript code, in a single and tiny object. They will therefore be much easier to create and maintain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let's dive more in depth into each of these new features.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Jaxon components
&lt;/h3&gt;

&lt;p&gt;In the previous versions of Jaxon, the webpage content was set exclusively using the HTML &lt;code&gt;id&lt;/code&gt; attribute.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;html&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'dom-element-id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each DOM element with dynamic content in a webpage content needed to be given a unique id, which will then be used to update its content. Keeping track of all those ids in an application was not an easy task.&lt;/p&gt;

&lt;p&gt;Jaxon 5 introduces a new &lt;a href="https://www.jaxon-php.org/docs/v5x/components/node-components.html" rel="noopener noreferrer"&gt;UI component&lt;/a&gt;, which is a Jaxon class that defines the content of a DOM element.&lt;br&gt;
It just needs to implement a method named &lt;code&gt;html()&lt;/code&gt;,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Jaxon\Demo\Calc\App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Calc&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;\Jaxon\App\NodeComponent&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;\Stringable&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&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="nf"&gt;view&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'jaxon::demo::calc::calc'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and to be bound to a DOM element in a webpage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="cp"&gt;&amp;lt;?=&lt;/span&gt; &lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;rq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Jaxon\Demo\Calc\App\Calc&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;render()&lt;/code&gt; method in the component can then be used to set the DOM element content, for example with an event handler.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-primary"&lt;/span&gt; &lt;span class="cp"&gt;&amp;lt;?=&lt;/span&gt;
        &lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;rq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Jaxon\Demo\Calc\App\Calc&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Clear&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, a click on the button will display the &lt;code&gt;jaxon::demo::calc::calc&lt;/code&gt; view in the &lt;code&gt;div&lt;/code&gt; element the UI component is bound to.&lt;/p&gt;

&lt;p&gt;The new components now make it very easy to build complex UI with Jaxon.&lt;/p&gt;

&lt;h3&gt;
  
  
  The call and selector factories
&lt;/h3&gt;

&lt;p&gt;Since one of the core features of Jaxon is to write UI components code in PHP on the server, it is important to be able to make calls to Javascript functions, define event handlers, and last but not the least, pass the contents of the webpage as parameters to those calls.&lt;br&gt;
That's the role of the &lt;code&gt;call factories&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;call factories&lt;/code&gt; have been around since the version 2, initially as the &lt;a href="https://www.jaxon-php.org/docs/v2x/advanced/jquery.html" rel="noopener noreferrer"&gt;JQuery PHP API&lt;/a&gt;.&lt;br&gt;
They have evolved a lot since then, and now they can make calls to the exported Jaxon classes, or to any Javascript function or object.&lt;br&gt;
They can also define event handlers on the webpage elements using Javascript or JQuery-style selectors.&lt;br&gt;
Thirdly, they also provides functions to pass any content of the webpage as parameter to Javascript calls.&lt;/p&gt;

&lt;p&gt;In this code from the Jaxon examples, JQuery selectors are used in a Jaxon custom HTML attribute to define calls to Jaxon classes as event handlers on two select lists, and to pass the selected item value as parameter to the handler.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt; &lt;span class="cp"&gt;&amp;lt;?=&lt;/span&gt; &lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.app-color-choice'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'change'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;rq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AppTest&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;jq&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;val&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.ext-color-choice'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'change'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;rq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ExtTest&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;jq&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;val&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this other example, a command is added in a response to make a call to the &lt;code&gt;Tontine.makeTableResponsive('content-planning-charge-page')&lt;/code&gt; Javascript code in the browser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;jo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Tontine'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;makeTableResponsive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'content-planning-charge-page'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When building an application UI on the server, being able to make Javascript calls and set event handlers in a webpage is paramount, and the &lt;code&gt;call factories&lt;/code&gt; provide Jaxon with a powerful set of features to achieve that quite easily.&lt;/p&gt;

&lt;h3&gt;
  
  
  Javascript library rewrite
&lt;/h3&gt;

&lt;p&gt;The Javascript library rewrite started as a discusion on Github about &lt;a href="https://github.com/jaxon-php/jaxon-js/issues/21" rel="noopener noreferrer"&gt;the forbidden usage of the eval function&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I then decided to rewrite the Javascript library, which today has resulted in many important changes.&lt;/p&gt;

&lt;p&gt;The library now includes a command processor which executes existing Javascript functions from a JSON payload. With this processor, there's no need for the &lt;code&gt;eval&lt;/code&gt; function anymore, and it is also at the foundation of the &lt;code&gt;call factories&lt;/code&gt; described above.&lt;/p&gt;

&lt;p&gt;The library also includes an attribute processor, which handles the Jaxon custom attributes needed to implement the UI components bindings and the event handlers.&lt;br&gt;
In the example above where the &lt;code&gt;Jaxon\Demo\Calc\App\Calc&lt;/code&gt; UI Component is bound to a &lt;code&gt;div&lt;/code&gt; element, the following HTML code is actually generated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;jxn-bind=&lt;/span&gt;&lt;span class="s"&gt;"Jaxon.Demo.Calc.App.Calc"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
...
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://www.jaxon-php.org/docs/v5x/features/responses.html" rel="noopener noreferrer"&gt;response commands&lt;/a&gt; were also rewritten with new names and a new JSON format. Their names are now more meaningful, and the obsolete ones were removed.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Dialog plugin
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://www.jaxon-php.org/docs/v5x/ui-features/dialogs.html" rel="noopener noreferrer"&gt;Dialog plugin&lt;/a&gt; is a special case in the Jaxon universe. It is a Jaxon response plugin, but at the same time it can also be extended with it own plugins.&lt;/p&gt;

&lt;p&gt;In the previous version, adding a dialog plugin required to write functions in both PHP and Javascript.&lt;br&gt;
In the v5 release, only a tiny Javascript object is now necessary.&lt;/p&gt;

&lt;p&gt;This is for example the code of the &lt;a href="https://notifyjs.jpillora.com/" rel="noopener noreferrer"&gt;Notify&lt;/a&gt; library integration, which implements the alert function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="n"&gt;jaxon&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dom&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;jaxon&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dialog&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'notify'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Dialogs options&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;alertOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="no"&gt;xTypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;success&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'success'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'info'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;warning&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'warn'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Show an alert message
     *
     * @param {object} alert The alert parameters
     * @param {string} alert.type The alert type
     * @param {string} alert.message The alert message
     *
     * @returns {void}
     */&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="n"&gt;alertOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;className&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;xTypes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="n"&gt;xTypes&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"top center"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only feature in PHP classes is to load the Javascript files into the webpage.&lt;/p&gt;

&lt;h3&gt;
  
  
  The examples
&lt;/h3&gt;

&lt;p&gt;A &lt;a href="https://www.jaxon-php.org/docs/v5x/about/example.html" rel="noopener noreferrer"&gt;new example&lt;/a&gt; is introduced to illustrate the Jaxon operation.&lt;/p&gt;

&lt;p&gt;The example now implements a simple calculator, which takes an operation and two operands as parameters, performs the calculation using an injected service, and displays the result.&lt;br&gt;
There are two text zones and a select combo for the inputs, and the result is displayed in a readonly text zone.&lt;/p&gt;

&lt;p&gt;The example is built with the new Jaxon UI components, and also released as a &lt;a href="https://github.com/jaxon-php/jaxon-demo-calc" rel="noopener noreferrer"&gt;Jaxon package&lt;/a&gt;.&lt;br&gt;
This package is used in the &lt;a href="https://github.com/jaxon-php/jaxon-demo-laravel" rel="noopener noreferrer"&gt;Laravel&lt;/a&gt;, &lt;a href="https://github.com/jaxon-php/jaxon-demo-symfony" rel="noopener noreferrer"&gt;Symfony&lt;/a&gt; and &lt;a href="https://github.com/jaxon-php/jaxon-demo-slim" rel="noopener noreferrer"&gt;Slim Framework&lt;/a&gt; demo applications, to show how the Jaxon library can be used to build a cross-framework and full-featured package including both the frontend and backend features.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/lagdo/dbadmin-mono" rel="noopener noreferrer"&gt;DB Admin&lt;/a&gt; package and the &lt;a href="https://github.com/lagdo/tontine" rel="noopener noreferrer"&gt;African Tontine&lt;/a&gt; application are also upgraded to Jaxon 5.&lt;br&gt;
Although the former is still a work in progress, both are real world examples of building complex one page Ajax applications with Jaxon.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;The new Jaxon 5 release is packed with features that make it a good choice for creating complex Ajax applications with PHP on the server side.&lt;br&gt;
There are UI components to build the webpage, custom attributes to enrich the HTML code, and powerful &lt;code&gt;call factories&lt;/code&gt; to make calls to all kind of Javascript functions in PHP.&lt;/p&gt;

&lt;p&gt;In addition to the &lt;a href="https://www.jaxon-php.org/docs.html" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;, there are &lt;a href="https://github.com/jaxon-php/jaxon-examples" rel="noopener noreferrer"&gt;many examples&lt;/a&gt; in PHP or with framework integration, and real world open source applications using the library.&lt;/p&gt;

</description>
      <category>php</category>
      <category>ajax</category>
      <category>uicomponents</category>
      <category>releaseannouncement</category>
    </item>
  </channel>
</rss>
