<?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: neoan</title>
    <description>The latest articles on DEV Community by neoan (@sroehrl).</description>
    <link>https://dev.to/sroehrl</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F240649%2F1dce7d10-afb9-4784-848d-92e1a41d9249.png</url>
      <title>DEV Community: neoan</title>
      <link>https://dev.to/sroehrl</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sroehrl"/>
    <language>en</language>
    <item>
      <title>The humor of JavaScript</title>
      <dc:creator>neoan</dc:creator>
      <pubDate>Sat, 09 Dec 2023 21:21:29 +0000</pubDate>
      <link>https://dev.to/sroehrl/the-humor-of-javascript-1oae</link>
      <guid>https://dev.to/sroehrl/the-humor-of-javascript-1oae</guid>
      <description>&lt;p&gt;As the year marks its end and we are therefore exposed to the yearly "What to use in 2024" click-bait articles, let's instead amuse us with some oddities of JavaScript. &lt;/p&gt;

&lt;h2&gt;
  
  
  Numbers
&lt;/h2&gt;

&lt;p&gt;You can't divide by zero. But why not? If I divide 1 by smaller and smaller fractions, I'll be getting higher and higher numbers nearing infinity. So eventually we'd end up at infinity? Not so fast. If we "came from the other side" towards zero, we'd approach negative infinity when getting to zero:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;0.0001&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 1,000&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;0.000001&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 100,0000&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/-&lt;/span&gt;&lt;span class="mf"&gt;0.000001&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// -100,0000&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/-&lt;/span&gt;&lt;span class="mf"&gt;0.0000001&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// -1,000,0000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So what does JavaScript do when dividing by zero? "NaN" maybe? Nope, it goes for infinity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&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="c1"&gt;// Infinity&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Interesting. That means that the type of 1/0 must be infinity? Nope, it's NaN (Not a number).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="mi"&gt;1&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="c1"&gt;// NaN&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, so infinity doesn't seem to be a type, then? Let's test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="kc"&gt;Infinity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// number&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait a second, you think? If infinity is a number and 1/0 is infinity, why is the type of 1/0 not a number (NaN)? Well, let's explore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// number&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;NaN&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Confused, yet?&lt;/p&gt;

&lt;h2&gt;
  
  
  Objects
&lt;/h2&gt;

&lt;p&gt;What's so nice about having no type safety is that we can be quick &amp;amp; dirty. So dirty indeed, that nearly every company will insist on Typescript to avoid almost impossible to find bugs. Let's examine the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;myObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getFromBackend&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
  &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&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;// result: {a: "b"}&lt;/span&gt;
    &lt;span class="nx"&gt;myObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&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="c1"&gt;// SpongeBob narrator: ..several hours later&lt;/span&gt;

&lt;span class="c1"&gt;// Is our variable myObject filled?&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;checkIfValid&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;myObject&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
   &lt;span class="c1"&gt;// do something&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;Seems logical to a beginner, but here's the culprit&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// object&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But then again, we all know objects aren't object anyway, right?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({}&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  OMG, what a language
&lt;/h2&gt;

&lt;p&gt;Using the type-safe comparison (===) is therefore a must, as otherwise the nightmare would be so much worse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are even books about JavaScript oddities, as this list could go on for a while. But I guess we'd rather go on reddit to bash on PHP so Santa doesn't put us on the naughty list ;-)&lt;/p&gt;

</description>
      <category>watercooler</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>My favorite sveltekit setup</title>
      <dc:creator>neoan</dc:creator>
      <pubDate>Fri, 08 Sep 2023 16:55:14 +0000</pubDate>
      <link>https://dev.to/sroehrl/my-favorite-sveltekit-setup-2k60</link>
      <guid>https://dev.to/sroehrl/my-favorite-sveltekit-setup-2k60</guid>
      <description>&lt;p&gt;What I immediately liked about the UI kit &lt;strong&gt;flowbite&lt;/strong&gt; was its dark-mode integration. Meanwhile, it has grown into one of the most popular tailwind component libraries and has graced the svelte community with a solid component library. &lt;/p&gt;

&lt;p&gt;However, setup, customization and adding common structure &amp;amp; utilities is a waste of time if your goal is to jump right into development. &lt;/p&gt;

&lt;p&gt;After using our boilerplate within the company, it is now open sourced and ready for your consideration: &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Repo&lt;/th&gt;
&lt;th&gt;Hosted&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/sroehrl/svelte-flowbite-boilerplate"&gt;github&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://sroehrl.github.io/svelte-flowbite-boilerplate"&gt;gh page&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  My one minute setup
&lt;/h2&gt;

&lt;p&gt;After running the npx command, I quickly adjust colors in &lt;em&gt;src/lib/colors.js&lt;/em&gt;. Then I share the complete project on Github. In order to enable easy client reviews, I go to the settings of the repository and enable Github pages based on Github actions (the package is equipped with a deployment script triggered at pushes/pulls to "main", there's nothing additional you need to do).&lt;br&gt;
Next, I adjust the file &lt;em&gt;static/manifest.json&lt;/em&gt; to my needs.&lt;br&gt;
That's it: I am ready to develop. &lt;/p&gt;

</description>
      <category>svelte</category>
      <category>webdev</category>
      <category>sveltekit</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>SvelteKit as PWA on GitHub pages or your own server</title>
      <dc:creator>neoan</dc:creator>
      <pubDate>Wed, 23 Aug 2023 19:54:10 +0000</pubDate>
      <link>https://dev.to/sroehrl/sveltekit-as-pwa-on-github-pages-or-your-own-server-1f7l</link>
      <guid>https://dev.to/sroehrl/sveltekit-as-pwa-on-github-pages-or-your-own-server-1f7l</guid>
      <description>&lt;h2&gt;
  
  
  What you can expect
&lt;/h2&gt;

&lt;p&gt;I needed something to jump-start development and couldn't find the right kind of starter package to actually save time, so here is a sveltekit boilerplate fulfilling the following needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tailwind installed &amp;amp; set up&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://flowbite-svelte.com/"&gt;Flowbite Svelte&lt;/a&gt; because it's awesome&lt;/li&gt;
&lt;li&gt;Color generator for CI adaptations&lt;/li&gt;
&lt;li&gt;GitHub action to deploy to GitHub pages during review cycles&lt;/li&gt;
&lt;li&gt;Zero configuration PWA support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
  summary
  &lt;br&gt;
Installation via npx&lt;br&gt;
Installation via GitHub template&lt;br&gt;
About colors&lt;br&gt;
Deploying on GitHub pages&lt;br&gt;
PWA pitfalls&lt;br&gt;


&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation via npx
&lt;/h2&gt;

&lt;p&gt;It doesn't get any faster than that. Be up &amp;amp; running in approx. 30 seconds when installing via npx (the command is available if you have npm installed)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx svelte-flowbite-boilerplate@latest &amp;lt;project-name&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The command checks whether you have yarn installed, and falls back to npm if not. Either way, just follow the instructions given to you after installation and you are ready to develop.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;p&gt;This is by far the fastest way to start developing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;p&gt;This will not create a GIT repository. &lt;/p&gt;

&lt;h2&gt;
  
  
  Installation via GitHub template
&lt;/h2&gt;

&lt;p&gt;Use the "use template" button at the &lt;a href="https://github.com/sroehrl/svelte-flowbite-boilerplate"&gt;repo&lt;/a&gt; to create your own copy of the repository and check your project out from there. &lt;/p&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;p&gt;You can directly work in GitHub's VSCode environment on the fly. &lt;/p&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;p&gt;The process takes slightly longer.&lt;/p&gt;

&lt;h2&gt;
  
  
  About colors
&lt;/h2&gt;

&lt;p&gt;As mentioned, the package comes with a color palette generator. In order to use it, open "src/lib/colors.js" and change/add colors as you please.&lt;br&gt;
Note that some named colors of flowbite-svelte can be overwritten like that as well (e.g. primary, red, etc.).&lt;/p&gt;

&lt;p&gt;When serving the project, you can navigate to /docs to see your colors rendered.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rlPQF3bB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7c8ub4fn9fpbywjurali.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rlPQF3bB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7c8ub4fn9fpbywjurali.png" alt="Rendered colors" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Deploying on GitHub pages
&lt;/h2&gt;

&lt;p&gt;Whether you want to make use of free hosting, or to show your team/clients your work in progress: you can choose to deploy your project on GitHub pages by simply going to your repo's settings and activating the pages using GitHub actions. The script is already set up and ready to be used.&lt;/p&gt;

&lt;p&gt;An example of that can be seen at the repository itself:&lt;br&gt;
&lt;a href="https://sroehrl.github.io/svelte-flowbite-boilerplate"&gt;gh-page of svelte-flowbite-boilerplate&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  PWA pitfalls
&lt;/h2&gt;

&lt;p&gt;The PWA runs out of the box, but some things aren't automated yet. To adjust everything to your needs, (re-)visit the manifest.json and the icons in the folder "/static"&lt;/p&gt;

&lt;p&gt;
  note!
  &lt;br&gt;
You might encounter issues if you are reusing this repo as the webworker get's confused when running another app on the same localhost port. Clear your browser's site data if that occurs. &lt;br&gt;


&lt;/p&gt;

&lt;h2&gt;
  
  
  That's it to get you started
&lt;/h2&gt;

&lt;p&gt;If you need details as you aren't familiar with one of the tools used, please use the links provided in the docs. You will find that the people at flowbite-svelte did a great job of making your process as easy as it gets.&lt;br&gt;
Lastly, if you like this boilerplate, please be so kind and star the repository.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/sroehrl"&gt;
        sroehrl
      &lt;/a&gt; / &lt;a href="https://github.com/sroehrl/svelte-flowbite-boilerplate"&gt;
        svelte-flowbite-boilerplate
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      General svelte-flowbite starter kit
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
REtech svelte kit app starter / boilerplate&lt;/h1&gt;
&lt;p&gt;Quick start for a svelte PWA powered by flowbite&lt;/p&gt;
&lt;h3&gt;
Preview&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://sroehrl.github.io/svelte-flowbite-boilerplate" rel="nofollow"&gt;@ github pages&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
includes&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;typescript&lt;/li&gt;
&lt;li&gt;flowbite&lt;/li&gt;
&lt;li&gt;tailwind&lt;/li&gt;
&lt;li&gt;flowbite icons&lt;/li&gt;
&lt;li&gt;color palette generator&lt;/li&gt;
&lt;li&gt;dayjs&lt;/li&gt;
&lt;li&gt;external API for REST backend (we recommend &lt;a href="https://lenkrad.neoan3.rocks" rel="nofollow"&gt;https://lenkrad.neoan3.rocks&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
Creating a project using &lt;code&gt;npx&lt;/code&gt;
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;npx svelte-flowbite-boilerplate@latest &amp;lt;project-name&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;check deployment base in &lt;code&gt;svelte.config.js&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
Creating a project using github's repository template&lt;/h2&gt;
&lt;p&gt;Use the template button at &lt;a href="https://github.com/sroehrl/svelte-flowbite-boilerplate"&gt;https://github.com/sroehrl/svelte-flowbite-boilerplate&lt;/a&gt; to start a new project&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;create .env (or .env.development, .env.deployment)&lt;/li&gt;
&lt;li&gt;setup src/lib/colors.js&lt;/li&gt;
&lt;li&gt;change base in &lt;code&gt;svelte.config.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;yarn&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;yarn dev&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
Ready for GitHub pages&lt;/h2&gt;
&lt;p&gt;This package contains GitHub actions to automatically deploy your app on GitHub pages. To activate, simply go to "Settings &amp;gt; Pages"
and use "GitHub Actions" as your source.&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/sroehrl/svelte-flowbite-boilerplate"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>svelte</category>
      <category>sveltekit</category>
      <category>webdev</category>
    </item>
    <item>
      <title>i18n: A lot to think about</title>
      <dc:creator>neoan</dc:creator>
      <pubDate>Sun, 21 Aug 2022 23:17:00 +0000</pubDate>
      <link>https://dev.to/sroehrl/i18n-a-lot-to-think-about-36a1</link>
      <guid>https://dev.to/sroehrl/i18n-a-lot-to-think-about-36a1</guid>
      <description>&lt;p&gt;When we think of internationalization, we usually think of translating content in various languages. But it is so much more than that. Let's look at the following topics and how to solve all of them with &lt;strong&gt;one&lt;/strong&gt; library.&lt;/p&gt;

&lt;h2&gt;
  
  
  Number formatting
&lt;/h2&gt;

&lt;p&gt;How hard can it be? Well, decimal notations alone are a point of contention. Sometimes even within a country (looking at you, Canada)&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--im0Ww3aj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uq5f8ox2qygny58fax1k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--im0Ww3aj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uq5f8ox2qygny58fax1k.png" alt="Image description" width="800" height="406"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;light blue: dot, green: comma, teal: both, red: Arabic decimal symbol (U+2396)&lt;/em&gt;&lt;br&gt;
Especially the Arabic notation is tricky as it looks like an apostrophe but isn't. This means that screen readers might misinterpret numbers. But even the most common differences can be confusing: in a scientific paper, translations of something like&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;... ergab eine Fehlerquote von 13,935%. &lt;br&gt;
[German]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;... showed an error rate of 13,935%.&lt;br&gt;
[English]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;would be a horrible mistranslation just based on the decimal point alone.&lt;/p&gt;

&lt;p&gt;If we add currency to the mix, things become even weirder:&lt;/p&gt;

&lt;p&gt;$9.99 or 9,99 $?&lt;/p&gt;

&lt;p&gt;You see where I am going with this; in order to be truly localized, we have to rely on trustworthy resources to even have a chance to get it right. Thankfully, PHP has an extension for that called &lt;code&gt;Intl&lt;/code&gt;. But before you jump onto php.net to find out that you opened Pandora's box, worry not: there is an easier approach. &lt;br&gt;
But first, let's look at another common issue:&lt;/p&gt;
&lt;h2&gt;
  
  
  Date, Time &amp;amp; localization
&lt;/h2&gt;

&lt;p&gt;I am probably not the only one with the luxury of having meetings with people from various time zones. And applications have gotten good at it. Zoom &amp;amp; Co invite me for the correct localized time so I don't have to think about the pain of Europe not switching between daylight saving time on the same day or India having time zones that my brain refuses to calculate because they the difference can't even be expressed in full hours. As a developer, I need both, though. I need to format the date or time correctly for the user &lt;strong&gt;AND&lt;/strong&gt; decide whether or not I want the context to be relative to the user or not. &lt;/p&gt;

&lt;p&gt;An example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;My body still wasn't used to the sun at 1 am, so I had difficulties sleeping at the small hotel in Reykjavík I naively booked with a view of the northern lights in mind.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So sure, you want the international reader to "experience" 1 am in the suitable format, but not "translate" the time to the time zone our reader resides. On the other hand, if you take this example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The event will take place virtually on Wednesday, August 20th at 11 pm PDT.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You most certainly will want to make sure that this information is accurately transcribed into whatever that actually means for the reader. As you can see, full control over the behavior is necessary.&lt;/p&gt;
&lt;h2&gt;
  
  
  Good ol' text translation
&lt;/h2&gt;

&lt;p&gt;So, we talked about everything but actual translations. Besides the fact that as someone being fluent in more than one language, I don't believe in the word "translation" to begin with (It implies that meaning could be 100% transferable between languages). On a linguistic meta level, this can be shown on the following things:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;German&lt;/th&gt;
&lt;th&gt;English&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0 Autos, 1 Auto, 2 Autos&lt;/td&gt;
&lt;td&gt;0 cars, 1 car, 2 cars&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0 Bakterien, 1 Bakterium, 2 Bakterien&lt;/td&gt;
&lt;td&gt;0 bacteria, 1 bacterium, 2 bacteria&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0 Informationen, 1 Information, 2 Informationen&lt;/td&gt;
&lt;td&gt;information, information, information&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Let's look at row 1:&lt;/p&gt;

&lt;p&gt;So in English, it seems to be the case that a singular is only used when we are talking about exactly ONE (And zero plural?!). And if we compare it to German, then this seems to be a thing for other languages as well. So in pseudo code, our logic would somehow have to account for that. &lt;/p&gt;

&lt;p&gt;In row 2,&lt;/p&gt;

&lt;p&gt;we are reminded of the fact that irregular plurals are a thing in many language, but you really start to get an insight into the nightmare in &lt;/p&gt;

&lt;p&gt;row 3,&lt;/p&gt;

&lt;p&gt;where we have to face the reality that things might be countable in some languages, but not in others. And don't forget, these languages are rather similar in comparison. Let's be a little mean:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Japanese&lt;/th&gt;
&lt;th&gt;English&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;一枚&lt;/td&gt;
&lt;td&gt;one (e.g. when counting paper)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;一本&lt;/td&gt;
&lt;td&gt;one (e.g. when counting pencils)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;一頭&lt;/td&gt;
&lt;td&gt;one (e.g. when counting elephants)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;一杯&lt;/td&gt;
&lt;td&gt;one (e.g. when counting cups)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Practicality
&lt;/h2&gt;

&lt;p&gt;Lastly, we have to ask us how much time we have in order to offer as a solution to these problems, so many companies make use of AI-based translations that are either rather unreliable (like google translate) or extremely expensive. To mitigate this issue, and since PHP's Intl offers the toolset to address these issues, I wrote an i18n script that let's you write server-side rendered HTML with extended markup (template engine).&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/sroehrl"&gt;
        sroehrl
      &lt;/a&gt; / &lt;a href="https://github.com/sroehrl/php-i18n-translate"&gt;
        php-i18n-translate
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Simple yet powerful i18n support for PHP
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
PHP i18n translate&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;Straight forward. Convenient. Fast.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/sroehrl/php-i18n-translate/actions/workflows/php.yml"&gt;&lt;img src="https://github.com/sroehrl/php-i18n-translate/actions/workflows/php.yml/badge.svg" alt="Build"&gt;&lt;/a&gt;
&lt;a href="https://github.com/sroehrl/php-i18n-translate/actions/workflows/php.yml"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--or5JKErQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/sroehrl/php-i18n-translate/badges/.github/badges/test-badge.svg" alt="Coverage"&gt;&lt;/a&gt;
&lt;a href="https://php.net" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/e74964fe58a31df084594876ad7ced9151b901c5c71ac243ba548be1c52f7ffa/68747470733a2f2f696d672e736869656c64732e696f2f7374617469632f76313f6c6162656c3d504850266d6573736167653d576974682532304c6f766526636f6c6f723d373737424234266c6f676f3d706870" alt="php"&gt;&lt;/a&gt;
&lt;a href="https://www.whyveganism.com/" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/640810f22c99c00673702132bc54580a2a24a8a00bf6d4c8dc2c4690840e7679/68747470733a2f2f696d672e736869656c64732e696f2f7374617469632f76313f6c6162656c3d31303025266d6573736167653d766567616e26636f6c6f723d343761323434266c6f676f3d6d6f6e676f6462" alt="vegan"&gt;&lt;/a&gt;
&lt;a href="https://codeclimate.com/github/sroehrl/php-i18n-translate/maintainability" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/ea2337ac0d06854bc17347094cfcce0ea719241e49987d2977daabb9d50768da/68747470733a2f2f6170692e636f6465636c696d6174652e636f6d2f76312f6261646765732f35623635306465373230656238303261383461392f6d61696e7461696e6162696c697479" alt="Maintainability"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
Installation&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;composer require sroehrl/php-i18n-translate&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight highlight-text-html-php notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;require_once&lt;/span&gt; &lt;span class="pl-s"&gt;'vendor/autoload.php'&lt;/span&gt;;

&lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;i18n&lt;/span&gt; = &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-v"&gt;I18nTranslate&lt;/span&gt;\&lt;span class="pl-v"&gt;Translate&lt;/span&gt;();

&lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;i18n&lt;/span&gt;-&amp;gt;&lt;span class="pl-en"&gt;setTranslations&lt;/span&gt;(&lt;span class="pl-s"&gt;'de'&lt;/span&gt;, [
    &lt;span class="pl-s"&gt;'hello'&lt;/span&gt; =&amp;gt; &lt;span class="pl-s"&gt;'hallo'&lt;/span&gt;,
    &lt;span class="pl-s"&gt;'goose'&lt;/span&gt; =&amp;gt; [&lt;span class="pl-s"&gt;'Gans'&lt;/span&gt;, &lt;span class="pl-s"&gt;'Gänse'&lt;/span&gt;]
]);&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
Quick start:&lt;/h2&gt;
&lt;h3&gt;
1. In Code&lt;/h3&gt;
&lt;div class="highlight highlight-text-html-php notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;echo&lt;/span&gt; "&lt;span class="pl-s"&gt;a: &lt;/span&gt;" . &lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;i18n&lt;/span&gt;-&amp;gt;&lt;span class="pl-en"&gt;t&lt;/span&gt;(&lt;span class="pl-s"&gt;'hello'&lt;/span&gt;) . "&lt;span class="pl-s"&gt;&amp;lt;br&amp;gt;&lt;/span&gt;"; 
&lt;span class="pl-k"&gt;echo&lt;/span&gt; "&lt;span class="pl-s"&gt;b: &lt;/span&gt;" . &lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;i18n&lt;/span&gt;-&amp;gt;&lt;span class="pl-en"&gt;t&lt;/span&gt;(&lt;span class="pl-s"&gt;'goose'&lt;/span&gt;) . "&lt;span class="pl-s"&gt;&amp;lt;br&amp;gt;&lt;/span&gt;";
&lt;span class="pl-k"&gt;echo&lt;/span&gt; "&lt;span class="pl-s"&gt;c: &lt;/span&gt;" . &lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;i18n&lt;/span&gt;-&amp;gt;&lt;span class="pl-en"&gt;t&lt;/span&gt;(&lt;span class="pl-s"&gt;'goose.plural'&lt;/span&gt;) . "&lt;span class="pl-s"&gt;&amp;lt;br&amp;gt;&lt;/span&gt;";

&lt;span class="pl-c"&gt;// detect plural by numeric value&lt;/span&gt;
&lt;span class="pl-k"&gt;foreach&lt;/span&gt;([&lt;span class="pl-c1"&gt;0&lt;/span&gt;,&lt;span class="pl-c1"&gt;1&lt;/span&gt;,&lt;span class="pl-c1"&gt;2&lt;/span&gt;] &lt;span class="pl-k"&gt;as&lt;/span&gt; &lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;number&lt;/span&gt;){
    &lt;span class="pl-k"&gt;echo&lt;/span&gt; &lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;number&lt;/span&gt; . "&lt;span class="pl-s"&gt; &lt;/span&gt;" . &lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;i18n&lt;/span&gt;-&amp;gt;&lt;span class="pl-en"&gt;t&lt;/span&gt;(&lt;span class="pl-s"&gt;'goose'&lt;/span&gt;, &lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;number&lt;/span&gt;) . "&lt;span class="pl-s"&gt;, &lt;/span&gt;";
}&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Outputs:&lt;/p&gt;
&lt;div class="highlight highlight-text-html-basic notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;a: hallo &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;br&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
b: Gans &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;br&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
c: Gänse &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;br&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/sroehrl/php-i18n-translate"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;It addresses our issues like such:&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="c1"&gt;// little pseudo code, but you get it:&lt;/span&gt;
&lt;span class="nv"&gt;$productModelData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SomeORM&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getProduct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_GET&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'productId'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="nv"&gt;$t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;I18nTranslate\Translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$userLocale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$userTimezone&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTranslationsAndSomeSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// I already apologize for the formatting&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$t&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="nc"&gt;Neoan3\Apps\Template\Template&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;embraceFromFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s1"&gt;'/theHTMLbelowThisCode.html'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'product'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$productModelData&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- A simple static translation using a t-tag --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&amp;lt;t&amp;gt;&lt;/span&gt;Welcome to our page!&lt;span class="nt"&gt;&amp;lt;/t&amp;gt;&amp;lt;h1&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- B simple static translation using a template function --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;{{t('Welcome to our page')}}&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;article&amp;gt;&lt;/span&gt;
   &lt;span class="c"&gt;&amp;lt;!-- C There's a lot going on here, we'll break it down later  --&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;t&amp;gt;&lt;/span&gt;Check out [%product-name%](%{{product.title}}%)&lt;span class="nt"&gt;&amp;lt;t/&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt; 
   &lt;span class="c"&gt;&amp;lt;!-- D show USD price, but show in user's format --&amp;gt;&lt;/span&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;"price"&lt;/span&gt; &lt;span class="na"&gt;i18n-currency=&lt;/span&gt;&lt;span class="s"&gt;"USD"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
     {{product.price}}
   &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&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;"special offer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;t&amp;gt;&lt;/span&gt;Convincing text to make you buy in the next:&lt;span class="nt"&gt;&amp;lt;/t&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- E Yes, this works --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;i18n-time=&lt;/span&gt;&lt;span class="s"&gt;"m"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;+2 min&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;br&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- F Prints something like: Wednesday, 12.10.2022 10:30 Eastern Daylight Time --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;i18n-date-local=&lt;/span&gt;&lt;span class="s"&gt;"EEEE, dd.MM.Y HH:mm zzzz"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
           {{product.realease}}
        &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&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;"very-special-offer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- G for  "gettin' very dynamic here" --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;t&amp;gt;&lt;/span&gt;Buy [%number%](% {{product.offerCount}} %) for only {{i18n-currency(product.discountedPrice * product.offerCount, 'USD')}} today!&lt;span class="nt"&gt;&amp;lt;/t&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  So I guess a little explanation wouldn't hurt?
&lt;/h2&gt;

&lt;p&gt;As you noticed, I started each comment with a letter for our reference:&lt;/p&gt;

&lt;h3&gt;
  
  
  A - T-tag
&lt;/h3&gt;

&lt;p&gt;In most cases, this will be enough. This tag runs after all other substitutions unless you additionally give the tag itself i18n-attributes. The outcome is a substitution of its content with the corresponding translation:&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="c1"&gt;//...&lt;/span&gt;

&lt;span class="nv"&gt;$translations&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'de'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
   &lt;span class="s1"&gt;'Welcome to our page!'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Willkommen auf unserer Seite!'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  B - The T-function
&lt;/h3&gt;

&lt;p&gt;The template engine uses curly brackets by default to evaluate content (You see this whenever we use data from "product").&lt;br&gt;
Sometimes you want translations to be run earlier in the process to control interactivity between the data-context and the translation context. This is especially useful if you have custom functions and/or attributes for the templating. As this would reach beyond the scope of this article, I will have to leave examples to your imagination. &lt;/p&gt;
&lt;h3&gt;
  
  
  C - Placeholders
&lt;/h3&gt;

&lt;p&gt;Sometimes (or quite often, depending on your project), you need to insert dynamic content into your translations. We best explore this by looking into the cycle of what happens under the hood:&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="c1"&gt;//...&lt;/span&gt;

&lt;span class="nv"&gt;$translations&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'de'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
   &lt;span class="c1"&gt;//...&lt;/span&gt;
   &lt;span class="s1"&gt;'Check out [%product-name%]'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Erfahre mehr über [%product-name%]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In our translations, we indicate dynamic values WITHIN the t-tag in order to account for placement differences or grammatical adjustments within languages. In our HTML-template, we then bind these placeholders to a value. As values could come from various sources, but we want to use the context of our product, we use curly brackets to indicate that we want to resolve the variable prior to substitution:&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;t&amp;gt;&lt;/span&gt;Check out [%product-name%](% {{ product.title }} %)&lt;span class="nt"&gt;&amp;lt;t/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;1. Find and interpret context-data:&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;t&amp;gt;&lt;/span&gt;Check out [%product-name%](%Scrapbook  #2%)&lt;span class="nt"&gt;&amp;lt;t/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2. Find and interpret functions&lt;br&gt;
&lt;em&gt;(not happening in this example)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;3. Sanitize string &amp;amp; search for translation&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="c1"&gt;// pseudo code to illustrate the principle&lt;/span&gt;
&lt;span class="nv"&gt;$memorize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Scrapbook #2"&lt;/span&gt;

&lt;span class="nv"&gt;$lookFor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Check out [%product-name%]"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$foundTranslation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Erfahre mehr über [%product-name%]'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4. Replace placeholder with value&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="c1"&gt;// pseudo code to illustrate the principle&lt;/span&gt;
&lt;span class="nv"&gt;$final&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str_replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'[%product-name%]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$memorize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$foundTranslation&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  D - Attributes
&lt;/h3&gt;

&lt;p&gt;We have several attributes at our disposal. Attributes are an easy way to hook static or dynamic values into i18n. In this case, we simply format the price to the user's expectations.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Pro-tip: i18n-translate uses the template engine's &lt;code&gt;addCustomAttribute&lt;/code&gt;-method to achieve this. This means you can create your own attributes according to the needs of your shop/cummunity etc.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  E - Another attribute
&lt;/h3&gt;

&lt;p&gt;Some attributes need a value, others don't. In the case of &lt;code&gt;i18n-time&lt;/code&gt; both the format (here minutes without leading zero) and the value are optional. If the value isn't a timestamp, the attribute uses PHP's &lt;code&gt;strtotime&lt;/code&gt;, making this example (two minutes from now) possible.&lt;/p&gt;

&lt;p&gt;Shows the current server time (but only minutes):&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="c"&gt;&amp;lt;!-- without content --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;i18n-time=&lt;/span&gt;&lt;span class="s"&gt;"m"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Shows the current server time in the time-foramt suited for the user:&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="c"&gt;&amp;lt;!-- without content or format --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;i18n-time&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  F - Make it local
&lt;/h3&gt;

&lt;p&gt;As mentioned, we sometimes want to translate a time to the time zone of the user. That's why &lt;code&gt;i18n-time-local&lt;/code&gt; and &lt;code&gt;i18n-date-local&lt;/code&gt; output the given value in the user's time zone &amp;amp; -format.&lt;/p&gt;

&lt;h3&gt;
  
  
  G - Functions to prerender placeholders
&lt;/h3&gt;

&lt;p&gt;All provided attributes are also available as functions. With the exception of the t-function, they translate themselves into placeholders:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;i18n-currency -&amp;gt; [%currency-value%]&lt;/li&gt;
&lt;li&gt;i18n-time, i18n-time-local -&amp;gt; [%time-value%]&lt;/li&gt;
&lt;li&gt;i18n-date, i18n-date-local -&amp;gt; [%date-value%]&lt;/li&gt;
&lt;li&gt;i18n-number -&amp;gt; [%number-value%]&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means, that our example would have the following translation&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="c1"&gt;//...&lt;/span&gt;

&lt;span class="nv"&gt;$translations&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'de'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
   &lt;span class="c1"&gt;//...&lt;/span&gt;
   &lt;span class="s1"&gt;'Buy [%number%] for only [%currency-value%] today!'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Für nur [%currency-value%] erhälts du [%number%] Stück!'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Accessibility
&lt;/h2&gt;

&lt;p&gt;Lastly, let's talk about screen-readers &amp;amp; co.&lt;br&gt;
Using a server-side rendered solution is already a good start, but what else is there to consider?&lt;/p&gt;
&lt;h3&gt;
  
  
  The semantic side
&lt;/h3&gt;

&lt;p&gt;In one of our examples we discussed using the t-funciton rather than the t-tag. This can also be useful if you don't want a semantic element to have a child (the t-tag). In other cases, you might want to leverage the existence of a tag to supply aria-declarations to your content. Since it is a tag, you can supply all regular attributes as you wish:&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;t&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"when-visually-impared:text-xxl"&lt;/span&gt; &lt;span class="na"&gt;aria-role=&lt;/span&gt;&lt;span class="s"&gt;"note"&lt;/span&gt; &lt;span class="na"&gt;data-id=&lt;/span&gt;&lt;span class="s"&gt;"x"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Translate me!&lt;span class="nt"&gt;&amp;lt;/t&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Extendability
&lt;/h3&gt;

&lt;p&gt;We can extend the comfort using the functionality bundled with this package. &lt;br&gt;
Let's say we have a JavaScript text-to-speech program we want to work with called "js-read-me" which reads from attributes:&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="nc"&gt;Neoan3\Apps\Template\Constants&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;addCustomAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'js-read-me'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$domAttr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$contextData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$t&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nv"&gt;$domAttr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;nodeValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$t&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$domAttr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;nodeValue&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;js-read-me=&lt;/span&gt;&lt;span class="s"&gt;"Listen to my rant by clicking this button"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;😤&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;We now ensured that the content of "js-read-me" uses our translation!&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;There is so much more we can achieve, but I mustn't overextend the time you spent on this already. I hope this serves as an inspiration and helps explain this complex yet important topic.&lt;/p&gt;

&lt;p&gt;Thank you for making it this far &amp;amp; until next time! &lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>php</category>
      <category>opensource</category>
      <category>a11y</category>
    </item>
    <item>
      <title>Code Along: Taking Lenkrad for a Spin</title>
      <dc:creator>neoan</dc:creator>
      <pubDate>Wed, 17 Aug 2022 22:33:00 +0000</pubDate>
      <link>https://dev.to/sroehrl/code-along-taking-lenkrad-for-a-spin-5cf3</link>
      <guid>https://dev.to/sroehrl/code-along-taking-lenkrad-for-a-spin-5cf3</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/bDjd0EsuTV4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this unedited video I built a personal blog to introduce the functionality of the neoan PHP lenkrad core. If you have some time and are interested, please feel invited to leave feedback!&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>php</category>
      <category>webdev</category>
    </item>
    <item>
      <title>High speed-dev: A minute to be up &amp; running</title>
      <dc:creator>neoan</dc:creator>
      <pubDate>Wed, 17 Aug 2022 03:05:33 +0000</pubDate>
      <link>https://dev.to/sroehrl/high-speed-dev-a-minute-to-be-up-running-3i40</link>
      <guid>https://dev.to/sroehrl/high-speed-dev-a-minute-to-be-up-running-3i40</guid>
      <description>&lt;h2&gt;
  
  
  No, it doesn't run on PHP 7.2!
&lt;/h2&gt;

&lt;p&gt;The neoan-core &lt;strong&gt;Lenkrad&lt;/strong&gt; doesn't play the compatibility game. Being backward compatible to older PHP versions or playing nicely with a plethora of ecosystems is a challenge that not only slows down development, but results in verbose usage and unoptimized core code.&lt;/p&gt;

&lt;p&gt;I wanted to have a framework for the next generation. I wanted to finally have a framework that let's me write business logic the way I want it to behave. &lt;/p&gt;

&lt;p&gt;Let's compare:&lt;/p&gt;

&lt;p&gt;In Laravel, I need a migration and a model to make the Eloquent ORM work:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;the migration&lt;/strong&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;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Database\Migrations\Migration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Database\Schema\Blueprint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Schema&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Migration&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;up&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'users'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Blueprint&lt;/span&gt; &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;string&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="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'email'&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;unique&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;timestamps&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;down&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'users'&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 &lt;strong&gt;the model&lt;/strong&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;App\Models&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Database\Eloquent\Model&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;User&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'users'&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;We might be used to this, but what we really want to write is:&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;#[IsPrimaryKey]&lt;/span&gt;
   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="na"&gt;#[Transform(Hash::class)]&lt;/span&gt;
   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$password&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="na"&gt;#[IsUnique]&lt;/span&gt;
   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Timestamps&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 advantage is not only easier reference and less verbose code. Your IDE will be able to better help you with navigating objects through auto-completion:&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;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Adam'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// name was suggested, as it's a property of the model class&lt;/span&gt;
&lt;span class="mf"&gt;...&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Interested?
&lt;/h2&gt;

&lt;p&gt;If you have PHP8.1 and interested in seeing how a framework could actually make your life easier, try it out:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;composer create-project neoan.io/starter-project [my-app]&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;The package is light in dependencies and up &amp;amp; running in seconds. Feedback highly appreciated!&lt;/p&gt;

</description>
      <category>neoan3</category>
      <category>php</category>
      <category>showdev</category>
      <category>laravel</category>
    </item>
    <item>
      <title>Controllable Templating in PHP</title>
      <dc:creator>neoan</dc:creator>
      <pubDate>Tue, 16 Aug 2022 01:54:17 +0000</pubDate>
      <link>https://dev.to/sroehrl/controllable-templating-in-php-54j</link>
      <guid>https://dev.to/sroehrl/controllable-templating-in-php-54j</guid>
      <description>&lt;h2&gt;
  
  
  It's been a while
&lt;/h2&gt;

&lt;p&gt;I have been using my own templating engine for a while now as I wasn't happy with how blade &amp;amp; co handle certain things. Additionally, any kind of logic within the view is a violation of separation of concerns in my view.&lt;/p&gt;

&lt;p&gt;However, after living with a few issues for a while, I finally decided to rewrite it completely:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/sroehrl"&gt;
        sroehrl
      &lt;/a&gt; / &lt;a href="https://github.com/sroehrl/neoan3-template"&gt;
        neoan3-template
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      neoan3 minimal template engine
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
neoan3-apps/template&lt;/h1&gt;
&lt;p&gt;PHP template engine&lt;/p&gt;
&lt;p&gt;&lt;a href="https://codeclimate.com/github/sroehrl/neoan3-template/test_coverage" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/c26987a277a240a87a57fb8ac006fb53ab34297206de956e331e23f51f6c7056/68747470733a2f2f6170692e636f6465636c696d6174652e636f6d2f76312f6261646765732f37366230393932343330303337356334643739612f746573745f636f766572616765" alt="Test Coverage"&gt;&lt;/a&gt;
&lt;a href="https://codeclimate.com/github/sroehrl/neoan3-template/maintainability" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/184e3a997daa9f0a02b72de05d82c7c03fc33355dee3dfbc86d29a73e086647d/68747470733a2f2f6170692e636f6465636c696d6174652e636f6d2f76312f6261646765732f37366230393932343330303337356334643739612f6d61696e7461696e6162696c697479" alt="Maintainability"&gt;&lt;/a&gt;
&lt;a href="https://travis-ci.org/sroehrl/neoan3-template" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/3664eaf8f478814d08eab4337fdd5ad1d53993d000b6d97222e17d2800bcb009/68747470733a2f2f7472617669732d63692e6f72672f73726f6568726c2f6e656f616e332d74656d706c6174652e7376673f6272616e63683d6d6173746572" alt="Build Status"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As of version 2, we dropped PHP 7.4 support
You require at least PHP 8.0 or use v1.2.0 of this package.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
Installation / Quick start&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;composer require neoan3-apps/template&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight highlight-text-html-php notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;use&lt;/span&gt; &lt;span class="pl-v"&gt;Neoan3&lt;/span&gt;\&lt;span class="pl-v"&gt;Apps&lt;/span&gt;\&lt;span class="pl-v"&gt;Template&lt;/span&gt;\&lt;span class="pl-v"&gt;Constants&lt;/span&gt;;
&lt;span class="pl-k"&gt;use&lt;/span&gt; &lt;span class="pl-v"&gt;Neoan3&lt;/span&gt;\&lt;span class="pl-v"&gt;Apps&lt;/span&gt;\&lt;span class="pl-v"&gt;Template&lt;/span&gt;\&lt;span class="pl-v"&gt;Template&lt;/span&gt;;

&lt;span class="pl-k"&gt;require_once&lt;/span&gt; &lt;span class="pl-s"&gt;'vendor/autoload.php'&lt;/span&gt;;

&lt;span class="pl-c"&gt;// optional, if set, path defines the relative starting point to templates&lt;/span&gt;
&lt;span class="pl-v"&gt;Constants&lt;/span&gt;::&lt;span class="pl-en"&gt;setPath&lt;/span&gt;(__DIR__ . &lt;span class="pl-s"&gt;'/templates'&lt;/span&gt;);

&lt;span class="pl-k"&gt;echo&lt;/span&gt; &lt;span class="pl-v"&gt;Template&lt;/span&gt;::&lt;span class="pl-en"&gt;embrace&lt;/span&gt;(&lt;span class="pl-s"&gt;'&amp;lt;h1&amp;gt;{{test}}&amp;lt;/h1&amp;gt;'&lt;/span&gt;,[&lt;span class="pl-s"&gt;'test'&lt;/span&gt;=&amp;gt;&lt;span class="pl-s"&gt;'Hello World'&lt;/span&gt;]);&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/sroehrl/neoan3-template#templating"&gt;Templating&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sroehrl/neoan3-template#iterations-n-for"&gt;Iterations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sroehrl/neoan3-template#conditions-n-if"&gt;Conditions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sroehrl/neoan3-template#custom-functions"&gt;Custom Functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sroehrl/neoan3-template#custom-delimiter"&gt;Custom Delimiter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sroehrl/neoan3-template#custom-attributes"&gt;Custom Attributes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sroehrl/neoan3-template#oop"&gt;OOP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sroehrl/neoan3-template#tips"&gt;Tips&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
Templating&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;neoan3-template&lt;/strong&gt; is not a full blown template engine, but rather what a template engine should be:
With modern JavaScript solutions creating a dynamic approach, neoan3-template focuses on the necessities of static rendering.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;profile.html&lt;/em&gt;&lt;/p&gt;
&lt;div class="highlight highlight-text-html-basic notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;h1&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;{{user}}&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;h1&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;p&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;{{profile.name}}&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;p&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;p&lt;/span&gt; &lt;span class="pl-c1"&gt;n-for&lt;/span&gt;="&lt;span class="pl-s"&gt;items as&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/sroehrl/neoan3-template"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Happy accidents
&lt;/h2&gt;

&lt;p&gt;I have had a way of adding project-specific functionality to the engine and wanted to keep it open for special needs. &lt;br&gt;
By simplifying the hook-process, I noticed something interesting:&lt;/p&gt;

&lt;p&gt;In theory, one can now use this package to create specific behavior utilizing two capabilities:&lt;/p&gt;
&lt;h3&gt;
  
  
  customFunctions
&lt;/h3&gt;

&lt;p&gt;We are usually under full control of the data we are sending to the rendering mechanism when dealing with SSR sites, but sometimes we want to leave e.g. a model as is. So let's build a salutation template 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="nc"&gt;Template\Constants&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;addCustomFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'salutation'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$gender&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nv"&gt;$salutation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Mrs.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$gender&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
      &lt;span class="nv"&gt;$salutation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Mr.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;elseif&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$gender&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
      &lt;span class="nv"&gt;$salutation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Mx.'&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;In our template, we can now use this function:&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="c"&gt;&amp;lt;!-- profile.html --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hello, {{salutation(user.gender)}} {{user.lastName}}&lt;span class="nt"&gt;&amp;lt;/p&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
   &lt;span class="s1"&gt;'gender'&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="s1"&gt;'firstName'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Samantha'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="s1"&gt;'lastName'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Smith'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="s1"&gt;'birthDay'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'1990-06-06'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="s1"&gt;'website'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'https://sam-smith-1990.com'&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nc"&gt;Template\Template&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;embraceFromFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/profile.html'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;output&lt;/strong&gt;&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&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hello, Mrs. Smith&lt;span class="nt"&gt;&amp;lt;/p&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;This is, of course, a very constructed example, but you get the idea. Another way of implementing additional functionality is via the method&lt;/p&gt;

&lt;h3&gt;
  
  
  customAttributes
&lt;/h3&gt;

&lt;p&gt;With this we can hook into attribute-interpretation of the template engine. Let's have a look:&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="nc"&gt;Template\Constants&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;addCustomAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'secure-link'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$attr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nv"&gt;$href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$attr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;parentNode&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'href'&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;nodeValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="c1"&gt;// external?&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;str_contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$href&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_HOST'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; 
      &lt;span class="nf"&gt;str_starts_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$href&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'http'&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;$attr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;parentNode&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'target'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'_blank'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nv"&gt;$attr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;parentNode&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'rel'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'noopener noreferrer'&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- profile.html --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hello, {{salutation(user.gender)}} {{user.lastName}}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"{{user.website}}"&lt;/span&gt; &lt;span class="na"&gt;secure-link&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{user.website}}&lt;span class="nt"&gt;&amp;lt;/a&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;&lt;strong&gt;output&lt;/strong&gt;&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&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hello, Mrs. Smith&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://sam-smith-1990.com"&lt;/span&gt; &lt;span class="na"&gt;target=&lt;/span&gt;&lt;span class="s"&gt;"_blank"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"noopener noreferrer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;https://sam-smith-1990.com&lt;span class="nt"&gt;&amp;lt;/a&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;I know these examples are rather strange, but due to the reusability one could easily build together a templating mechanism suited to personal needs. &lt;br&gt;
As usual, leaving a star when playing around with the repo is appreciated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Discussion
&lt;/h2&gt;

&lt;p&gt;Now to the fun part: What has always bothered &lt;strong&gt;you&lt;/strong&gt; when having to deal with passing data to your templating mechanism? What do you wish was less of a hassle? &lt;/p&gt;

</description>
      <category>php</category>
      <category>webdev</category>
    </item>
    <item>
      <title>What is dev.to for?</title>
      <dc:creator>neoan</dc:creator>
      <pubDate>Tue, 23 Nov 2021 03:01:48 +0000</pubDate>
      <link>https://dev.to/sroehrl/what-is-devto-for-4koa</link>
      <guid>https://dev.to/sroehrl/what-is-devto-for-4koa</guid>
      <description>&lt;p&gt;Lately there has been an influx of certain kinds of posts on dev.to that we should probably talk about: &lt;/p&gt;

&lt;h2&gt;
  
  
  Uneducated opinion pieces
&lt;/h2&gt;

&lt;p&gt;Before I describe what kind of articles I am referring to, let's first clarify what dev.to enabled and what - in my opinion - should not be jeopardized: The absence of gate-keeping, which destroyed the vibe of many other platforms, communities, etc.&lt;/p&gt;

&lt;p&gt;However, this inclusiveness has particular dangers that have met a threshold recently. What I am referring to are posts that seem to be driven by a "learn by explaining it" approach and that are often simply too dangerous to leave uncommented. Way too often a mode of speech is used that would lead the beginner to believe that an expert is sharing advice while completely wrong or misleading statements are picked up and quoted. This has become so bad that I find people citing these sources and therefore unwillingly propagate misinformation similar to the false-news phenomenon in the political realm. Additionally, these articles tend to state opinion as fact. In my opinion, it is relatively easy to avoid mixing opinion with facts through language in our field as we only apply established technology.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what's the call to action?
&lt;/h2&gt;

&lt;p&gt;The question is what this community should do to avoid becoming a heap of nonsense or half-truths rather than a source of actual knowledge, given the understandable fact that many learners aren't able to distinguish between transfer of knowledge and confident nonsense. &lt;/p&gt;

&lt;p&gt;Are you expecting the same, or is this observation based on my personal feed? Thoughts?&lt;/p&gt;

</description>
      <category>watercooler</category>
      <category>discuss</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Tech-blogging the easy way</title>
      <dc:creator>neoan</dc:creator>
      <pubDate>Sat, 13 Nov 2021 16:19:53 +0000</pubDate>
      <link>https://dev.to/sroehrl/tech-blogging-the-easy-way-347m</link>
      <guid>https://dev.to/sroehrl/tech-blogging-the-easy-way-347m</guid>
      <description>&lt;p&gt;Lately I have seen a lot of posts here about how to set up your own blog. It's not a surprise that a regular Wordpress-installation doesn't really scream developer. On my personal blog &lt;a href="https://neoan.us/blog"&gt;neoan.us/blog&lt;/a&gt;, I use &lt;a href="https://blua.blue"&gt;blua.blue&lt;/a&gt; and if you are a follower you will notice that many of my dev.to contributions originate from there as well (whenever I want to publish to multiple sites/services). However, knowing that the PHP-crowd here is miniscule I decided to provide you with 2 repositories you can start with that do not require the use of the blua.blue-API (because they are webhook-based) and allow you to simply design your blog using the means of your choice.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Repo&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;serverless framework&lt;/td&gt;
&lt;td&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/sroehrl"&gt;
        sroehrl
      &lt;/a&gt; / &lt;a href="https://github.com/sroehrl/serverless-blog"&gt;
        serverless-blog
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
blua.blue Serverless Framework Node Express API on AWS&lt;/h1&gt;
&lt;p&gt;This POC is based on the serverless node/express/api template with added support for
s3 bucket storage and rendering.&lt;/p&gt;
&lt;h2&gt;
Setup&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Create a bucket and ensure that your AWS cli AIM has the required permissions to read &amp;amp; write to this bucket.&lt;/li&gt;
&lt;li&gt;Change line 8 of handler.js accordingly: &lt;code&gt;const bucketName = 'my-article-storage-bucket'&lt;/code&gt;;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
Usage&lt;/h2&gt;
&lt;h3&gt;
Deployment&lt;/h3&gt;
&lt;p&gt;Install dependencies with:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;npm install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and then deploy with:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;serverless deploy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;
Enhance&lt;/h2&gt;
&lt;p&gt;The current setup is a POC to ease local development (when using serverless-local).
Ultimately, you may want to set up your bucket as a website and permanently render
what is now done in &lt;code&gt;app.get('/:slug?)&lt;/code&gt; to HTML files (pug.compileFile) to enjoy a static blog.&lt;/p&gt;
&lt;/div&gt;

  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/sroehrl/serverless-blog"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;file-based (mono-repo node &amp;amp; PHP)&lt;/td&gt;
&lt;td&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/sroehrl"&gt;
        sroehrl
      &lt;/a&gt; / &lt;a href="https://github.com/sroehrl/minimal-blog"&gt;
        minimal-blog
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
minimal-blog&lt;/h1&gt;
&lt;h2&gt;
blua.blue webhook POC&lt;/h2&gt;
&lt;p&gt;This little repo can be run either with node or PHP and serves as a proof of concept for blua.blue based blogs without using the API or SDKs.
Both the PHP-version and the node-version are based on a total of less than 75 lines of code. The PHP version is even completely free of dependencies.&lt;/p&gt;
&lt;p&gt;The goal of this project is was to create the easiest possible setup to host your own blog.&lt;/p&gt;
&lt;p&gt;See it here:
&lt;a href="https://equinox-vivacious-havarti.glitch.me/" rel="nofollow"&gt;https://equinox-vivacious-havarti.glitch.me/&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
How to use&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;If you don't have an account, sign up at &lt;a href="https://blua.blue" rel="nofollow"&gt;blua.blue&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Clone, fork or download this repo and host it depending on your needs*&lt;/li&gt;
&lt;li&gt;Set up webhooks on blua.blue&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;PHP-endpoint: &lt;code&gt;https://your-site.com/receive.php&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;node-endpoint: &lt;code&gt;https://your-site.com/receive&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;*Be careful of hosting via services like heroku: many of these services delete files written to the file-system after some idle time&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That's it. Enjoy&lt;/p&gt;
&lt;/div&gt;

  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/sroehrl/minimal-blog"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How to use them
&lt;/h2&gt;

&lt;p&gt;After deploying one of these versions, sign up with blua.blue and navigate to your profile. You will find the tab "Webhooks". With both repositories, you will want to generate a webhook to &lt;code&gt;https://your-endpoint.tld/receive&lt;/code&gt;. There is no need for a token as we check for allowed origins, but ultimately you will want to set one of your choice and then verify the source of the payload (sent through authorization header as bearer token) in order to prevent other blua.blue-users to post on your behalf.&lt;/p&gt;

&lt;h2&gt;
  
  
  That's it
&lt;/h2&gt;

&lt;p&gt;Lastly, please be aware of two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;These repos are very basic and meant to be a boilerplate rather than a final solution. I am happy to accept pull-requests&lt;/li&gt;
&lt;li&gt;Share! If you built something beautiful, let everyone know in the comments!&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>showdev</category>
    </item>
    <item>
      <title>How to use JWT in the neoan3 PHP framework</title>
      <dc:creator>neoan</dc:creator>
      <pubDate>Thu, 11 Nov 2021 01:46:35 +0000</pubDate>
      <link>https://dev.to/sroehrl/how-to-use-jwt-in-the-neoan3-php-framework-47c7</link>
      <guid>https://dev.to/sroehrl/how-to-use-jwt-in-the-neoan3-php-framework-47c7</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/4h1JMpAx0cE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  The code to the video
&lt;/h2&gt;

&lt;p&gt;I am trying out a new format of supplementing my videos with the relevant code-pieces and publishing them as an article. Please let me know if this is helpful or annoying. TY&lt;/p&gt;

&lt;h2&gt;
  
  
  UserModel.php
&lt;/h2&gt;

&lt;h3&gt;
  
  
  changes to the default outgoing method
&lt;/h3&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 $transactionResult
     * @return array
     */&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;outgoing&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;$transactionResult&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$transactionResult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;])){&lt;/span&gt;
            &lt;span class="k"&gt;unset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$transactionResult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;elseif&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$transactionResult&lt;/span&gt;&lt;span class="p"&gt;)){&lt;/span&gt;
            &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$transactionResult&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$single&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
                &lt;span class="nv"&gt;$transactionResult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;outgoing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$single&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="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$transactionResult&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;
  
  
  changes to the default incoming method
&lt;/h3&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 $transactionResult
     * @return array
     */&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;outgoing&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;$transactionResult&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$transactionResult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;])){&lt;/span&gt;
            &lt;span class="k"&gt;unset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$transactionResult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;elseif&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$transactionResult&lt;/span&gt;&lt;span class="p"&gt;)){&lt;/span&gt;
            &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$transactionResult&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$single&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
                &lt;span class="nv"&gt;$transactionResult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;outgoing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$single&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="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$transactionResult&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 login method
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;   &lt;span class="cd"&gt;/**
     * @throws RouteException
     */&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$credentials&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$foundUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;easy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user.id user.password'&lt;/span&gt;&lt;span class="p"&gt;,[&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;$credentials&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;]]);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$foundUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;password_verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$credentials&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="nv"&gt;$foundUser&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;])){&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RouteException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Unauthorized'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$foundUser&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'id'&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;h2&gt;
  
  
  AuthController.php
&lt;/h2&gt;

&lt;p&gt;The final version of our authorization controller.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: In the video, I forgot to address how my IDE automatically includes use-commands. Make sure you include those.&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="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Neoan3\Component\Auth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Neoan3\Core\RouteException&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Neoan3\Frame\Demo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Neoan3\Model\User\UserModel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Neoan3\Model\User\UserModelWrapper&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Neoan3\Provider\Auth\Authorization&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Neoan3\Provider\Model\InitModel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cd"&gt;/**
 * Class AuthController
 * @package Neoan3\Component\Auth
 *
 * Generated by neoan3-cli for neoan3 v3.*
 */&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Demo&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="cd"&gt;/**
    * GET: api.v1/auth
    * GET: api.v1/auth/{id}
    * GET: api.v1/auth?{query-string}
    * @return array
    */&lt;/span&gt;
    &lt;span class="na"&gt;#[Authorization('restrict',['admin'])]&lt;/span&gt;
    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getAuth&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&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;authObject&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPayload&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * POST: api.v1/auth
     * @param string $mode
     * @param array $body
     * @return array
     * @throws \Neoan3\Core\RouteException
     */&lt;/span&gt;
    &lt;span class="na"&gt;#[InitModel(UserModel::class)]&lt;/span&gt;
    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;postAuth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Login"&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;$body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$mode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'Register'&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
            &lt;span class="c1"&gt;// create user&lt;/span&gt;
            &lt;span class="nv"&gt;$newUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserModelWrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nv"&gt;$newUser&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;store&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;rehydrate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$newUser&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;\Exception&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RouteException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Malformed input'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;406&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="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// try login&lt;/span&gt;
            &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;UserModel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nv"&gt;$authObject&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="nc"&gt;Auth&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'all'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;]]);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'token'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$authObject&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getToken&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;



</description>
      <category>php</category>
      <category>lamp</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>101 on building apps clients actually need</title>
      <dc:creator>neoan</dc:creator>
      <pubDate>Fri, 05 Nov 2021 16:19:42 +0000</pubDate>
      <link>https://dev.to/sroehrl/101-on-building-apps-clients-actually-need-4j6c</link>
      <guid>https://dev.to/sroehrl/101-on-building-apps-clients-actually-need-4j6c</guid>
      <description>&lt;p&gt;You might have read my article &lt;a href="https://dev.to/sroehrl/rethinking-vue-full-stack-57g5"&gt;Rethinking Vue Full stack&lt;/a&gt; where I presented a prototype of what I called a "Frackend". Back then, I only had a proof of concept. But first things first: why should you care?&lt;/p&gt;

&lt;h2&gt;
  
  
  How devs make money: What you are really needed for
&lt;/h2&gt;

&lt;p&gt;Unless we are one of the unicorns who actually make a living with crowd-founded open source projects, we are likely employed by or are hired by companies who market or sell something using the internet. And at the end of the day, they aren't impressed by our abilities to bubble sort or our ToDo-SPAs on heroku. At least they shouldn't be (That people who are hiring us often don't understand this themselves is a rant for another time). Instead, these companies are fighting a battle between two competing principles: organic traffic vs. user experience. If you ever ran Lighthouse, you enjoyed these little insights like &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Walmart noticed a 1% increase in revenue for every saved 100ms"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;About a year ago I was working for a client who represented over 3000 smaller businesses and conducted an analytical evaluation of revenue vs. page-speed. The outcome of this study was while revenue measurably went down as soon as loading times exceed 1.7 seconds,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;every page load exceeding 3 seconds results in a considerable amount of lost revenue.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The truth is that when people browse products they loose interest quickly when loading times are slow and with over 90% of traffic being mobile, internet speed itself isn't always optimal in the first place. Think about your own retention span: what is the title of this post and with what "trick" did I confuse you? (check the url to get the full picture)&lt;/p&gt;

&lt;h2&gt;
  
  
  What about SPAs with CSR?
&lt;/h2&gt;

&lt;p&gt;You might say this isn't a problem, thinking about your React or Angular app that runs as snappy as it gets and lazy loads assets in the most optimal way there is. And you are right - sort of. I know you have been told that at least Google interprets JavaScript and runs your virtual routes and therefore indexes SPA-content correctly, but look at the reality: Whatever you google for when it comes to content or products will yield server-side rendered results first. &lt;strong&gt;&lt;em&gt;Always&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is organic traffic so important?
&lt;/h2&gt;

&lt;p&gt;I guess I don't have to explain why most companies are highly interested in SEO: if I offer content (e.g. Newspapers, Blogs, etc.) or products (aka online-shops), I need to be found. If someone searches for "awesome red sneakers" and not just directly for "step-by-step-shoes.com", we want to be in the game. And organic traffic is the best traffic there is - it's free. Now, when I say free, I don't mean that there isn't cost related to SEO optimization - after all, it's a complete industry itself - I mean that organic traffic doesn't correlate to a customer in the same way advertising does. Let's explain that using an example in order to understand why SEO-optimization companies ask for such outlandish rates:&lt;br&gt;
A given ad-campaign consists of customer analysis, assets, placement. Simplified, I first analyze who I want to target, then create marketing material (so the actual ad) and then place it somewhere (Facebook ads, Youtube ads, Google AdWords, etc.). This results in an initial investment (so whatever it cost to create this setup) and variable costs (so whatever every impression, click or similar costs me). With tracking in place, we can derive a direct correlation that allows us to make statements like "A new customer costs us X US$ (or whatever currency you calculate)". Needless to say, as soon as you stop spending, the traffic will subside. Organic traffic is different: If you manage to gain X amount of additional visitors through organic traffic, whatever revenue that traffic generates will flow until competitors manage to pull that away from you. Additionally, whatever a company spent on this optimization has no variable cost per visitor.  &lt;/p&gt;

&lt;h2&gt;
  
  
  So we are doomed?
&lt;/h2&gt;

&lt;p&gt;If you now realize that there is a reason why Wordpress and Shopify are so popular despite being technically unimpressive solutions, then you are not alone. However, to optimize something like an Adobe Magento ecommerce shop or similar, you have to invest in knowledge and hardware. And yet: even if you are doing a really good job, you won't get close to the speed a client-side rendered solution would have. And what does all that traffic help if people jump off?&lt;/p&gt;

&lt;h2&gt;
  
  
  What about next, nuxt &amp;amp; Co?
&lt;/h2&gt;

&lt;p&gt;Thankfully, solutions to this problem gain traction. The attempt of these solutions is relatively simple: Let the developers work as if they were developing a single page application, while in reality a hybrid solution will be rendered. How does this work? Let's assume you visit "my-webshop.com/products/basketball". The server responds with the HTML for this endpoint, making it indexable by search engines. In a second step, the SPA logic kicks in and presents the user with the fast reactivity that is important for a successful experience. As a side effect, the user has the impression the initial loading is faster as you see the content prior to it being reactive, taking care of the issue of initial page load SPAs usually have. Most of the solutions out there even "pre-deliver" asynchronous data. And that makes sense: Why would you deliver content that then executes a call back to the very server it came from to ask for additional data? After all, we should already know what data is needed for that route. This speeds up the hydration of our SPA even further. Additionally, smart prefetching based on rendered or visible (depending on the particular technology) routing-links make use of saving start-up time by dynamic imports while having the effect of actually being already delivered when needed. So there you go, problem solved! Well, not so fast:&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveats
&lt;/h2&gt;

&lt;p&gt;Not every scenario is covered as easily as one might think. What about iterations, for example. Let's think of a scenario where I have an online shop and want to display all products of a certain category. Depending on the size of results, this can lead to quite a huge initial page load if rendered server-side. After all, we first have to get those products form a database on the server before the server can even start rendering the HTML. But if we don't (which in that scenario is currently the recommended way for this scenario in all major solutions), we have the issue that from an SEO perspective, our products aren't on that page. The pros will probably point to reducing fetched data-fields by using GraphQL and then in a second step loading additional resources (like additional pictures etc.) and merge the objects after hydration, but as you notice we dive into a complex, individual and work-intensive pool here. And the idea of "you only work on the frontend, the server builds itself" has died. I could bring in additional examples, but let's rather focus on what would need to be solved: We need a declarative way of deciding what data is preloaded and what DOM-manipulations to run on the client, the server or both in order to create a truly perfect solution that enables even relatively unexperienced developers to rapidly develop apps that have measurable performance and SEO advantages and can be developed in a fraction of the time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting close
&lt;/h2&gt;

&lt;p&gt;Well, we are working on it. A few days ago we uploaded the vastN3 based version of &lt;a href="https://blua.blue"&gt;blua.blue&lt;/a&gt; to test-drive the technology in a asset-heavy (and sorry, not yet perfectly designed) environment. And the results speak for themselves. To get a intuitive feeling for it, try the following:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;action&lt;/th&gt;
&lt;th&gt;instructions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Feel it&lt;/td&gt;
&lt;td&gt;Visit &lt;a href="https://blua.blue"&gt;blua.blue&lt;/a&gt; and navigate, search, explore&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check it&lt;/td&gt;
&lt;td&gt;Open up the source of a given page and see what is delivered by the server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Confirm efficacy&lt;/td&gt;
&lt;td&gt;Verify indexing by searching for any article currently published (e.g. &lt;a href="https://www.google.com/search?q=rapidly+build+your+own+stateless"&gt;google?q=...&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;What you will find is that it will feel very fast while solving all your client's or employer's needs. &lt;/p&gt;

&lt;p&gt;We are still not ready to offer vastN3 for production projects, but be sure to follow me here or on GitHub in order to take advantage of something I hope will be the easiest form you ever developed hybrid applications. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Rapidly build your own stateless REST-API with neoan3</title>
      <dc:creator>neoan</dc:creator>
      <pubDate>Tue, 19 Oct 2021 01:47:16 +0000</pubDate>
      <link>https://dev.to/sroehrl/rapidly-build-your-own-stateless-rest-api-with-neoan3-37mg</link>
      <guid>https://dev.to/sroehrl/rapidly-build-your-own-stateless-rest-api-with-neoan3-37mg</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;Coding along should approx. take you 15 min&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What we will be working on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setup&lt;/li&gt;
&lt;li&gt;Adding a simple model&lt;/li&gt;
&lt;li&gt;Writing authentication endpoints&lt;/li&gt;
&lt;li&gt;Final thoughts&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;Since we don't want to spend a lot of time on addressing various environments, let's check out the official docker setup for neoan3:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git clone https://github.com/neoan3/docker.git&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Our only constraint is the need for docker-compose, so be sure you have that installed (comes with Docker Desktop on Mac &amp;amp; Windows). In order to get started, we will run the following commands:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker-compose up -d --build&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker-compose exec neoan3 sh&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That's it! The hashtag you will see indicates you are executing the service's shell as root.&lt;/p&gt;

&lt;p&gt;From here, let's finally get started and create a neoan3 project:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;neoan3 new app&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To verify everything works as expected, try visiting &lt;a href="http://localhost:8090"&gt;http://localhost:8090&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--US8s92J9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1f2z10bz4o3qm3jtamuc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--US8s92J9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1f2z10bz4o3qm3jtamuc.png" alt="Image description" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a simple user model
&lt;/h2&gt;

&lt;p&gt;The easiest way to get fast results is to use the basic email login. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;neoan3 add model https://github.com/neoan3/email-password-auth.git&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Later, it makes sense to look at the few lines of relevant code in the folder &lt;em&gt;model/user&lt;/em&gt; , but for now we will jump over to migrating the model with our database that shipped with our docker setup. To do so, all you need it to run &lt;/p&gt;

&lt;p&gt;&lt;code&gt;neoan3 migrate models up&lt;/code&gt; and then choose &lt;strong&gt;&lt;em&gt;neoan3_db&lt;/em&gt;&lt;/strong&gt; as the credential key.&lt;/p&gt;

&lt;p&gt;To verify the installation of our model has worked as expected, visit &lt;a href="http://localhost:8090/migrate"&gt;http://localhost:8090/migrate&lt;/a&gt; and see if you can find "user" in the dropdown.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;NOTE:&lt;/em&gt; Don't worry about the security-warning you will see on that page. This is just a reminder that you shouldn't deploy this setup without taking the steps lined out in the README of the docker repo we started out with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing authentication endpoints
&lt;/h2&gt;

&lt;p&gt;Let's finally code something, right? Well, almost. Let's get us started with some boilerplate for our endpoints:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;neoan3 new component auth -t:api -f:demo&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This command will get us to a good starting point and within your project you should find a folder [app]/component/Auth with a file AuthController.php. And that's the file we will work with.&lt;/p&gt;

&lt;h3&gt;
  
  
  The plan
&lt;/h3&gt;

&lt;p&gt;We want to have the following endpoints at our disposal&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;POST /auth (this is our login-endpoint)&lt;/li&gt;
&lt;li&gt;POST /auth/register (this is, well, you guessed right)&lt;/li&gt;
&lt;li&gt;GET /auth (this returns a logged in user or a 401 unauthorized response. We mainly want that for testing.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;FYI: the default api-endpoint behavior is using neoan3 api v1. Our endpoints will therefore be at &lt;a href="http://localhost:8090/api.v1/auth###"&gt;http://localhost:8090/api.v1/auth###&lt;/a&gt; Let's first look at the method postAuth&lt;/p&gt;

&lt;p&gt;Since we want both /auth and /auth/register to be handles by this method, our postAuth should look like this:&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="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;postAuth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Login'&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;$body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$mode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'Login'&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="c1"&gt;// for endpoint /auth (or /auth/login)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$mode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'Register'&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="c1"&gt;// for endpoint /auth/register&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&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;As you can see, the API converts kebab-case to PascalCase, so something like /auth/log-me-in would be interpreted as LogMeIn. &lt;/p&gt;

&lt;h3&gt;
  
  
  adding model transactions
&lt;/h3&gt;

&lt;p&gt;We are using PHP8 in our docker setup. This makes it possible to load injections via Attribute&lt;br&gt;
My IDE does most of this for me, but be sure to have both&lt;br&gt;
&lt;code&gt;use Neoan3\Provider\Model\InitModel;&lt;/code&gt; and&lt;br&gt;
&lt;code&gt;use Neoan3\Model\User\UserModel;&lt;/code&gt; after the namespace of your file&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="c1"&gt;// 1. Load our user model&lt;/span&gt;
&lt;span class="na"&gt;#[InitModel(UserModel::class)]&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;postAuth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Login'&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;$body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 2. pass the payload (body) to the corresponding model-method&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$mode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'Login'&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="c1"&gt;// for endpoint /auth (or /auth/login): send the credentials to login&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;UserModel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$mode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'Register'&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="c1"&gt;// for endpoint /auth/register: send the credentials to register&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;UserModel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// 3. create a JWT token&lt;/span&gt;
    &lt;span class="nv"&gt;$auth&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="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'auth'&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;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'self'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'token'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$auth&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getToken&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;
  
  
  GET /auth
&lt;/h3&gt;

&lt;p&gt;In order to try this out without a front-end we can use neoan3's on-board helper located at &lt;a href="http://localhost:8090/endpoint"&gt;http://localhost:8090/endpoint&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But first, let's built our GET-method. The most basic usage would be to restrict access to our GET-endpoint unless authenticated:&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="c1"&gt;// 1. Add the authorization Attribute&lt;/span&gt;
&lt;span class="na"&gt;#[Authorization('restrict')]&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getAuth&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 2. read the JWT&lt;/span&gt;
    &lt;span class="nv"&gt;$auth&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="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'auth'&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;validate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// 3. return its content to the client without exposing the identifier&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$auth&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPayload&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;Now we can jump over to &lt;a href="http://localhost:8090/endpoint"&gt;http://localhost:8090/endpoint&lt;/a&gt; and start with our test-scenario:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creating a user:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Set  the endpoint to "auth/register" with the method POST, adding a JSON-payload like &lt;br&gt;
&lt;code&gt;{"email":"test@example.com","password":"secure-me"}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When hitting send you should get an answer with a token&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Test authentication&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Copy the content of the token and paste it into the input field at the authorization-tab, then switch the method to GET after setting the endpoint to auth.&lt;/p&gt;

&lt;p&gt;You should now receive your user back.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6eAjeRaf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ljjt6htte6va5thklqt1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6eAjeRaf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ljjt6htte6va5thklqt1.png" alt="endpoint" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;First of all: did you run in any kind of issues? Let me know. Otherwise, I hope you are able to derive how easy it is to work with persistent data with neoan3 beyond a user model. Lastly, let's talk about CORS.&lt;br&gt;
I don't know what your plans for the frontend are. Whenever you get into a scenario where you run your application outside of the docker container (e.g. while developing a VueJS app), you will likely have a development server with a port (e.g. 8080). In order to work with cross-origin requests, please find the file &lt;strong&gt;&lt;em&gt;default.php&lt;/em&gt;&lt;/strong&gt; and adjust the allowed_origins accordingly (wildcard works, but be aware of the implications)&lt;/p&gt;

&lt;p&gt;Happy coding&lt;/p&gt;

</description>
      <category>neoan3</category>
      <category>php</category>
      <category>jwt</category>
      <category>authentication</category>
    </item>
  </channel>
</rss>
