<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Toon Verwerft - VeeWee</title>
    <link href="http://veewee.github.io/atom.xml" rel="self"/>
    <link href="http://veewee.github.io/"/>
    <updated>2022-11-15T10:21:01+01:00</updated>
    <id>http://veewee.github.io</id>
    <author>
        <name>Toon Verwerft</name>
        <uri>http://veewee.github.io/</uri>
        <email>toonverwerft@gmail.com</email>
    </author>
    
    <entry>
        <title>Taming the XML beast!</title>
        <link href="http://veewee.github.io/blog/taming-the-xml-beast/"/>
        <updated>2021-02-07T00:00:00+01:00</updated>
        <id>http://veewee.github.io/blog/taming-the-xml-beast</id>
        <content type="html">&lt;p&gt;
Imagine a world ... in which you didn't have to deal with all PHP's strange XML quirks.
The people following me on &lt;a href=&quot;https://twitter.com/toonverwerft&quot; target=&quot;_blank&quot;&gt;Twitter&lt;/a&gt; might have noticed that I don't like the XML tools that PHP currently provides.
My main frustrations with the built-in tools can be divided in 2 big items: The lack of error handling and the bloated APIs.
&lt;/p&gt;

&lt;h2 id=&quot;lack-of-error-handling&quot;&gt;Lack of error handling&lt;/h2&gt;

&lt;p&gt;Most of the time, you’ll be working with XML files of which you know they contain valid XML syntax.
In some situations however, you might receive invalid XML or XML that is not valid according to an XSD schema.
At this point, lib-xml gives you following:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$doc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DOMDocument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$doc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;loadXML&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'&amp;lt;invalid&amp;gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;var_dump&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Resulting in:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Warning: DOMDocument::loadXML():
  Premature end of data in tag invalid line 1 in Entity,
  line: 1 in /in/0I8Or on line 4
  
bool(false)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Yes, that is right… It returns false and it triggers … a PHP warning …
This means that code execution is not being stopped and a shitload of other warnings will be triggered if you do not check the false case of the loadXML function.&lt;/p&gt;

&lt;p&gt;If you want to cover up the warning and display the actual XML issue, you’ll have to write code that looks like this.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$doc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DOMDocument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$previousErrorReporting&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;libxml_use_internal_errors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;libxml_clear_errors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$doc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;loadXML&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'&amp;lt;invalid&amp;gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$errors&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;libxml_get_errors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;libxml_clear_errors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;libxml_use_internal_errors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$previousErrorReporting&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Do something with the errors and break execution&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Do note that most XML functions work in a similar way: they return false and trigger a warning.
So if you want to reliably work with XML, you need to wrap them all with your own error handling.&lt;/p&gt;

&lt;p&gt;The code above can be found in so many packages out there.
It’s like everybody is OK with this approach.
At least, I am not!&lt;/p&gt;

&lt;h2 id=&quot;bloated-api&quot;&gt;Bloated API&lt;/h2&gt;

&lt;p&gt;The XML extensions provided by PHP contain functions for everything you want to do with XML.
The DOMDocument class contains about 50 functions and 20 properties (estimated values) which all have their own purpose.
This is only the main entry point of your XML, besides that you can find DOMElements, DOMNodes, DOMAttributes, … which all have a similar amount of functions.&lt;/p&gt;

&lt;p&gt;Don’t get me wrong, I like this structure: It is created to do whatever you want to do with XML.
You want to load XML, fine! Or do you rather manipulate something, fine as well! Do whatever you please!
The downside of this all, is that you need to know a lot about the low level API!&lt;/p&gt;

&lt;p&gt;To give you an example for day-to-day loading of XML:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$document&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DOMDocument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$document&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encoding&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'UTF-8'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$document&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;preserveWhiteSpace&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$document&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;formatOutput&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// wrap error handling here ...&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$document&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;loadXML&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'&amp;lt;root /&amp;gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Custom error handling&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;With error handling, this is about 15 lines of code for just loading an XML file!
Not to mention that I needed to look up every property in there …&lt;/p&gt;

&lt;p&gt;The same goes for basically any manipulation you want to do.
Did you ever try to create an XML document with DOMDocument? It’s aweful - because it is all this ultra flexible.&lt;/p&gt;

&lt;p&gt;What if we were able to split all these functions and different XML types per use case?
That way we could create a smaller Document class that you can use to perform specific types of actions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Loading with configurable settings.&lt;/li&gt;
  &lt;li&gt;Validating based on whatever schema you please.&lt;/li&gt;
  &lt;li&gt;Building XML&lt;/li&gt;
  &lt;li&gt;Manipulating XML&lt;/li&gt;
  &lt;li&gt;Locating items inside an XML&lt;/li&gt;
  &lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;other-components&quot;&gt;Other components&lt;/h2&gt;

&lt;p&gt;I don’t want to convert this blog post into a big rant, so I am not going to focus on all other XML components at this moment.
So instead of complaining, let’s deal with these problems and let’s create something that covers these problems instead.&lt;/p&gt;

&lt;h1 id=&quot;xml-without-worries&quot;&gt;XML without worries&lt;/h1&gt;

&lt;p&gt;In order to tame the XML beast, I decided to create yet another package.
It’s not that there isn’t any XML library out there, but most focus on 1 specific problem or are bloated wrappers around DOMDocument.
With this package I want to improve ALL XML extensions that are available in PHP.&lt;/p&gt;

&lt;p&gt;The goal of the package is to provide all tools for dealing with XML in PHP without worries.
You will find a type-safe, declarative API that deals with errors for you!&lt;/p&gt;

&lt;p&gt;Currently the package provides DOM, XSD, XSLT, Error-Handling and Reader components.
In the future I will also focus on additional components like a memory-safe Writer and focus a bit on “simple”Xml.
There is a lot of stuff to discover, so let me give you a couple of highlights which I personally really like!&lt;/p&gt;

&lt;h2 id=&quot;locating-data-inside-an-xml-document&quot;&gt;Locating data inside an XML document&lt;/h2&gt;

&lt;h3 id=&quot;loading-the-xml-document&quot;&gt;Loading the XML document&lt;/h3&gt;

&lt;p&gt;You can load an XML document with configurable functions to determine how it will load.
These configurable functions can contain whatever you want:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Specify encoding&lt;/li&gt;
  &lt;li&gt;Specify output&lt;/li&gt;
  &lt;li&gt;Validate internal XSD schema’s whilst loading&lt;/li&gt;
  &lt;li&gt;You can create custom configurators that e.g. replace import statements with their eventual XML (flattening)&lt;/li&gt;
  &lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;VeeWee\XML\DOM\Configurator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;VeeWee\XML\DOM\Document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;VeeWee\XML\DOM\Loader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;VeeWee\XML\DOM\Validator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;VeeWee\Xml\ErrorHandling\Issue\Level&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$doc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;Configurator\utf8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;Configurator\trim_spaces&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;Configurator\Loader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;nf&quot;&gt;Loader\xml_file_loader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'data.xml'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;Configurator\validator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;Validator\internal_xsd_validator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Level&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;warning&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;xpath-improvements&quot;&gt;XPath improvements&lt;/h3&gt;

&lt;p&gt;Next up is the actual querying. You start of by configuring how you want to create your XPath object.
In this case, you can configure it with lookup namespaces:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Psl\Type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;VeeWee\XML\DOM\Xpath\Configurator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$xpath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$doc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;xpath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;Configurator\namespaces&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;'acme'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'http://acme.com'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$currentNode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$xpath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;querySingle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'//acme:products'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$xpath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;evaluate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'count(.//item)'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Type\int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$currentNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;After creating the XPath object, you can see a new function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;querySingle&lt;/code&gt;. 
I found myself frequently looking for one element and wanted to make that possible.
Another addition is typed evaluation.
By specifying a type, you can make sure that the $count variable actually contains an integer or throws an exception instead.&lt;/p&gt;

&lt;p&gt;If you write an error in your XPath query, you will receive a meaningfull error message explaining you what is wrong with your query!&lt;/p&gt;

&lt;h3 id=&quot;memory-safe-reading&quot;&gt;Memory-safe Reading&lt;/h3&gt;

&lt;p&gt;If you have a very big XML file, you want to lookup nodes in a memory-safe way.
The improved version of the XMLReader looks like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;VeeWee\Xml\Dom\Document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;VeeWee\Xml\Reader\Configurator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;VeeWee\Xml\Reader\Reader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;VeeWee\Xml\Reader\Matcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$reader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fromXmlFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'large-data.xml'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;Configurator\xsd_schema&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'schema.xsd'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;cd&quot;&gt;/** @var \Generator&amp;lt;string&amp;gt; $provider */&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$provider&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;provide&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;Matcher\all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;Matcher\node_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'item'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;Matcher\node_attribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'locale'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'nl-BE'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$provider&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$nlItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$dom&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fromXmlString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$nlItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Do something with it&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can trust this reader to handle the boring node traversal for you.
By specifying matcher functions, you are in control of what XML strings are yielded.
From that point on, you can e.g. use a regular Document to deal with the smaller XML chunks.&lt;/p&gt;

&lt;p&gt;The reader is able to detect errors or invalid schema implementations whilst iterating over the dataset lazily.
You will receive a meaningful exception at all time!&lt;/p&gt;

&lt;h2 id=&quot;writing&quot;&gt;Writing&lt;/h2&gt;

&lt;p&gt;Reading is a bug chunk of your day-to-day XML usage, but in some cases you mind want to create or manipulate an XML.
In the XML package, you will find some tools that make building XML quite intuitive.
You basically specify what the XML should look like:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;VeeWee\Xml\Dom\Document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VeeWee\Xml\Dom\Builder\attribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VeeWee\Xml\Dom\Builder\children&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VeeWee\Xml\Dom\Builder\element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;VeeWee\Xml\Dom\Builder\namespaced_element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VeeWee\Xml\Dom\Builder\value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VeeWee\Xml\Dom\Manipulator\append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$doc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$doc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;manipulate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$doc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'root'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;nf&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'foo'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;nf&quot;&gt;attribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'bar'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'baz'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                &lt;span class=&quot;nf&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'hello'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nf&quot;&gt;namespaced_element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'http://namespace'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'foo'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;nf&quot;&gt;attribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'bar'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'baz'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                &lt;span class=&quot;nf&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                    &lt;span class=&quot;nf&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'hello'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'world'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$xml&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$doc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;toXmlString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h1 id=&quot;in-closing&quot;&gt;In closing&lt;/h1&gt;

&lt;p&gt;The snippets above are only some highlights of the package.
There is a lot more in there for you to discover!&lt;/p&gt;

&lt;p&gt;At this moment, the package already contains a lot of components that you can use on a day-to-day basis.
Since XML is very broad, there are still missing functions.
It might contain some rough corners and will surely grow in time.&lt;/p&gt;

&lt;p&gt;It has to start somewhere, it has to start sometime
What better place than here, what better time than now?!&lt;/p&gt;

&lt;h3 id=&quot;introducing-veeweexml&quot;&gt;Introducing &lt;a href=&quot;https://github.com/veewee/xml&quot; target=&quot;_blank&quot;&gt;veewee/xml&lt;/a&gt;!&lt;/h3&gt;

&lt;p&gt;Feel free to drop me any feedback.&lt;/p&gt;

&lt;p&gt;Hope you love it!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Run composer tasks in parallel</title>
        <link href="http://veewee.github.io/blog/run-composer-tasks-in-parallel/"/>
        <updated>2020-12-02T00:00:00+01:00</updated>
        <id>http://veewee.github.io/blog/run-composer-tasks-in-parallel</id>
        <content type="html">&lt;p&gt;
Composer has a built-in way of running multiple composer scripts by declaring a script alias.
This alias runs all specified scripts one by one and fails if one of the scripts fails.
To save you some time, I've written the &lt;a href=&quot;https://github.com/veewee/composer-run-parallel&quot; target=&quot;_blank&quot;&gt;veewee/composer-run-parallel&lt;/a&gt; plugin that can run multiple composer scripts in parallel and won't stop before all tasks have been executed: 
&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;
&lt;img src=&quot;/images/blog/20201202/composer-parallel.gif&quot; alt=&quot;example&quot; width=&quot;100%&quot; /&gt;
&lt;/p&gt;

&lt;h1 id=&quot;why-i-created-this-package&quot;&gt;Why I created this package?&lt;/h1&gt;

&lt;p&gt;
  As the creator of &lt;a href=&quot;https://github.com/phpro/grumphp&quot; target=&quot;_blank&quot;&gt;GrumPHP&lt;/a&gt;,
  I am used that &lt;a href=&quot;/blog/running-grumphp-tasks-in-parallel/&quot;&gt;all tasks run in parallel&lt;/a&gt;.
  Some of the open-source project that I work on don't have a GrumPHP configuration (yet).
  Most of those projects run Quality Assurance tools crafted out of composer scripts.
  Even on those projects, I want to make sure to commit good code before pushing it to a Pull Request.
  Since I got bored of waiting for the composer scripts to run one by one, I decided to dive into the composer internals in order to make composer scripts run in parallel as well.
&lt;/p&gt;

&lt;h1 id=&quot;shut-up-and-tell-me-how-to-use-it&quot;&gt;Shut up and tell me how to use it!&lt;/h1&gt;

&lt;p&gt;
  Configuring parallel scripts is like configuring any regular composer script.
  This package provides a `@parallel` script that takes other composer script aliases as arguments:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ci&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;@parallel cs tests&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;php-cs-fixer fix --dry-run&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tests&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;phpunit&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
  The code above adds a `ci` composer script to your project, that runs the coding styles and unit tests in parallel.
  You can run the script like this:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;composer run ci&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
  Most of the times, you don't want to introduce dependencies to projects you don't own.
  Therefore, this plugin also provides a `composer parallel` command.
  You can install this package globally, meaning you can unleash the power of parallel task execution even on packages that don't have this plugin installed:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;composer parallel cs tests&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h1 id=&quot;in-closing&quot;&gt;In closing&lt;/h1&gt;

&lt;p&gt;
  No more waiting!
  This &lt;a href=&quot;https://github.com/veewee/composer-run-parallel&quot; target=&quot;_blank&quot;&gt;veewee/composer-run-parallel&lt;/a&gt; plugin can be quickly added to any project and is fun to use.
  It contains a few more options. Head over to the readme on GitHub to learn more.
&lt;/p&gt;

&lt;p&gt;
  Whilst writing the plugin, I was pleasantly surprised by what is available in the composer codebase by default.
  Writing the package was a matter of linking the various existing components together.
  Big-ups to the composer team!
&lt;/p&gt;

&lt;p&gt;
  This plugin comes with one big limitation:
  Since it is only setting composer as a dependency, it is limited to the `Loop` and `ProcessExecutor` that is provided by composer.
  To display the result of a script, both the stderr and stdout are printed out to the end user.
  This could result in non-sequential output if the script you are executing mixes stdout and stderr messages.
&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Let GrumPHP fix your code!</title>
        <link href="http://veewee.github.io/blog/let-grumphp-fix-your-code/"/>
        <updated>2020-06-07T00:00:00+02:00</updated>
        <id>http://veewee.github.io/blog/let-grumphp-fix-your-code</id>
        <content type="html">&lt;p&gt;
    One of the most requested features is the ability to automatically fix broken code.
    Since previously we could not do this in a controlled an safe way, we decided that this won't be a GrumPHP feature.
    &lt;a href=&quot;https://github.com/phpro/grumphp/releases/tag/v0.19.0&quot; target=&quot;_blank&quot;&gt;In the new GrumPHP version&lt;/a&gt; (0.19.0), we rewrote the task runner system.
    Now it is possible to do these kind of code manipulations. 
    Let's see how it works...
&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
&lt;img src=&quot;/images/blog/20200607/fixer.gif&quot; width=&quot;100%&quot; /&gt;
&lt;/p&gt;

&lt;h2&gt;How do I get this madness to work?&lt;/h2&gt;

&lt;p&gt;
    No worries: Fixing is enabled by default!
    Currently we added fixers for `phpcs` and `PHP-CS-Fixer`.
    This list might be extended in the future and you can of course also provide fixers for your own custom tasks!
&lt;/p&gt;

&lt;h2&gt;How does GrumPHP knows what to fix?&lt;/h2&gt;
&lt;p&gt;
    GrumPHP will first run the configured tasks as it always did.
    When a task fails, we already provided the commandline command to fix the code.
    This resulted in manual copy/pasting the code, which is a stupid repeatable task.
    With this new feature, the task can now determine if it can autofix the code by e.g. running the console command it displayed.
    In a last phase before finishing the task runner, the autofixer process is initialized.
    It will look for fixable tasks and after asking for your consent, it will run the fix command that is provided from the task.
    GrumPHP will not add any new files to GIT or won't automatically commit these changes.
&lt;/p&gt;

&lt;h2&gt;You are in full control!&lt;/h2&gt;
&lt;p&gt;
    In previous versions, we only displayed the command line tool that you can use to fix your code.
    We never wanted GrumPHP to change code during a pre-commit or inside a CI cycle.
    Therefore, we decided to fix the code but don't stage the changes to git.
    This way, you can always review the changes that were made before recommitting the code.
&lt;/p&gt;

&lt;h2&gt;Don't touch my code!&lt;/h2&gt;

&lt;p&gt;
    I can imagine that you don't want GrumPHP to touch your code.
    Luckily, the fixer is configurable:
    You can choose to completely disable it or you can choose to change the default consent answer.
&lt;/p&gt;

&lt;p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# grumphp.yaml&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;grumphp&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;fixer&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;fix_by_default&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;/p&gt;

&lt;p&gt;
    &lt;em&gt;Note:&lt;/em&gt;
    The `fix_by_defaut` parameter will also be used in situations where CLI input is not supported.
    Depending on your CLI, this could be e.g. during pre-commit. 
&lt;/p&gt;

&lt;p&gt;
Enjoy and let me know what you think of it!
&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Running GrumPHP tasks in parallel</title>
        <link href="http://veewee.github.io/blog/running-grumphp-tasks-in-parallel/"/>
        <updated>2020-06-06T00:00:00+02:00</updated>
        <id>http://veewee.github.io/blog/running-grumphp-tasks-in-parallel</id>
        <content type="html">&lt;p&gt;
    Last week, we launched &lt;a href=&quot;https://github.com/phpro/grumphp/releases/tag/v0.19.0&quot; target=&quot;_blank&quot;&gt;a new version of GrumPHP&lt;/a&gt; (0.19.0).
    One of the main new features inside this release is the ability to run your tasks in parallel.
    This feature will save you a lot of waiting, both during pre-commit and on the CI environments!
&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
&lt;img src=&quot;/images/blog/20200606/parallel.gif&quot; width=&quot;100%&quot; /&gt;
&lt;/p&gt;

&lt;h2&gt;How do I get this madness to work?&lt;/h2&gt;

&lt;p&gt;
    Actually, you don't have to do anything! Parallel task execution is enabled by default.
    All tasks will run in parallel, unless you specify a different priority on a task.
    This way, you can specify parallel groups inside your configuration.
    Imagine following setup:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# grumphp.yaml&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;grumphp&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;tasks&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;phpcs&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;standard&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;PSR2&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;phpunit&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;~&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;clover_coverage&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;clover_file&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;test/clover.xml'&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;priority&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;-10&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    This configuration will run both `phpunit` and `phpcs` in parallel since they are both in priority group 0.
    When both tasks are ready, the `clover_coverage` task is started
&lt;/p&gt;

&lt;p&gt;
Enjoy and let me know what you think of it!
&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Optimizing PHP performance by using fully-qualified function calls</title>
        <link href="http://veewee.github.io/blog/optimizing-php-performance-by-fq-function-calls/"/>
        <updated>2016-12-21T00:00:00+01:00</updated>
        <id>http://veewee.github.io/blog/optimizing-php-performance-by-fq-function-calls</id>
        <content type="html">&lt;p&gt;
    Today, a little conversation on Twitter escalated rather quickly.
    Apparently PHP runs function calls differently depending on namespaced or non namespaced context.
    When calling functions in a namespaced context, additional actions are triggered in PHP which result in slower execution.
    In this article, I'll explain what happens and how you can speed up your application.
&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Wondering how much &lt;a href=&quot;https://twitter.com/hashtag/PHP?src=hash&quot;&gt;#PHP&lt;/a&gt; I could break by removing the local namespace lookup semantics for namespaced vs. core functions...&lt;/p&gt;&amp;mdash; Reviewed, BLYATIFUL! (@Ocramius) &lt;a href=&quot;https://twitter.com/Ocramius/status/811504929357660160&quot;&gt;December 21, 2016&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;p&gt;
    The conversation started with the tweet above. 
    To understand the difference between global and namespaced function calls better, I'll explain what is going on under the hood.
&lt;/p&gt;

&lt;h2&gt;Calling functions in the global namespace&lt;/h2&gt;

&lt;p&gt;Function calls in the global namespace look like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// global.php&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'bar'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;call_user_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'foo'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;After parsing this script, the opcodes look like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;php &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; vld.active&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1 &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; vld.execute&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0 global.php

...
line     &lt;span class=&quot;c&quot;&gt;#* E I O op                           fetch          ext  return  operands&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;-------------------------------------------------------------------------------------&lt;/span&gt;
   4     0  E &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;   EXT_STMT
         1        NOP
   8     2        EXT_STMT
         3        EXT_FCALL_BEGIN
         4        SEND_VAL                                                 &lt;span class=&quot;s1&quot;&gt;'foo'&lt;/span&gt;
         5        DO_FCALL                                      1          &lt;span class=&quot;s1&quot;&gt;'call_user_func'&lt;/span&gt;
         6        EXT_FCALL_END
         7      &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; RETURN                                                   1

...&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As you can see, this is a simple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EXT_FCALL&lt;/code&gt; sequence of opcodes.&lt;/p&gt;

&lt;h2&gt;Calling functions in a namespace&lt;/h2&gt;

&lt;p&gt;Function calls in a namespace look like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// namespaced.php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;baz&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'bar'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;call_user_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'foo'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;After parsing this script, the opcodes look like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;php &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; vld.active&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1 &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; vld.execute&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0 global.php

...
line     &lt;span class=&quot;c&quot;&gt;#* E I O op                           fetch          ext  return  operands&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;-------------------------------------------------------------------------------------&lt;/span&gt;
   4     0  E &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;   NOP
   6     1        EXT_STMT
         2        NOP
  10     3        EXT_STMT
         4        INIT_NS_FCALL_BY_NAME
         5        EXT_FCALL_BEGIN
         6        SEND_VAL                                                 &lt;span class=&quot;s1&quot;&gt;'foo'&lt;/span&gt;
         7        DO_FCALL_BY_NAME                              1
         8        EXT_FCALL_END
         9      &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; RETURN                                                   1
...&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The opcodes look pretty much the same as in the global namespace. 
However, there is one additional opcode added: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INIT_NS_FCALL_BY_NAME&lt;/code&gt;.
When PHP runs over this opcode, it will check if the function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;call_user_func()&lt;/code&gt; is found in the namespace.
If the function exists in the namespace, PHP will run this one.
When the function does not exist in current namespace, PHP will check if it exists in the global namespace and execute that one.&lt;/p&gt;

&lt;p&gt;This handy “feature” is frequently (ab)used during testing.
A good example for this (ab)use is overwriting the functions to read from or write to the filesystem.
In the source files, you can for example use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fopen()&lt;/code&gt; function.
During the tests, you can mock this function by placing it in the namespace of the class that you are testing.
An example of this can be found in the &lt;a href=&quot;https://github.com/thephpleague/flysystem/blob/master/tests/LocalAdapterTests.php&quot;&gt;local adapter of flysystem&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Benchmarks&lt;/h2&gt;

&lt;p&gt;One of the next tweets stated that a performance gain of 4.5% was made by using fully qualified function calls.
Of course, this is just a non-proven number and depends on the project you are working on.
To make sure that I am not writing nonsense, I made a little benchmark in PHP 7.1:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;php&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;PHP&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;7.1.0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cli&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;built&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Dec&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2016&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;29&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NTS&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;Copyright&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1997&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2016&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;The&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;PHP&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Group&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Zend&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Engine&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;.1.0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dev&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Copyright&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1998&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2016&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Zend&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Technologies&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Next, I wrote code that can be run with the &lt;a href=&quot;https://github.com/phpbench/phpbench&quot;&gt;phpbench tool&lt;/a&gt;.
There are 4 cases I covered:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Run a global function in a fully qualified way.&lt;/li&gt;
  &lt;li&gt;Run a global function in a non-fully qualified way.&lt;/li&gt;
  &lt;li&gt;Run an overridden function that exists globally and in the namespace.&lt;/li&gt;
  &lt;li&gt;Run a namespaced function.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ve chosen a rather big amount of revs and iterations to make sure the results are accurate.
The code in the benchmark looks like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/**
     * @Revs(10000)
     * @Iterations(100)
     */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MixedBench&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;benchFqGlobalFunction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;benchGlobalFunction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nf&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;benchOverriddenFunction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nf&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;benchNamespacedFunction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nf&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This is an overview of the results:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;phpbench run bench

&lt;span class=&quot;se&quot;&gt;\f&lt;/span&gt;oo&lt;span class=&quot;se&quot;&gt;\M&lt;/span&gt;ixedBench

    benchFqGlobalFunction         I99 P0 	&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;μ Mo]/r: 0.145 0.141 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;μs&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 	&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;μSD μRSD]/r: 0.018μs 12.59%
    benchGlobalFunction           I99 P0 	&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;μ Mo]/r: 0.148 0.145 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;μs&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 	&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;μSD μRSD]/r: 0.021μs 14.38%
    benchOverriddenFunction       I99 P0 	&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;μ Mo]/r: 0.157 0.157 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;μs&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 	&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;μSD μRSD]/r: 0.022μs 13.82%
    benchNamespacedFunction       I99 P0 	&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;μ Mo]/r: 0.157 0.159 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;μs&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 	&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;μSD μRSD]/r: 0.019μs 12.38%

4 subjects, 400 iterations, 40,000 revs, 0 rejects
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;best &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;mean mode] worst&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0.124 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;0.152 0.151] 0.225 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;μs&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
⅀T: 60.773μs μSD/r 0.020μs μRSD/r: 13.293%
suite: 133a2c5566a4e9fb57b0251cebfd189bc150f104, &lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt;: 2016-12-21, stime: 22:06:03

+-------------------------+-------+-----+---------+--------+
| subject                 | revs  | its | mean    | diff   |
+-------------------------+-------+-----+---------+--------+
| benchFqGlobalFunction   | 10000 | 100 | 0.145μs | 0.00%  |
| benchGlobalFunction     | 10000 | 100 | 0.148μs | +2.26% |
| benchNamespacedFunction | 10000 | 100 | 0.157μs | +8.55% |
| benchOverriddenFunction | 10000 | 100 | 0.157μs | +8.38% |
+-------------------------+-------+-----+---------+--------+&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As expected, the fully qualified global function call is the fastest one. 
This is because PHP does not need to go through the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INIT_NS_FCALL_BY_NAME&lt;/code&gt; opcode.
When calling the global function in a non-fully qualified way, it is slower.
Running functions inside a namespace are always slower then running global functions.&lt;/p&gt;

&lt;p&gt;Of course, this is not a big overhead in this simple benchmark.
It could be a big overhead if you think about the amount of function calls per run.
PHP is not able to optimize this since it is possible that functions get defined during runtime.&lt;/p&gt;

&lt;h2&gt;Speeding up your application&lt;/h2&gt;

&lt;p&gt;Currently the only way to speed up the function calls, is by making sure that the global functions are called in a fully qualified way.
This is a tedious manual action. You could do this in one of these 2 ways:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// solution 1:&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;baz&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// solution 2:&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;baz&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Luckily for us, the community is very creative and alert when it comes to performance.
Maybe one of the following (future) solutions is less boring to implement:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/nilportugues/php-backslasher&quot;&gt;Add the php_backslasher package as a git hook.&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Add a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;declare(no_dynamic_functions=1)&lt;/code&gt; on top of the PHP file or maybe in a future &lt;a href=&quot;https://wiki.php.net/rfc/namespace_scoped_declares&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;namespace_scoped_declares&lt;/code&gt;&lt;/a&gt; method.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtrack.jetbrains.com/issue/WI-34446&quot;&gt;Autocompletion to FQ function names in PHPStorm.&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/Ocramius/FunctionFQNReplacer&quot;&gt;Another awesome package by Ocramius?&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/kelunik/fqn-check&quot;&gt;A CLI tool that checks your files for FQ function calls.&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/phpro/grumphp/issues/325&quot;&gt;A GrumPHP task.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;
    As you can see, performance killers can hide in small corners.
    I'm glad to see how this little tweet can get this much feedback from the community in no time.
    Let's hope that a good solution for this performance problem will be added to PHP soon so that we can easily speed up our applications even more.
    Now that the secret behind this optimization is revealed, I am looking forward to discover more of these little performance killers.
&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Writing your first NodeJS Lambda function</title>
        <link href="http://veewee.github.io/blog/writing-your-first-nodjs-lambda-function/"/>
        <updated>2016-07-30T00:00:00+02:00</updated>
        <id>http://veewee.github.io/blog/writing-your-first-nodjs-lambda-function</id>
        <content type="html">&lt;p&gt;
    Last week I was playing around with writing some custom &lt;a href=&quot;https://slack.com/&quot; target=&quot;_blank&quot;&gt;Slack&lt;/a&gt; slashcommands and cronjobs.
    Originally, I started writing these integrations with PHP. 
    Since slack requires a publically available endpoint and I did not want to set up a server for these scripts,
    I decided to take a look at &lt;a href=&quot;https://aws.amazon.com/lambda/details/&quot; target=&quot;_blank&quot;&gt;AWS Lambda&lt;/a&gt;.
    This Amazon service makes it possible to run scripts serverless. The scripts are triggered based on triggers inside of AWS.
    In this artile you can find out how to get started with writing lambda functions.
&lt;/p&gt;

&lt;h2&gt;Selecting the right tools&lt;/h2&gt;

&lt;p&gt;
    AWS Lambda can run Python, Java and NodeJS scripts.
    Since I've got some experience writing &lt;a href=&quot;https://nodejs.org/en/&quot; target=&quot;_blank&quot;&gt;NodeJS&lt;/a&gt;, I've choosen to go for this technology.
    There are many tools available for writing Lambda functions in NodeJS. 
    After investigating these tools, I've decided to go with &lt;a href=&quot;https://github.com/Testlio/lambda-tools&quot; target=&quot;_blank&quot;&gt;lambda-tools&lt;/a&gt;.
    This tool makes it easy to develop and deploy multiple lambda functions inside one codebase. 
    It comes with a Yeoman generator named &lt;a href=&quot;https://github.com/Testlio/generator-lambda-tools&quot;&gt;generator-lambda-tools&lt;/a&gt;.
&lt;/p&gt;

&lt;h2&gt;Getting started&lt;/h2&gt;

&lt;p&gt;
    The first thing we'll want to do is scafold the application:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;yo lambda-tools

? Service name: your-lambda-name
? Service description: Some Description
? License &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;API&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;: MIT
? Author email your-email
? Author name your-name
? Default Lambda runtime Node.js 4.3
? Install dependencies lambda-tools, lambda-foundation&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    When the command is finished, you'll find a project structure like this:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
├── .lambda-tools-rc.json
├── .yo-rc.json
├── api.json
├── cf.json
├── lambdas/
└── node_modules/&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    There are 2 hidden configuration files named `.lambda-tools-rc.json` and `.yo-rc.json`. 
    These are used to configure the yeoman generator and the lambda-tools command.
    The `api.json` is used for the &lt;a href=&quot;https://aws.amazon.com/api-gateway/&quot; target=&quot;_blank&quot;&gt;AWS API Gateway&lt;/a&gt; service.
    This service will make it possible to create a public endpoint that triggers the Lambda method we'll create next.
    &lt;br /&gt;
    The `cf.json` is used for the &lt;a href=&quot;https://aws.amazon.com/cloudformation/&quot; target=&quot;_blank&quot;&gt;AWS CloudFormation&lt;/a&gt; service.
    This service will take care of orchestrating the related AWS services. 
    It will be used to deploy your lambda functions and let all the AWS services talk to each other.
    &lt;br /&gt;
    The `lambdas` directory is currently empty, but will contain all the lambda functions you are going to write.
    &lt;br /&gt;
    Finally there is the `node_modules` directory which contains all your project dependencies.
&lt;/p&gt;

&lt;h2&gt;Writing your first lambda&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;yo lambda-tools:lambda

? Lambda &lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;name: mylambda
? Create event.json: Yes&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    The command above will create a folder named `mylambda` inside the `lambdas` directory.
    In this folder there are 2 files: `event.json` and `index.js`.
    The event.json contains the data that will be used as input for the Lambda function.
    Feel free to put it in `.gitignore` since you can only use this for testing purpose.
    The `index.js` file contains a `handler()` method and looks like this:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;use strict&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;handler&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;succeed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Hello!&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    The callback has 2 parameters:
    `event` which will be populated by AWS Lambda. During development this parameter can be linked to the `event.json` file.
    `context` which will make it possible to `succeed()` or `fail()` the lambda method.
    The parameters added to these 2 functions will be returned as result of the lambda:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;node node_modules/lambda-tools/bin/lambda.js execute ./lambdas/mylambda/index.js &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; lambdas/mylambda/event.json &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;Executing: lambdas/mylambda/index.js
	--
	With event:
	{}
	--


	--
	Result 'Hello!'&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2&gt;Creating a cronjob&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;yo lambda-tools:periodic-lambda      

? Lambda &lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;name cronjob
? Create event.json Yes
? Schedule/Rate expression cron&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;0 10 &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; ? &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
? CloudWatch rule name &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;leave empty &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;automatic name&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; ten-o-clock
? CloudWatch rule logical ID &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;used &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;CloudFormation template&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; TenOClockEvent
? CloudWatch rule description &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;leave empty to skip&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
? CloudWatch rule static input &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;JSON string, leave empty to skip&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
? CloudWatch rule input path &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;JSONPath string, leave empty to skip&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
? Is CloudWatch rule ENABLED? Yes&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    In &lt;a href=&quot;https://aws.amazon.com/cloudwatch/&quot; target=&quot;_blank&quot;&gt;AWS CloudWatch&lt;/a&gt;, it is possible to create RATE or CRON rules.
    These rules can be the trigger for a Lambda function to execute. This means it is possible to create a lambda function that executes periodically.
    The generated code looks and behaves exactly the same as the `mylambda` code above.
    In the `cf.json` file, a event rule is added to cloudwatch and the event is linked to the lambda function.
&lt;/p&gt;

&lt;h2&gt;Creating an API endpoint&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;yo lambda-tools:endpoint   

? Path &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;the endpoint /lambdas/apilambda
? HTTP Method POST
? Lambda &lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;name lambdas-apilambda-post
? Map request body to event property &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;leave blank to skip&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; body
? Map HTTP headers? No&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    By adding an API endpoint, you can create a publically available HTTPS endpoint that triggers a Lambda function.
    The generated code again looks the same as the `mylambda` code.
    The `api.json` file is altered and now describes the new endpoint:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;paths&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;/lambdas/apilambda&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;post&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;responses&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;200&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Default response&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;schema&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;object&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;properties&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;additionalProperties&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;parameters&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;x-amazon-apigateway-auth&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;none&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;x-amazon-apigateway-integration&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;aws&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;uri&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;$lLambdasApilambdaPost&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;credentials&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;$IamRoleArnApiGateway&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;httpMethod&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;POST&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;requestParameters&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;requestTemplates&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;application/json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;{&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;$context.resourcePath&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:$input.json('$')}&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;responses&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;statusCode&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;200&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;responseTemplates&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                                &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;application/json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;$input.json('$')&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    The added path describes the endpoint. 
    As you can see it only handles POST requests with a content-type of `application/json`.
    The JSON body of the request is added as the &quot;body&quot; parameter of the Lambda event.
    This is done internally through the `x-amazon-apigateway-integration` header.
    In the response you'll have to add the responseTemplate to make sure that the result of the lambda is returned as JSON.
    You can test the API endpoint with following commands:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;c&quot;&gt;# This command will start a server on port 3000:&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;node node_modules/lambda-tools/bin/lambda.js run &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; api.json

&lt;span class=&quot;c&quot;&gt;# Send a curl request:&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; POST &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Content-Type: application/json&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'{request: &quot;will be added to event as body param&quot;}'&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;http://localhost:3000/lambdas/apilambda&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    This HTTP request will be handled as followed:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;  &lt;span class=&quot;nt&quot;&gt;&amp;lt;--&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;POST&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;lambdas&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;apilambda&lt;/span&gt;
	&lt;span class=&quot;err&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Configuring&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Lambda&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;function&lt;/span&gt;
	&lt;span class=&quot;na&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt; Configuring Lambda function 1ms

	&lt;span class=&quot;nt&quot;&gt;&amp;lt;--&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Creating&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;integration&lt;/span&gt;
	&lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;apiId&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;local-lambda&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;,&lt;/span&gt;
			&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;httpMethod&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;,&lt;/span&gt;
			&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;identity&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{},&lt;/span&gt;
			&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;requestId&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;&quot;98&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;e626ab-bbc7-4be2-a94c-b6f622b1d140&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;,&lt;/span&gt;
			&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;resourceId&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;POST&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;lambdas&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;apilambda&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;,&lt;/span&gt;
			&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;resourcePath&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;&quot;/&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;lambdas&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;apilambda&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;,&lt;/span&gt;
			&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;stage&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dev&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;
		&lt;span class=&quot;err&quot;&gt;},&lt;/span&gt;
		&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;&quot;/&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;lambdas&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;apilambda&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;,&lt;/span&gt;
			&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;will&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;be&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;added&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;
			&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;na&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt; Creating integration 14ms

	&lt;span class=&quot;nt&quot;&gt;&amp;lt;--&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Executing&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Lambda&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;lambdas-apilambda-post&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;index.handler&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;)&lt;/span&gt;


	&lt;span class=&quot;na&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt; Executing Lambda function 151ms

	&lt;span class=&quot;nt&quot;&gt;&amp;lt;--&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Creating&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;response&lt;/span&gt;
	&lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;200,&lt;/span&gt;
		&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{},&lt;/span&gt;
		&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;,&lt;/span&gt;
		&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;!&quot;&lt;/span&gt;
	&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;na&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt; Creating response 1ms

  --&amp;gt; POST /lambdas/apilambda 200 200ms 87b&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2&gt;Configuring AWS&lt;/h2&gt;

&lt;p&gt;
    Now that we've created our lambda methods, the next step is to deploy them to AWS.
    This step is not documented very good, so I'll try to describe it as good as possible.
&lt;/p&gt;

&lt;p&gt;
    First you'll need to create a user with the &lt;a href=&quot;https://github.com/Testlio/lambda-tools#iam-permissions&quot;&gt;IAM-permissions described on the lambda-tools page&lt;/a&gt;.
    When you've created this user, you'll have to make sure that the user has an Access Key so that it can be used to automate stuff.
    Now that you've got both the Access Id and Secret Access Key, you'll have to generate an API token: 
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;aws configure
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;aws sts get-session-token&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    Now that we have all the AWS parameters, we'll need to create a `.env` file so that the tool knows how to deploy the application:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;AWS_ENVIRONMENT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;dev
&lt;span class=&quot;nv&quot;&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;your-key-id
&lt;span class=&quot;nv&quot;&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;your-key-secret
&lt;span class=&quot;nv&quot;&gt;AWS_SESSION_TOKEN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;your-key-token
&lt;span class=&quot;nv&quot;&gt;AWS_REGION&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;eu-west-1
&lt;span class=&quot;nv&quot;&gt;AWS_RUNTIME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;nodejs4.3
&lt;span class=&quot;nv&quot;&gt;EXCLUDE_GLOBS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;event.json *.env *.dist&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;PACKAGE_DIRECTORY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;build&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    Finally we need to configure a &lt;a href=&quot;https://aws.amazon.com/s3&quot;&gt;AWS S3&lt;/a&gt; bucket in which the lambda functions will be stored.
    This needs to be a unique index which can be configured in the `.lambda-tools-rc.json` file. 
    Add following `tools` to the root element:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tools&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;resources&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;s3Bucket&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;your-unique-s3-bucket-name&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    Now that we've configured the project source code to run with AWS, we'll have to set up everything in AWS.
    Luckilly this can be done with one simple command that only needs to run once:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;node node_modules/lambda-tools/bin/lambda.js setup &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; eu-west-1&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2&gt;Deploying your lambdas to AWS&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;node node_modules/lambda-tools/bin/lambda.js deploy &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; eu-west-1&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    By running the command above, the lambdas are build into some archive files.
    These archive files are stored in your AWS S3 Bucket.
    When this is done, the `cf.json` file is added to AWS CloudFormation which will start the orchestration of the installation:
&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;A CloudFormation stack will be created or updated based on the `cf.json` file.&lt;/li&gt;
    &lt;li&gt;The source code of the lambdas are stored in your S3 Bucket&lt;/li&gt;
    &lt;li&gt;IAM permissions will be added&lt;/li&gt;
    &lt;li&gt;A new scheduling rule will be added to CloudWatch.&lt;/li&gt;
    &lt;li&gt;New logging groups will be added to CloudWatch.&lt;/li&gt;
    &lt;li&gt;The API gateway will be configured with the `api.json` file.&lt;/li&gt;
    &lt;li&gt;The lambdas will be created and configured.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Adding configurable variables to the lambdas&lt;/h2&gt;

&lt;p&gt;
    Adding custom configuration to a lambda function can be done based on environment variables.
    These variables can be added with the `-e` option during a deploy.
    When you've got a lot of configurable variables, another option is to add a .env file to every lambda directory and use the 
    &lt;a href=&quot;https://github.com/ncthis/env-loader&quot; target=&quot;_blank&quot;&gt;env-loader&lt;/a&gt;.
    You'll have to create an asset to make sure the .env file is added to your lambda source code.
    This can be done by adding a new `cf.json` file to every lambda directory that looks like:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Assets&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;.env&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;.env&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;
    If you are writing your first AWS project, getting started is pretty complex.
    The documentation is rather big and you'll have to find your way in all the different AWS services.
    Once you found your way and got your project set-up and configured, writing Lambda functions is pretty fun.
    They are easy to understand and there are a lot of NPM packages available for Rapid Application Development.
    I am definitely looking forward in writing more Lambda integrations!
&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>GrumPHP approves Bitbucket Pipelines!</title>
        <link href="http://veewee.github.io/blog/grumphp-approves-bitbucket-pipelines/"/>
        <updated>2016-06-15T00:00:00+02:00</updated>
        <id>http://veewee.github.io/blog/grumphp-approves-bitbucket-pipelines</id>
        <content type="html">&lt;p&gt;
    Today, my invitation for 
    &lt;a href=&quot;https://bitbucket.org/&quot; target=&quot;_blank&quot;&gt;Bitbucket&lt;/a&gt;
    Pipelines Beta got accepted!
    For those who haven't heard about it: 
    &lt;a href=&quot;https://bitbucket.org/product/features/pipelines&quot; target=&quot;_blank&quot;&gt;Pipelines&lt;/a&gt; 
    is a Continuous Delivery tool integrated in Bitbucket.
    When you push your changes to your Bitbucket repository, it will spin up a 
    &lt;a href=&quot;http://docker.io/&quot; target=&quot;_blank&quot;&gt;Docker&lt;/a&gt; 
    container and run the actions you specify.
    I was quite exited about the concept and immediately started to set up an automated test scenario with 
    &lt;a href=&quot;https://github.com/phpro/grumphp&quot; target=&quot;_blank&quot;&gt;GrumPHP&lt;/a&gt;.
&lt;/p&gt;

&lt;h2&gt;Configuration&lt;/h2&gt;

&lt;p&gt;
    The configuration of Pipelines is similar to existing services like e.g. 
    &lt;a href=&quot;https://travis-ci.org/&quot; target=&quot;_blank&quot;&gt;Travis&lt;/a&gt;.
    It all starts by adding a 
    &lt;a href=&quot;https://confluence.atlassian.com/bitbucket/configure-bitbucket-pipelines-yml-792298910.html&quot; target=&quot;_blank&quot;&gt;bitbucket-pipelines.yml&lt;/a&gt; 
    file to the root of your project. 
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;bitbucket-pipelines.yml:&lt;/strong&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;php:7.0-cli&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;pipelines&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;apt-get update &amp;amp;&amp;amp; apt-get install -y git&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;php -r &quot;readfile('https://getcomposer.org/installer');&quot; | php&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;php composer.phar global require hirak/prestissimo&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;php composer.phar install --prefer-dist&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;./vendor/bin/grumphp run&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    After every commit, the pipelines file will be loaded.
    Since we've added a default pipeline, it will spin up a basic &lt;a href=&quot;https://hub.docker.com/_/php/&quot; target=&quot;_blank&quot;&gt;PHP 7.0 container&lt;/a&gt;.
    Because it's a basic container, we'll have to install git and composer to make sure the test scenario works.
    The installation of these packages will happen on every commit,
    so it is better to create your own container which contains all the tools you need to test your code.
    Finally, the composer dependencies are installed and the GrumPHP command is being triggered.
&lt;/p&gt;

&lt;h2&gt;Analysing the results&lt;/h2&gt;

&lt;p class=&quot;text-center&quot;&gt;
    &lt;a href=&quot;/images/blog/20160615/pipelines-overview.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;/images/blog/20160615/pipelines-overview.png&quot; alt=&quot;GrumPHP Pipelines&quot; class=&quot;img-responsive&quot; /&gt;&lt;/a&gt;
&lt;p&gt;

&lt;p&gt;
    As you can see, the Pipelines overview page is very clean and focuses on the output of your tasks.
    Every commit will trigger a new run and a new results overview page.
    This makes it very easy to spot problems before they got merged in!
&lt;/p&gt;


&lt;h3&gt;Pros&lt;/h3&gt;
&lt;ul&gt;
    &lt;li&gt;It is a unique service that integrates completely on your git server!&lt;/li&gt;
    &lt;li&gt;The interface is very simple and focuses on the errors.&lt;/li&gt;
    &lt;li&gt;Pipelines is integrated in every screen in Bitbucket. You get feedback about the committed code in a wink of an eye.&lt;/li&gt;
    &lt;li&gt;It is possible to let Pipelines handle your Continuous Delivery flow!&lt;/li&gt;
    &lt;li&gt;You can specify different steps per git branch.&lt;/li&gt;
    &lt;li&gt;It works perfectly fine with GrumPHP!&lt;/li&gt;
    &lt;li&gt;It is FREE!&lt;/li&gt;
&lt;/ul&gt;


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

&lt;ul&gt;
    &lt;li&gt;The docker image is loaded from &lt;a href=&quot;https://hub.docker.com&quot; target=&quot;_blank&quot;&gt;DockerHub&lt;/a&gt; which takes a while.&lt;/li&gt;
    &lt;li&gt;You can only specify 1 image, which means you cannot test every commit against multiple PHP versions.&lt;/li&gt;
    &lt;li&gt;It is not possible to cache the composer packages. All dependencies are downloaded on every commit.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;
    Bitbucket has done a really great job creating ther unique Pipelines service! 
    Currently it is still in Beta which means they are still working on making it even better. 
    I hope to see some additional features like running tests on multiple images, caching volumes, ... in a near future.
    In a next phase, I will be playing around with the Continuous Delivery options and maybe link Pipelines 
    with an 
    &lt;a href=&quot;https://www.ansible.com/&quot; target=&quot;_blank&quot;&gt;Ansible&lt;/a&gt;
    script to automatically deploy the changes to a development server.
&lt;/p&gt;
&lt;/p&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Authenticating with X.509 client certificates</title>
        <link href="http://veewee.github.io/blog/authenticating-with-x509-client-certificates/"/>
        <updated>2015-12-07T00:00:00+01:00</updated>
        <id>http://veewee.github.io/blog/authenticating-with-x509-client-certificates</id>
        <content type="html">&lt;p&gt;
    Last week, I was diving in different authentication systems for API's.
    One of the better ways of authentication is through &lt;a href=&quot;https://en.wikipedia.org/wiki/X.509&quot; target=&quot;_blank&quot;&gt;X.509 client certificates&lt;/a&gt;.
    This one is a bit is harder to set-up, but sure is secure, manageable and powerful.
    While searching for documentation on the subject, I was surprised there weren't a lot of good articles.
    In this article, I will try to explain every step as easy as possible.
&lt;/p&gt;

&lt;h2&gt;Why should I use X.509 authentication?&lt;/h2&gt;
&lt;p&gt;
    The main advantage is that the client is not sending a username or password to the server. 
    This means that a man-in-the-middle attack is nearly impossible. 
    It is much easier to steal a username/password login, for example by bruteforcing, then stealing a certificate.
    Because the certificate is signed, it is only possible to connect to the real server.
    It is possible to revoke and manage these certificates in an easy way.
&lt;/p&gt;

&lt;h2&gt;Configuring the server&lt;/h2&gt;

&lt;p&gt;
    Client Certificate authentication can only be done while running HTTPS.
    So first of all, make sure the server is running HTTPS. 
    This can be done with a self-signed or a signed certificate.
    Your apache VHost configuration should look more or less like this:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-apache&quot; data-lang=&quot;apache&quot;&gt;&lt;span class=&quot;nc&quot;&gt;SSLEngine&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;on&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;SSLCertificateFile&lt;/span&gt;      &quot;/etc/ssl/certs/server.pem&quot;
&lt;span class=&quot;nc&quot;&gt;SSLCertificateKeyFile&lt;/span&gt;   &quot;/etc/ssl/private/server.key&quot;
&lt;span class=&quot;nc&quot;&gt;SSLProtocol&lt;/span&gt;             TLSv1 TLSv1.1 TLSv1.2
&lt;span class=&quot;nc&quot;&gt;SSLCipherSuite&lt;/span&gt;          &quot;.......&quot;
 
&lt;span class=&quot;c&quot;&gt;# When using signed certificates:&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;SSLCertificateChainFile&lt;/span&gt; &quot;/etc/ssl/yourDomainName.ca-bundle&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    Now that you got HTTPS up and running, you should be able to browse to your application through HTTPS. 
&lt;/p&gt;

&lt;h3&gt;Creating a certification authority&lt;/h3&gt;

&lt;p&gt;
    A certification authority (CA) hands out a digital certificate in which the CA says that a public key in the certificate, 
    belongs to the person, organization, server or entity that is mentioned in the certificate.
    In our example, this will be done based on the e-mail address that is provided in the certificate.
    The task of the CA is to control the identity of the issuer, so that the client that is using the certificates from the CA can be trusted.
&lt;/p&gt;

&lt;p&gt;
    First we will need to create the CA private key and certificate:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /etc/ssl/certs/
openssl genrsa &lt;span class=&quot;nt&quot;&gt;-out&lt;/span&gt; ca.key 4096
openssl req &lt;span class=&quot;nt&quot;&gt;-new&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-x509&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-days&lt;/span&gt; 365 &lt;span class=&quot;nt&quot;&gt;-key&lt;/span&gt; ca.key &lt;span class=&quot;nt&quot;&gt;-out&lt;/span&gt; ca.crt&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;div class=&quot;alert alert-warning&quot;&gt;
    &lt;strong&gt;Note:&lt;/strong&gt; Make sure to set the CN to a valid server domain. Otherwise this might result in exceptions!
&lt;/div&gt;

&lt;p&gt;
    Now that we have the CA key and certificate, we can register it to Apache to validate the client certificates:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-apache&quot; data-lang=&quot;apache&quot;&gt;&lt;span class=&quot;nc&quot;&gt;SSLCACertificateFile&lt;/span&gt; &quot;/etc/ssl/certs/ca.crt&quot;
&lt;span class=&quot;nc&quot;&gt;SSLVerifyClient&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;optional&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;SSLVerifyDepth&lt;/span&gt; 1
&lt;span class=&quot;nc&quot;&gt;SSLOptions&lt;/span&gt; +StdEnvVars&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    As you can see the client certificate verification is optional. 
    This will make it possible to add another type of authentication like basic authentication when there is nog client certificate.
    The verify depth is set to 1 so that it only accepts certificates signed by the configured CA.
    Finally, the StdEnvVars are registered so that the additional SSL server variables are available in PHP.
&lt;/p&gt;

&lt;h2&gt;Configuring the client&lt;/h2&gt;

&lt;p&gt;
    Now that we got or server fully configured, it is time to create a client certificate.
    Following commands should be ran on the client machine to create a Certificate Signing Request (CSR):
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;openssl genrsa &lt;span class=&quot;nt&quot;&gt;-out&lt;/span&gt; client.key 4096
openssl req &lt;span class=&quot;nt&quot;&gt;-new&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-key&lt;/span&gt; client.key &lt;span class=&quot;nt&quot;&gt;-out&lt;/span&gt; client.csr&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;div class=&quot;alert alert-warning&quot;&gt;
    &lt;strong&gt;Note:&lt;/strong&gt; Make sure to set the CN to a valid server domain. Otherwise this might result in exceptions!&lt;br /&gt;
    &lt;strong&gt;Note:&lt;/strong&gt; The email field will be used to authenticate the user.
&lt;/div&gt;

&lt;p&gt;
    The CSR file is useless when it is not signed by the CA.
    So the logical next step is to transfer the certificate to the server and sign it with the CA.
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;openssl x509 &lt;span class=&quot;nt&quot;&gt;-req&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-days&lt;/span&gt; 365 &lt;span class=&quot;nt&quot;&gt;-in&lt;/span&gt; client.csr &lt;span class=&quot;nt&quot;&gt;-CA&lt;/span&gt; ca.crt &lt;span class=&quot;nt&quot;&gt;-CAkey&lt;/span&gt; ca.key &lt;span class=&quot;nt&quot;&gt;-set_serial&lt;/span&gt; 01 &lt;span class=&quot;nt&quot;&gt;-out&lt;/span&gt; client.crt&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    The command above results in a useful client certificate. 
    To make it easier to use the certificate, we will pack the client private key and the certificate in one file.
    This action should run on the client machine:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;cat &lt;/span&gt;client.crt client.key &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; client.pem&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;div class=&quot;alert alert-warning&quot;&gt;
    &lt;strong&gt;Note:&lt;/strong&gt; it's important to place the crt before the key in the pem file!
&lt;/div&gt;

&lt;p&gt;
    In above example the CSR was created on the client, to make it clear that the certificate + key should only be known by the client.
    However, it is perfectly possible to run all these commands on the server and send the pem file to the client who will be using the certificate.
    This means that the creation of the client certificate can be automated. 
    You could create your own user interface to make the keys manageable per user of the application.
    This can for example be done with the built-in &lt;a href=&quot;http://php.net/manual/en/book.openssl.php&quot; target=&quot;_blank&quot;&gt;openssl&lt;/a&gt; extension of PHP.
    When the certification file is generated on the server, you should transfer this certificate in a trusted way. 
    For example a download over HTTPS in the back-end of your application.
&lt;/p&gt;

&lt;h2&gt;Requesting resources with a client certificate&lt;/h2&gt;

&lt;p&gt;
    Ok, we configured our server and requested a client certificate. 
    Now how do I use this certificate to get my resources?
    The easiest way is the add the &quot;&lt;em&gt;-cert&lt;/em&gt;&quot; attribute to the curl command.
    Since we are using Guzzle for HTTP requests, the client configuration will look like this:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Guzzle\Http\Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$baseUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'ssl.certificate_authority'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'system'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'request.options'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;'cert'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'client.pem'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    As you can see it is possible to specify the certificate in the request.options part of the configuration.
    Another option is the ssl.certificate_authority. This one can be used to specify which CA that should be used. 
    By default the built-in CA file is being used.
    You can choose to disable ssl verification or add your own ca file.
    For example, when using self-signed certificates, you can run following command:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;openssl s_client &lt;span class=&quot;nt&quot;&gt;-showcerts&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-connect&lt;/span&gt; my.host.com:443 &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ca-file.pem&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    This ca-file.pem file will contain the certificate of the certification authority and mark it as trusted. 
    Now it can be used in the PHP configuration as followed:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Guzzle\Http\Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$baseUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'ssl.certificate_authority'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'ca-file.pem'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'request.options'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;'cert'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'client.pem'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2&gt;X.509 authentication in Symfony&lt;/h2&gt;

&lt;p&gt;
    One of the less known features of Symfony is X.509 authentication.
    It can easily be configured with the default x509 authentication security adapter.
    The configuration is pretty easy:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;na&quot;&gt;security&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;providers&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;client_certificate&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
                    &lt;span class=&quot;na&quot;&gt;email@certification.file&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
                      &lt;span class=&quot;na&quot;&gt;roles&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ROLE_SUPER_ADMIN&lt;/span&gt;
 
    &lt;span class=&quot;na&quot;&gt;firewalls&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;x509&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;client_certificate&lt;/span&gt;
 
    &lt;span class=&quot;na&quot;&gt;access_control&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;^/&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;roles&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ROLE_SUPER_ADMIN&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;requires_channel&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;https&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;div class=&quot;alert alert-warning&quot;&gt;
    &lt;strong&gt;Note:&lt;/strong&gt; This type of authentication only works with HTTPS. 
    &lt;a href=&quot;http://symfony.com/doc/current/cookbook/security/force_https.html&quot; target=&quot;_blank&quot;&gt;You might want to enforce HTTPS&lt;/a&gt;!
&lt;/div&gt;

&lt;p&gt;
    As you can see HTTPS is enforced and authentication will try X.509 authentication by default.
    When a valid client certificate is found, 
    Symfony will try to match the email that is configured inside the certificate with a user in the client_certificate user provider.
    In this case we are using an in-memory provider that links an e-mail to a security role.
&lt;/p&gt;

&lt;h2&gt;X.509 authentication in PHP&lt;/h2&gt;

&lt;p&gt;
    That was easy! But how does it work?
    By adding the &quot;SSLOptions +StdEnvVars&quot; configuration in Apache, there are some additional &quot;&lt;em&gt;SSL_&lt;/em&gt;&quot; environment variables available.
    These variables contain the email in the client certificate. For example:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$email&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$_SERVER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'SSL_CLIENT_S_DN_Email'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$email&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;preg_match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'#/emailAddress=(.+\@.+\..+)(/|$)#'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$_SERVER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'SSL_CLIENT_S_DN'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$matches&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$email&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$matches&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    Now that we have the e-mail, it is possible to search this email in the list of configured client_certificates.
    Symfony will throw an exception when the email can't be found.
&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;
    Even though it is a lot of work to get this type of authentication running,
    it sure is a powerful type of authentication. 
    The users of your application will be able to connect to your application in an improved and secure way. 
    It also comes in very handy for server to server communication in which you don't always want to hardcode user credentials.
    Your customers will surely thank you for the extra effort you made!
&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Hijacking your code with streams</title>
        <link href="http://veewee.github.io/blog/hijacking-your-code-with-streams/"/>
        <updated>2015-10-26T00:00:00+01:00</updated>
        <id>http://veewee.github.io/blog/hijacking-your-code-with-streams</id>
        <content type="html">&lt;p&gt;
    Lately, you might have noticed that streams are getting more important in the PHP scene.
    They are for example widely used in 
    &lt;a href=&quot;http://www.php-fig.org/psr/psr-7/&quot; target=&quot;_blank&quot;&gt;PSR-7&lt;/a&gt; and implemented in
    &lt;a href=&quot;https://github.com/zendframework/zend-diactoros&quot; target=&quot;_blank&quot;&gt;Diactoros&lt;/a&gt;.
    Yesterday I was scrolling down the issues list of &lt;a href=&quot;http://phpspec.readthedocs.org/en/latest/&quot; target=&quot;_blank&quot;&gt;Phpspec&lt;/a&gt; 
    and bumped in on &lt;a href=&quot;https://github.com/phpspec/phpspec/pull/788&quot; target=&quot;_blank&quot;&gt;this pull request&lt;/a&gt;.
    This pull request shows that it is possible to convert code in-memory and later require the modified content to be executed.
    Wow, that is awesome! Let's take a look at it.
&lt;/p&gt;

&lt;h2 id=&quot;the-concept&quot;&gt;The concept&lt;/h2&gt;
&lt;p&gt;
    You probably already used some built-in PHP streams like regular files, `php://memory` or `data://...` 
    in combination with the `fopen()` method or the `StdFileObject` class.
    Beside those built-in streams, it is possible to configure your own stream wrappers.
    For this post I will be creating a blacklist stream that will remove blacklisted methods from your code.
    The blacklist stream wrapper will read a PHP file and replaces blacklisted methods from the code.
    When the file is required through the blacklist wrapper, all blacklisted methods will be removed from the code.
&lt;/p&gt;

&lt;h2 id=&quot;show-me-some-code&quot;&gt;Show me some code&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StreamWrapper&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$realPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$fileResource&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$blacklistedMethods&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blacklistMethod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$blacklistedMethods&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream_open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$mode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$opened_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;realPath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;preg_replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'|^blacklist://|'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;file_exists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;realPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;file_get_contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;realPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$blacklistedMethods&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$blacklistedMethod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;preg_replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/^'&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$blacklistedMethod&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'\([^\)]*\);$/im'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fileResource&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;fopen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'php://memory'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'w+'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;fwrite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fileResource&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;rewind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fileResource&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$opened_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;realPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream_stat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;stat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;realPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;fread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fileResource&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream_eof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;feof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fileResource&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;/h2&gt;

&lt;p&gt;To use the stream wrapper, you have to register it with the name blacklist.
Next you can require the file with the new stream URL. 
Internally PHP will open the file with your custom stream reader.
This means that you can alter the content of the PHP file in an in-memory stream which will be used by PHP.
Here is what the file looks like.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// run.php&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'StreamWrapper.php'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;StreamWrapper&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;blacklistMethod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'die'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;stream_wrapper_register&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'blacklist'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'StreamWrapper'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'blacklist://test.php'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The above code needs a file test.php. This file looks like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// test.php&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;die&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'now you see me ...'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'now you dont!'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;When executing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;run.php&lt;/code&gt; you will see the result:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;php run.php
now you dont!&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;what-the-hell-did-i-just-read&quot;&gt;What the hell did I just read…&lt;/h2&gt;
&lt;p&gt;
    I know, most projects won't need in-memory code adjustments. 
    The blacklist wrapper in this post will probably never be needed, but it is used to show you what is possible.
    Streams are pretty cool and will probably become more important in the future.
&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Replacing service dependencies with proxies</title>
        <link href="http://veewee.github.io/blog/replacing-service-dependencies-with-proxies/"/>
        <updated>2014-10-11T00:00:00+02:00</updated>
        <id>http://veewee.github.io/blog/replacing-service-dependencies-with-proxies</id>
        <content type="html">&lt;p&gt;
    When using the Zend Framework 2 service manager, it is possible to create shared services that will be loaded only once.
     In some situations however, it is very hard to switch the already injected dependencies in this service.
     You could mark the service as unshared even if this is often unnecessary.
     Another solution is to wrap the service with a proxy object and use the proxy instead of the service. 
&lt;/p&gt;

&lt;h2 id=&quot;real-life-scenario&quot;&gt;Real-life Scenario&lt;/h2&gt;
&lt;p&gt;
    In an application with multiple tenants, there is one database per tenant.
     When browsing the application the tenant's database connection is always known.
     This connection doesn't ever change when browsing the application.
     Therefor the Doctrine DocumentManager is injected and the services are marked as shared.
&lt;/p&gt;
&lt;p&gt;
    On the server, there are some long-running processes to handle async commands.
     These processes run globally and are not dependant on a specific tenant.
     This means that the processes need to switch the DocumentManager based on the tenant they are working for at the moment.
&lt;/p&gt;
&lt;p&gt;
    Off course, the registered services have to work with the current DocumentManager, even if they are marked as shared.
&lt;/p&gt;

&lt;h2 id=&quot;delegators&quot;&gt;Delegators&lt;/h2&gt;
&lt;p&gt;
    One of the cool features of ZF2 are 
     &lt;a href=&quot;http://framework.zend.com/manual/2.3/en/modules/zend.service-manager.delegator-factories.html&quot; target=&quot;_blank&quot;&gt;service delegators&lt;/a&gt;.
     These delegators make it possible to attach or wrap custom functionality to an instance.
     In this case we will use the delegator to wrap the actual service in a proxy.
     The instance of the service will still be created in the service manager like before, 
     but instead of returning this instance we will return a proxy object.
&lt;/p&gt;

&lt;h2 id=&quot;proxies&quot;&gt;Proxies&lt;/h2&gt;
&lt;p&gt;
    In this post, I already talked a lot about using proxies. But what are those proxies?
&lt;/p&gt;
&lt;p&gt;
    The short answer: Proxies are objects that serve as a gateway to the actual object. 
&lt;/p&gt;
&lt;p&gt;
    The long answer: There are many different types of proxies.
     Here you can find a good overview of all 
     &lt;a href=&quot;http://ocramius.github.io/presentations/proxy-pattern-in-php&quot; target=&quot;_blank&quot;&gt;proxy patterns&lt;/a&gt;
     in PHP.
&lt;/p&gt;
&lt;p&gt;
    In this specific case, a Virtual Proxy is the right proxy to use.
     It extends the actual base class and has exactly the same API.
     An over-simplified proxy of a Doctrine DocumentManager could look like this:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DocumentManagerProxy&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DocumentManager&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__construct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;DocumentManager&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$className&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$className&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;// ... All other methods of the DocumentManager ...&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    Because this kind of objects will result in a lot of effort in maintaining,
     it is better to use a library that automatically generates the proxy objects.
     One of those libraries is 
     &lt;a href=&quot;https://github.com/Ocramius/ProxyManager&quot; target=&quot;_blank&quot;&gt;ProxyManager&lt;/a&gt; by Ocramius.
&lt;/p&gt;

&lt;h1 id=&quot;putting-it-all-together&quot;&gt;Putting it all together&lt;/h1&gt;

&lt;h2 id=&quot;servicemanager-configuration&quot;&gt;ServiceManager configuration&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'factories'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;'documentmanager'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DoctrineMongoODMModule\Service\DocumentManagerFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'manager_key'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;'Application\DocumentManagerProxyDelegator'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Application\Factory\DocumentManagerProxyDelegatorFactory'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;'Application\DynamicDocumentManager'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Application\Factory\DynamicDocumentManagerFactory'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'delegators'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;'documentmanager'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'Application\DocumentManagerProxyDelegator'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;delegator&quot;&gt;Delegator&lt;/h2&gt;

&lt;p&gt;
    The delegator is responsible for initializing the actual DocumentManager and creating the proxy object.
     Another service is added that is responsible for maintaining and loading the different DocumentManagers.
     Make sure that the proxy initializer returns false, 
     so that the proxy is initialized with the current DocumentManager on every method call.
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ProxyManager\Factory\LazyLoadingValueHolderFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Zend\ServiceManager\DelegatorFactoryInterface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Zend\ServiceManager\ServiceLocatorInterface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DocumentManagerProxyDelegator&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DelegatorFactoryInterface&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/**
     * @var LazyLoadingValueHolderFactory
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$proxyFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/**
     * @var DynamicDocumentManager
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$dynamicDocumentManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/**
     * @param $dynamicDocumentManager
     * @param $proxyFactory
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__construct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$dynamicDocumentManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$proxyFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dynamicDocumentManager&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$dynamicDocumentManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proxyFactory&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$proxyFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/**
     * {@inheritdoc}
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createDelegatorWithName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ServiceLocatorInterface&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$serviceLocator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$requestedName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$dynamicDocumentManager&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dynamicDocumentManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$currentDocumentManager&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$dynamicDocumentManager&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setCurrentManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$currentDocumentManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$proxy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proxyFactory&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;createProxy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;'Doctrine\ODM\MongoDB\DocumentManager'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$wrappedObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$dynamicDocumentManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;$wrappedObject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$dynamicDocumentManager&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getCurrentManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$proxy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;delegator-factory&quot;&gt;Delegator Factory&lt;/h2&gt;
&lt;p&gt;
    The delegator factory creates an instance of the factory.
     For this example It is very straight forward.
     If you are planning to use it in production, 
     you might add some extra caching configuration to the proxy factory.
     This configuration can be based on
     `&lt;a href=&quot;https://github.com/zendframework/zf2/blob/master/library/Zend/ServiceManager/Proxy/LazyServiceFactoryFactory.php&quot; target=&quot;_blank&quot;&gt;Zend\ServiceManager\Proxy\LazyServiceFactoryFactory&lt;/a&gt;`. 
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Application\DocumentManagerProxyDelegator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ProxyManager\Factory\LazyLoadingValueHolderFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Zend\ServiceManager\FactoryInterface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Zend\ServiceManager\ServiceLocatorInterface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DocumentManagerProxyDelegatorFactory&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FactoryInterface&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ServiceLocatorInterface&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$serviceLocator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$dynamicDocumentManager&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$serviceLocator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'Application\DynamicDocumentManager'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$proxyFactory&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LazyLoadingValueHolderFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DocumentManagerProxyDelegator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$dynamicDocumentManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$proxyFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;dynamic-documentmanager&quot;&gt;Dynamic DocumentManager&lt;/h2&gt;
&lt;p&gt;
    The dynamic DocumentManager is responsible for loading and managing the DocumentManagers.
     While creating an instance for the DocumentManager, the real instance is injected in the DynamicDocumentManager.
     An implementation might look like this:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DynamicDocumentManagerInterface&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getCurrentManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setCurrentManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;DocumentManager&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$documentManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loadForTenant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Tenant&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$tenant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    The `setCurrentManager()` is called by the delegator to set the current manager.
&lt;/p&gt;
&lt;p&gt;
    The `getCurrentManager()` is called while initializing the proxy. 
     This way, the current manager will always be used when using the `documentmanager` in a shared service.
&lt;/p&gt;
&lt;p&gt;
    Before executing a command in the long-running process, the `loadForTenant()` method is being called.
     This method will close the old manager and reset the service manager keys for all Doctrine services.
     Finally it will recreate the `documentmanager`, which will trigger the `setCurrentManager()` method again.
&lt;/p&gt;

&lt;h1 id=&quot;final-thoughts&quot;&gt;Final thoughts&lt;/h1&gt;
&lt;p&gt;
    This technique might look a little bit `hacky`, 
     but is actually a very neat trick to make it easier to change instances on the fly.
&lt;/p&gt;
&lt;p&gt; 
    You don't have to mark all services that rely on the DocumentManager as unshared.
     In the codebase, you can still use the actual instance type in the annotations.
&lt;/p&gt;
&lt;p&gt;
     You might think of some other good use-cases to implement this powerful technique yourself.
&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Generating ZF2 template maps on the fly</title>
        <link href="http://veewee.github.io/blog/generating-zf2-template-maps-on-the-fly/"/>
        <updated>2014-08-19T00:00:00+02:00</updated>
        <id>http://veewee.github.io/blog/generating-zf2-template-maps-on-the-fly</id>
        <content type="html">&lt;p&gt;
    One of the performance boosters in
     &lt;a href=&quot;http://framework.zend.com/&quot; target=&quot;_blank&quot;&gt;Zend Framework 2&lt;/a&gt;
     is using `template_map` instead of the `template_path_stack` in the view manager.
     While developing, it is easier to use the stack.
     This is because you don't have to add a mapping every time you create a new view.
     At the end of the development you might forget to transform the stack into a template map.
     This is why it is useful to &lt;strong&gt;never&lt;/strong&gt; use the stack and automate the generation of the template_map array instead.
&lt;/p&gt;
&lt;p&gt;
    There is already a great tool called
     `&lt;a href=&quot;https://github.com/zendframework/zf2/blob/master/bin/templatemap_generator.php&quot; target=&quot;_blank&quot;&gt;templatemap_generator.php&lt;/a&gt;`
     included in the bin folder of zf2.
     It can be used to generate a template map for every module in your application.
     In the next step, we want to make sure that this tool is called every time a view file is created.
     This kind of automation can be done with a task manager like
     `&lt;a href=&quot;http://gruntjs.com/&quot; target=&quot;_blank&quot;&gt;Grunt&lt;/a&gt;`.
&lt;/p&gt;

&lt;h2 id=&quot;sample-configuration&quot;&gt;Sample configuration&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;initConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;

    &lt;span class=&quot;na&quot;&gt;phplint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;applicationViews&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;module/Application/**/*.phtml&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nl&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;applicationViews&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;module/Application/view/**/*.phtml&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;tasks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;phplint:applicationViews&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;exec:generate_application_template_map&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;

    &lt;span class=&quot;na&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;generate_application_template_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;../../vendor/bin/templatemap_generator.php&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;cwd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;module/Application&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;registerTask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;generate-template-maps&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;exec:template_map_application&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    By using this configuration, Grunt will watch for file changes in the `view` folder of the `Application` module.
     When a file has changed, PHPLint will check for syntax errors and finally a new template map file will be generated.
     There is also a command named `generate-template-maps` which you can run manually.
&lt;/p&gt;

&lt;p&gt;
    &lt;em&gt;
        &lt;strong&gt;Note:&lt;/strong&gt;
        Make sure to include the npm packages
        &lt;a href=&quot;https://www.npmjs.org/package/grunt-exec&quot; target=&quot;_blank&quot;&gt;grunt-exec&lt;/a&gt;
        and
        &lt;a href=&quot;https://npmjs.org/package/grunt-phplint&quot; target=&quot;_blank&quot;&gt;grunt-phplint&lt;/a&gt;.
    &lt;/em&gt;
&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;
    By automating all of the boring tasks, you can gain a lot of time during development.
     If you want to automate some more tasks during PHP development, you can check an earlier blog called
     `&lt;a href=&quot;http://veewee.github.io/blog/validating-your-php-code-on-the-fly/&quot;&gt;Validating your PHP code on the fly&lt;/a&gt;`.
&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Writing your first Grunt plugin</title>
        <link href="http://veewee.github.io/blog/writing-your-first-grunt-plugin/"/>
        <updated>2014-04-27T00:00:00+02:00</updated>
        <id>http://veewee.github.io/blog/writing-your-first-grunt-plugin</id>
        <content type="html">&lt;p&gt;For one of my projects, I needed a tool to list all used translations keys from a PHP project.
  Because I want to keep the translation database clean, I decided to create a
  &lt;a href=&quot;http://gruntjs.com/&quot; target=&quot;_blank&quot;&gt;Grunt&lt;/a&gt; plugin.
  There was one big problem: How do you create this plugin?
  So I started to read the documentation, some blog posts, etc. and noticed
  that the documentation was pretty confusing.
  Let me take you on a tour through my first plugin.&lt;/p&gt;

&lt;h2 id=&quot;where-to-start&quot;&gt;Where to start?&lt;/h2&gt;

&lt;h3 id=&quot;create-the-plugin-skeleton&quot;&gt;Create the plugin skeleton&lt;/h3&gt;
&lt;p&gt;The Grunt team has created a tool called &lt;a href=&quot;http://gruntjs.com/project-scaffolding&quot; target=&quot;_blank&quot;&gt;grunt-init&lt;/a&gt;.
  It’s purpose is to quickly scaffold your project with some basic templates.
  The tool does not include any templates, so you have to download them manually.
  There is a tempalte for creating a
  &lt;a href=&quot;https://github.com/gruntjs/grunt-init-gruntplugin&quot; target=&quot;_blank&quot;&gt;grunt-plugin&lt;/a&gt;
  and another one to add a
  &lt;a href=&quot;https://github.com/gruntjs/grunt-init-gruntfile&quot; target=&quot;_blank&quot;&gt;Gruntfile&lt;/a&gt;
  to your project.
  When you run the tool, a wizard is launched to personalize the template.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt-init gruntplugin&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;After running this command, all the template files are being copied to your folder.
  The structure is pretty straight forward.
  There is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tasks&lt;/code&gt; folder which contains the Grunt tasks.
  Another folder is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test&lt;/code&gt; folder. This is the place where you write some node tests for your plugin.
  Finally, there is also a Gruntfile which will help you with some basic tasks like testing the plugin.&lt;/p&gt;

&lt;h3 id=&quot;configure-npm&quot;&gt;Configure NPM&lt;/h3&gt;
&lt;p&gt;Once you got through the installation wizard, you should personalize the NPM file.
  My plugin is project specific, so I decided to make it a private repository.
  I also like using
  &lt;a href=&quot;http://lodash.com/&quot; target=&quot;_blank&quot;&gt;Lo-Dash&lt;/a&gt;
  for handling arrays, so I added this one as a dependency of the plugin.
  All these parameters can be configured in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; file.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;lodash&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;~2.4.1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;When the configuration is saved, the next step is to install the dependencies.
  This can be done by running the command:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;writing-the-task&quot;&gt;Writing the task&lt;/h2&gt;

&lt;h3 id=&quot;task-structure&quot;&gt;Task structure&lt;/h3&gt;
&lt;p&gt;You can add one or more tasks to your plugin. By default there is one
  &lt;a href=&quot;http://gruntjs.com/creating-tasks#multi-tasks&quot; target=&quot;_blank&quot;&gt;multi-task&lt;/a&gt;
  in the tasks folder.
  It looks like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;use strict&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;registerMultiTask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;findTranslations&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Find all translations in your project.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// The task code comes here&lt;/span&gt;

  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;initialize-dependencies&quot;&gt;Initialize dependencies&lt;/h3&gt;
&lt;p&gt;Grunt has some standard tools to handle
  &lt;a href=&quot;http://gruntjs.com/api/grunt.file&quot; target=&quot;_blank&quot;&gt;file&lt;/a&gt; actions and
  &lt;a href=&quot;http://gruntjs.com/api/grunt.log&quot; target=&quot;_blank&quot;&gt;logging&lt;/a&gt;.
  When you want to use custom libraries, you can include them through
  &lt;a href=&quot;http://requirejs.org/&quot; target=&quot;_blank&quot;&gt;require&lt;/a&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;lodash&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;options&quot;&gt;Options&lt;/h3&gt;
&lt;p&gt;If you ever worked with Grunt before, you know that all commands are configurable.
  Some of the options will have a default value.
  In the plugin, you can add custom &lt;a href=&quot;http://gruntjs.com/api/grunt.option&quot;&gt;options&lt;/a&gt; as followed:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The options in the object are the default options and can be overwritten in the Gruntfile.&lt;/p&gt;

&lt;h3 id=&quot;files&quot;&gt;Files&lt;/h3&gt;
&lt;p&gt;Next to the options, there is a basic configuration parameter to specify source and destinations files.
The configuration looks like:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;  &lt;span class=&quot;nx&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;test/fixtures/php-controller-plugin&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;tmp/translations-json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As you can see, it is possible to add multiple src / dest collections.
  The source can consist out of multiple files and the names can contain regular expressions like wildcards.
  In the plugin, it is very easy to loop through the files:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;translations&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filePath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filePath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Todo: Find translation keys&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

      &lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;translations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;locating-translation-keys&quot;&gt;Locating translation keys&lt;/h3&gt;
&lt;p&gt;To find the translation keys in a file, I needed to write some regular expressions to find the key.
  Luckily for me, I use a very basic translation method.
  In my project I have 2 different ways of retrieving translations: one for the controller and one for the view.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;translationKeyRegex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;s]?.*[&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;]{1}([a-z0-9&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;_]*)[&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;]{1}[&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;s]?.*&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;regexs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;phpControllerPlugin&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;translator-&amp;gt;get&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;translationKeyRegex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;phpViewHelper&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;_t-&amp;gt;get&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;translationKeyRegex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This may look a bit hard at first, but it is actually very easy. There are only 2 patterns:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;In the controller: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$translator-&amp;gt;get('KEY_123');&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;In the view: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_t-&amp;gt;get('KEY_123');&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After the regular expressions were written, I created a function that returns the translation keys:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;findTranslationKeys&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;regex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;found&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;regex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;found&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;found&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Okay, the hard part of the plugin is written.
  Now the only thing left is adding this functionality to the part where we read the file.
  I want to execute all regular expressions patterns on every file.
  The resulting array should only contain unique entries.
  This can easily be done with the Lo-Dash forEach and union method:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;found&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;regex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;regexs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;regex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;RegExp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;gi&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;found&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;findTranslationKeys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;regex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Only use unique translation keys:&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;translations&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;union&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;translations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;found&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;formatting-the-output&quot;&gt;Formatting the output&lt;/h3&gt;
&lt;p&gt;As you can see in the files part, at the moment we only output the result as newline-separated text.
  Because I want to clean up my database through PHP, I decided to make JSON the default format.
  To specify which format will be used I added one other function:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formatTranslations&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;translations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formatted&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;newlines&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;formatted&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;translations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;formatted&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;translations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;formatted&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Invalid export format&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formatted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The translations parameter is the array of found translation keys and the format is configured in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;options.format&lt;/code&gt; variable.&lt;/p&gt;

&lt;h3 id=&quot;logging&quot;&gt;Logging&lt;/h3&gt;
&lt;p&gt;At the end of the command, I find it useful to log the results of the task.
 In this case, I only print an indication of the amount of found items.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;    &lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;writeln&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Saved &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;translations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; translation keys to file &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;testing&quot;&gt;Testing&lt;/h2&gt;
&lt;p&gt;For now, I only talked about writing the plugin.
  Of course it is also recommended to write some test for your plugin.
  As far as I can see in other plugins, there are only functional tests.
  In the test directory there are 2 folders.
  The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fixtures&lt;/code&gt; folder is where you add the files where you want to find translation keys in.
  In the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;expected&lt;/code&gt; folder you place the output file that you expect the plugin to generate.&lt;/p&gt;

&lt;p&gt;Now the first thing that you need to do, is to configure your task in the Gruntfile.
  When you run the test command, your configured tasks will run first.
  So in the tasks you can configure to run the tasks with the fixtures file and save it in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmp&lt;/code&gt; folder.
  When you know which files are being read and written, it is easy to create your test:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;  &lt;span class=&quot;nx&quot;&gt;json_format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actual&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;tmp/translations-json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;expected&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;test/expected/json_format&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;actual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;should return translations in json.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now the only command you need to run to test your code is:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;deployment&quot;&gt;Deployment&lt;/h2&gt;
&lt;p&gt;Once your plugin is ready, you want to place it in GIT.
  Because this is a private repository, I placed it on a private repository on BitBucket.
  Now the next problem arose: How can I load my custom plugin through NPM in another project?
  In the latest versions of NPM, it is possible to add packages that are not managed on NPM.
  The real problem is that it is a private repository.
  After some searching, I found out that the only good way the require the package is to use the SSH url of the package.
  This is what I placed in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; file of the main project.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;devDependencies&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;grunt-find-translations&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;git+ssh://git@bitbucket.org:organization/package.git&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Don’t forget to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm install&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In the Gruntfile of the project, I configured the task to search for translations in all .php and .phtml files.
  The result of the tasks will be saved in the logs folder.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;    &lt;span class=&quot;nx&quot;&gt;findTranslations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;json_format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
              &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;{,*/}*.php&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;{,*/}*.phtml&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;logs/translation-keys.json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Finally my task was ready to use in my project:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt findTranslations

&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; Running &lt;span class=&quot;s2&quot;&gt;&quot;findTranslations:json_format&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;findTranslations&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; task
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; Saved 250 translation keys to file logs/translation-keys.json&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</content>
    </entry>
    
    <entry>
        <title>Three-way data binding in AngularJS</title>
        <link href="http://veewee.github.io/blog/three-way-data-binding/"/>
        <updated>2014-04-06T00:00:00+02:00</updated>
        <id>http://veewee.github.io/blog/three-way-data-binding</id>
        <content type="html">&lt;p&gt;One of the cool features in &lt;a href=&quot;http://angularjs.org/&quot; target=&quot;_blank&quot;&gt;AngularJS&lt;/a&gt; is the two-way data binding.
 When you change a property of an object, the value is instantly changed in every view or service that is using this property.
 A while ago, I saw a video about the combination of AngularJS and
 &lt;a href=&quot;https://www.firebase.com/&quot; target=&quot;_blank&quot;&gt;Firebase&lt;/a&gt;.
 This combination makes it possible to create three-way data binding in AngularJS.&lt;/p&gt;

&lt;h2 id=&quot;what-is-firebase&quot;&gt;What is Firebase?&lt;/h2&gt;
&lt;p&gt;Firebase is an online service that provides an API to store and sync data in realtime.
 This means that when the data is saved, all connected clients will retrieve the latest data without reloading the page.
 You can see Firebase as a database service with some extra features like authentication.
 The cool thing about this service is that you don’t need to create a database schema.
 You can create collections just by specifying a path to the database in the URL.
 An additional package ‘&lt;a href=&quot;https://www.firebase.com/quickstart/angularjs.html&quot; target=&quot;_blank&quot;&gt;AngularFire&lt;/a&gt;’ is available for integration with AngularJS.&lt;/p&gt;

&lt;h2 id=&quot;the-worlds-easiest-guestbook&quot;&gt;The world’s easiest guestbook&lt;/h2&gt;

&lt;h3 id=&quot;getting-started&quot;&gt;Getting started&lt;/h3&gt;
&lt;p&gt;A good way to start a test project is by using &lt;a href=&quot;http://yeoman.io/&quot; target=&quot;_blank&quot;&gt;Yeoman&lt;/a&gt;.
 Both AngularJs and AngularFire have a generator that will create your basic application in no time.
 Just run following commands and follow the wizard:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;yo angular
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;yo angularfire
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt serve&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;the-view&quot;&gt;The view&lt;/h3&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;jumbotron&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;'Allo, 'Allo!&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;lead&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    Please leave a message if your like my page!
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;form-group&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ng-model=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;input.name&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;placeholder=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Name&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;form-control&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;form-group&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;textarea&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ng-model=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;input.message&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;form-control&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;placeholder=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Message&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/textarea&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;btn btn-lg btn-success&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;data-ng-click=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;addMessage()&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Splendid!&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;messages&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ng-cloack=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;message&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;message-{{ message.$id }}&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ng-repeat=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;message in messages | orderByPriority | reverse&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ message.name }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;content&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
            {{ message.message }}
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;initializing-your-firebase-collection&quot;&gt;Initializing your firebase collection&lt;/h3&gt;
&lt;p&gt;The AngularFire package provides some ways to interact with Firebase.
 The easiest way to connecto to a collection is by using the syncData service.
 We can create the connection with one line of code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;angular&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;MainCtrl&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;syncData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;$scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;messages&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;syncData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;messages&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;add-a-message&quot;&gt;Add a message&lt;/h3&gt;
&lt;p&gt;Now that we set up the connection, we want to add messages to the collection.
 This part is very easy: you just pass a JSON object to the collection:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;$scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;''&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;$scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addMessage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;$scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;messages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;$scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;sort-messages-in-reverse-order&quot;&gt;Sort messages in reverse order&lt;/h3&gt;
&lt;p&gt;When you want to display the messages in reverse order you should create one extra filer called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reverse&lt;/code&gt;.
 This filter is allready written in one of the example AngularFire projects.
 &lt;a href=&quot;https://github.com/firebase/angularFire-seed/blob/master/app/js/filters.js&quot; target=&quot;_blank&quot;&gt;You can find the code over here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A quick way to create a custom filter is by using the Yeoman angular:filter generator:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;yo angular:filter reverse&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;hosting&quot;&gt;Hosting&lt;/h3&gt;
&lt;p&gt;It is also possible to use Firebase hosting.
 A custom CLI tool is provided an can be installed through NPM:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; firebase-tools&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The next step is to create a firebase configuration file. This can be done with the command:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;firebase init&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;em&gt;Note: The destination folder should be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dist&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The next step is to deploy the application. This is also very easy:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt build
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;firebase deploy&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The sample application is now available at: &lt;a href=&quot;https://veewee.firebaseapp.com/&quot; target=&quot;_blank&quot;&gt;Firebase App&lt;/a&gt;.&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>PHPBenelux 2014</title>
        <link href="http://veewee.github.io/blog/php-benelux-2014/"/>
        <updated>2014-01-27T00:00:00+01:00</updated>
        <id>http://veewee.github.io/blog/php-benelux-2014</id>
        <content type="html">&lt;p&gt;
    Last weekend, the annual &lt;a href=&quot;http://conference.phpbenelux.eu/2014/&quot; target=&quot;_blank&quot;&gt;PHPBenlux&lt;/a&gt; conference took place.
    With a small delegation of the &lt;a href=&quot;http://www.phpro.be/&quot; target=&quot;_blank&quot;&gt;Phpro&lt;/a&gt; crew,
    I went to Kontich for 2 days filled with talks, discussions and pleasure.
    In this article you can find a small summary of the talks that inspired me.
&lt;/p&gt;

&lt;h2 id=&quot;day-1&quot;&gt;Day 1:&lt;/h2&gt;

&lt;h3 id=&quot;keynote-mentoring-developers&quot;&gt;Keynote: Mentoring developers&lt;/h3&gt;
&lt;p&gt;
    It won't be a surprise if I told you that the conference opened with a motivational keynote.
    &lt;a href=&quot;http://emsmith.net/&quot; target=&quot;_blank&quot;&gt;Elizabeth Marie Smith&lt;/a&gt; took us back to her childhood and told
    us why and how she started with programming.
    It reminded me of the time when I wrote my first super flashy website and of my first steps in PHP development.
    When you start learning something new, you NEED somebody to look up to. This will help you grow so much faster.
    In a next stadium it is your turn to give something back. Help the people around you that need your help, but DON'T
    spoon-feed the n00b.
&lt;/p&gt;

&lt;h3 id=&quot;what-hackers-do-once-they-get-passed-your-code&quot;&gt;What hackers do once they get passed your code&lt;/h3&gt;
&lt;p&gt;
    In this first session, &lt;a href=&quot;http://mattiasgeniar.be/&quot; target=&quot;_blank&quot;&gt;Mattias Geniar&lt;/a&gt; showed us what hackers can do once they get passed your code.
    A presentation filled with clear examples on how hackers will try to gain and remain access to your server.
    Most of the time, hackers will use automated tools to find a weak point in your code.
    Once they have found this weak spot, they will try to compromise your website.
    This can be done by injecting obfuscated 'eval' scripts into your website.
    Or worse: Injecting a complete &lt;a href=&quot;http://en.wikipedia.org/wiki/Backdoor_Shell&quot; target=&quot;_blank&quot;&gt;backdoor shell&lt;/a&gt;
    on which hackers can fully control your hosting environment.
&lt;/p&gt;

&lt;h3 id=&quot;refactoring-to-design-patters&quot;&gt;Refactoring to Design Patters&lt;/h3&gt;
&lt;p&gt;
    In this talk, &lt;a href=&quot;http://www.whitewashing.de/&quot; target=&quot;_blank&quot;&gt;Benjamin Eberlei&lt;/a&gt;
    gave us a hands-on demo on refactoring.
    One of his first quotes was an unquestionable statement:
    &lt;em&gt;&quot;Neglecting Object-Oriented design leads to under-engineering,
    but focusing soley on Design-Pattern leads to over-engineering&quot;&lt;/em&gt;.
    Next he started with his demo, in which he made small changes to a legacy controller.
    By making these small changes, it was very clear were the
    &lt;a href=&quot;http://en.wikipedia.org/wiki/Factory_pattern&quot; target=&quot;_blank&quot;&gt;Factory&lt;/a&gt;,
    &lt;a href=&quot;http://en.wikipedia.org/wiki/Facade_pattern&quot; target=&quot;_blank&quot;&gt;Facade&lt;/a&gt; and
    &lt;a href=&quot;http://en.wikipedia.org/wiki/Strategy_pattern&quot; target=&quot;_blank&quot;&gt;Strategy&lt;/a&gt;
    patterns were needed.
    Some tips to keep in mind:
    &lt;ul&gt;
        &lt;li&gt;Get in control on how objects are created and centralize object creation.&lt;/li&gt;
        &lt;li&gt;Refactor step by step, otherwise you will be debugging all the time.&lt;/li&gt;
    &lt;/ul&gt;
&lt;/p&gt;

&lt;h3 id=&quot;php-performance-under-the-hood&quot;&gt;PHP Performance Under the hood&lt;/h3&gt;
&lt;p&gt;
    The last talk of the day was brought to us by &lt;a href=&quot;http://daveyshafik.com/&quot; target=&quot;_blank&quot;&gt;Davey Shafik&lt;/a&gt;.
    It was a rather heavy subject to close the day with, but it gave a good oversight of what happens in PHP internally.
    Nice to see how the PHP code gets tokenized, transformed into opcodes which are interpreted into memory.
    What I wrote down for my day to day tasks is to make sure
    &lt;a href=&quot;http://be2.php.net/opcache&quot; target=&quot;_blank&quot;&gt;Zend OPcache&lt;/a&gt;
    is enabled on production environments.
&lt;/p&gt;

&lt;h2 id=&quot;day-2&quot;&gt;Day 2:&lt;/h2&gt;

&lt;h3 id=&quot;models-and-service-layers-hemoglobin-and-hobgoblins&quot;&gt;Models and Service Layers; Hemoglobin and Hobgoblins&lt;/h3&gt;
&lt;p&gt;
    It was still early in the morning and apparently nobody had it's first coffee yet.
    Anyway, the first talk of the day, with a rather strange title, was given to us by a rather strange headed guy named
    &lt;a href=&quot;http://rosstuck.com/&quot; target=&quot;_blank&quot;&gt;Ross Tuck&lt;/a&gt;.
    He prepared some great slides for us, in which he warned us that he had an average of 1 slide per 14 seconds.
    The talk itself turned out to be about Domain Design Patterns.
    By showing some easy examples, he explained why you should be using fat model / skinny services,
    &lt;a href=&quot;http://martinfowler.com/bliki/CQRS.html&quot; target=&quot;_blank&quot;&gt;CQRS&lt;/a&gt; and
    &lt;a href=&quot;http://martinfowler.com/eaaDev/EventSourcing.html&quot; target=&quot;_blank&quot;&gt;Event Sourcing&lt;/a&gt;.
    This was a very enlightening talk for the project I am currently working on.
&lt;/p&gt;

&lt;h3 id=&quot;moving-away-from-legacy-code-with-bdd&quot;&gt;Moving Away from Legacy code with BDD&lt;/h3&gt;
&lt;p&gt;
    This was one of the talks I really looked forward to, given by
    &lt;a href=&quot;http://everzet.com/&quot; target=&quot;_blank&quot;&gt;Konstantin Kudryashov&lt;/a&gt; (aka everzet).
    As a BDD evangelist, he explained why it is better to promise less features, but more business value to a customer.
    This can be done with a BDD-Pipeline in which we handle some stages before starting refactoring the code:
    &lt;ul&gt;
        &lt;li&gt;&lt;a href=&quot;http://impactmapping.org/&quot; target=&quot;_blank&quot;&gt;Impact Mapping&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;Feature mapping&lt;/li&gt;
        &lt;li&gt;Order the tasks by role and benefit&lt;/li&gt;
        &lt;li&gt;Describe features into example scenarios&lt;/li&gt;
        &lt;li&gt;Describe, Implement, Design&lt;/li&gt;
    &lt;/ul&gt;
    The last 2 steps is where
    &lt;a href=&quot;http://behat.org/&quot; target=&quot;_blank&quot;&gt;Behat&lt;/a&gt; and
    &lt;a href=&quot;http://www.phpspec.net/&quot; target=&quot;_blank&quot;&gt;Phpspec&lt;/a&gt; come into play.
    Some really nice testing tools, to describe and validate how your application and models should behave.
&lt;/p&gt;

&lt;h3 id=&quot;maximising-performance-in-zf2&quot;&gt;Maximising Performance in ZF2&lt;/h3&gt;
&lt;p&gt;
    Another talk on my TODO list was this one, brought to us by
    &lt;a href=&quot;http://blog.hock.in/&quot; target=&quot;_blank&quot;&gt;Gary Hockin&lt;/a&gt;.
    In the first part he told us how he benchmarks and profiles his ZF2 applications.
    This was mainly with the tools
    &lt;a href=&quot;http://www.joedog.org/siege-home/&quot; target=&quot;_blank&quot;&gt;Siege&lt;/a&gt; and
    &lt;a href=&quot;http://xdebug.org/&quot; target=&quot;_blank&quot;&gt;Xdebug&lt;/a&gt;.
    Next he gave us some very helpful tips on how to increase performance in ZF2:
    &lt;ul&gt;
        &lt;li&gt;Use &lt;a href=&quot;https://github.com/EvanDotPro/EdpSuperluminal&quot; target=&quot;_blank&quot;&gt;EdpSuperLuminal&lt;/a&gt; on production&lt;/li&gt;
        &lt;li&gt;Turn on Zend Opcode caching on production.&lt;/li&gt;
        &lt;li&gt;Do not place closures in config file, place them in the Module.php file.&lt;/li&gt;
        &lt;li&gt;
            Place popular routes in the and of your configuration.
            The router is a LIFO stack.
            Note: Take care of module order.
        &lt;/li&gt;
        &lt;li&gt;
            Use View template maps in production instead of the template_view_stack.
            This can be done with the default templatemap_generator.php, shipped with zend.
        &lt;/li&gt;
        &lt;li&gt;Minimize the use of the shared event manager.&lt;/li&gt;
        &lt;li&gt;Cache big datasets.&lt;/li&gt;
        &lt;li&gt;Add default files like favicon.ico, robots.txt, ... to make sure ZF2 does not get bootstrapped on request.&lt;/li&gt;
    &lt;/ul&gt;
&lt;/p&gt;

&lt;h3 id=&quot;uncon-feature-branches--prs&quot;&gt;Uncon: Feature branches &amp;amp; PR’s&lt;/h3&gt;
&lt;p&gt;
    This year, there was also an Uncon going on at PHPBenelux. The first session I followed, was a small talk about
    &lt;a href=&quot;https://github.com/pascaldevink/phlybox&quot; target=&quot;_blank&quot;&gt;PhlyBox&lt;/a&gt; by
    &lt;a href=&quot;http://privatevoid.nl/&quot; target=&quot;_blank&quot;&gt;Pascal de Vink&lt;/a&gt;.
    At this moment, the tool doesn't do much. It is just a PoC for something that might become powerfull.
    It is designed to make it easier to deploy feature branches to a specific environment.
    I have thought about the concept myself, but don't think this is the way to go.
    Basically, the tool spawns new vagrant boxes with a custom branch as source.
    I think it would be easier to use a tool like
    &lt;a href=&quot;https://npmjs.org/package/grunt-git&quot;&gt;grunt-git&lt;/a&gt;
    to clone a branch to a specific directory and create a new VirtualHost that will redirect to the branch.
    Then the only thing that remains a problem, is running database migrations.
    So, I guess there is still a lot of stuff to think through.
&lt;/p&gt;

&lt;h3 id=&quot;uncon-queue-your-work-about-job-queues-and-abstraction-layers&quot;&gt;Uncon: Queue your work; about job queues and abstraction layers&lt;/h3&gt;
&lt;p&gt;
    The next part of the Uncon was a talk about Queueing and Messaging systems in PHP, brought to us by
    &lt;a href=&quot;https://juriansluiman.nl/&quot; target=&quot;_blank&quot;&gt;Jurian Sluiman&lt;/a&gt;.
    All the actions that users don't need to be aware of, should be done asynchronous.
    This way, you can deliver the content to the user in no time and let the
    server do the other jobs when there are resources to do the task.
    A good way to do this kind of asynchronous data handling, is by using queue deamons like
    &lt;a href=&quot;http://gearman.org/&quot; target=&quot;_blank&quot;&gt;Gearman&lt;/a&gt; or
    &lt;a href=&quot;http://kr.github.io/beanstalkd/&quot;&gt;Beanstalkd&lt;/a&gt;.
    A Job Server will remember what tasks that need to be done and a Job Worker will
    handle the actions and give a response to the Task Server.
    When you need more control over the Messaging, you can use a Messaging Queues like
    &lt;a href=&quot;http://zeromq.org/&quot; target=&quot;_blank&quot;&gt;ZeroMQ&lt;/a&gt; or
    &lt;a href=&quot;http://www.rabbitmq.com/&quot; target=&quot;_blank&quot;&gt;RabbitMQ&lt;/a&gt;.
    This was a really interesting topic.
    I can't wait to add this asynchronous queues into a next project.
&lt;/p&gt;

&lt;h3 id=&quot;extract-till-you-drop&quot;&gt;Extract Till You Drop&lt;/h3&gt;
&lt;p&gt;
    The last talk was about extracting legacy code.
    &lt;a href=&quot;http://verraes.net/&quot; target=&quot;_blank&quot;&gt;Mathias Verraes&lt;/a&gt;
    gave us a live demo, a bit similar to the talk of Benjamin Eberlei.
    It was great to watch how Mathias used all the build-in
    &lt;a href=&quot;http://www.jetbrains.com/phpstorm/&quot; target=&quot;_blank&quot;&gt;PhpStorm&lt;/a&gt;
    refactoring macro's.
    He also had a very interesting way in naming stuff. Exactly what you would expect from a DDD evangelist!
    The tests ran in PHPUnit, but had a BDD like structure. It looked like a mixture of PhpUnit, PhpSpec And Behat.
&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;
    PHPBenlux was, again, a great conference.
    It's amazing to see how the sessions and socials improve every year.
    To all the organizers: keep up the good work!
    I hope to be there again next year.
&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Validating your PHP code on the fly</title>
        <link href="http://veewee.github.io/blog/validating-your-php-code-on-the-fly/"/>
        <updated>2014-01-21T00:00:00+01:00</updated>
        <id>http://veewee.github.io/blog/validating-your-php-code-on-the-fly</id>
        <content type="html">&lt;p&gt;
    It's amazing how much time you can loose while running PHP tests.
    First you alter your code or test. Next you start your test and wait for it to finish.
    Finally you find out you messed up and start the process all over again.
    In this article I am going to show you how to automate PHP testing,
    so you can focus on adding business value to your application.
&lt;/p&gt;
&lt;p&gt;
    For this article I created a simple
    &lt;a href=&quot;http://framework.zend.com/&quot; target=&quot;_blank&quot;&gt;Zend Framework 2&lt;/a&gt;
    application with
    &lt;a href=&quot;http://www.phpspec.net/&quot; target=&quot;_blank&quot;&gt;Phpspec&lt;/a&gt; tests.
    Even though this article focuses on these 2 packages,
    it is possible to create this kind of automation for every possible package.
&lt;/p&gt;

&lt;h2 id=&quot;application-structure&quot;&gt;Application structure&lt;/h2&gt;
&lt;p&gt;
    First, let's take a look at the directory structure.
    In the representation below, you can see a default ZF2 skeleton.
    The root folder contains the directories config, module, public and vendor.
    The `config` folder provides the application configuration.
    In the `module` folder you can see 2 modules that should be tested: Export and Import.
    Next you can find the public directory which will bootstrap the application.
    And finally there is the vendor folder that will be filled with dependencies by
    &lt;a href=&quot;https://getcomposer.org/&quot; target=&quot;_blank&quot;&gt;Composer&lt;/a&gt;.
&lt;/p&gt;
&lt;pre&gt;
.
|-- config
|   |-- application.config.php
|-- module
|   |-- Export
|   |   |-- config
|   |   |-- spec
|   |   |-- src
|   |   |  `-- Export
|   |   |       |-- Service
|   |   |       `-- Module.php
|   |   |-- view
|   |   `-- Module.php
|   `-- Import
|       |-- config
|       |-- spec
|       |-- src
|       |  `-- Import
|       |       |-- Service
|       |       `-- Module.php
|       |-- view
|       `-- Module.php
|-- public
|-- vendor
&lt;/pre&gt;

&lt;h2 id=&quot;configuring-composer&quot;&gt;Configuring composer&lt;/h2&gt;
&lt;p&gt;
    Because nobody wants to download all the dependencies manually, we will be using composer to get the required packages.
    We also want to configure composer to automatically load our custom modules: Export and Import.
    This way, no additional autoloading is required and Phpspec will be able to find all classes by itself.
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;composer.json&lt;/strong&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;veewee/validating-on-the-fly&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;zendframework/zendframework&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;2.*&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;require-dev&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;phpspec/phpspec&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;dev-master&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;fabpot/PHP-CS-Fixer&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;minimum-stability&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;dev&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;prefer-stable&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;autoload&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;psr-0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Export&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;module/Export/src/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Import&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;module/Import/src/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    As you can see, composer will download Zend Framework 2 to the vendor directory.
    When you add the option `--dev` during the installation, Phpspec and PHP-CS-Fixer will also be downloaded.
    The last part of this configuration file will provide autoloading for the custom Export and Import module.
    To download and install all the dependencies, one command is being used:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;composer &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--dev&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--prefer-dist&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;configuring-phpspec&quot;&gt;Configuring phpspec&lt;/h2&gt;
&lt;p&gt;
    As you can see in the directory overview, there is already a spec folder available.
    The Phpspec tests will be placed in this directory.
    This way, every module has it's own scope and can be tested separately.
&lt;/p&gt;
&lt;p&gt;
    Now the tricky part: let's tell Phpspec where to find the custom source and spec files.
    Because we need to test multiple modules on multiple locations, we need to add multiple test suites to Phpspec.
    This is done by creating a phpspec.yml file in the root folder of the application.
    A test suite describes where the source and spec files of a custom namespace are located.
    Let's take a look at the configuration file for our application:
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;phpspec.yml&lt;/strong&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;na&quot;&gt;formatter.name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dot&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;suites&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;Export&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Export&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;src_path&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;module/Export/src/'&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;spec_path&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;module/Export/'&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;Import&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Import&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;src_path&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;module/Import/src/'&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;spec_path&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;module/Import/'&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    One of the downsides of Phpspec is that, at the moment, you can not run suites based on suite name.
    To test this configuration, you can run following commands:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./vendor/bin/phpspec run module/Export/src
~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./vendor/bin/phpspec run module/Import/src&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;configuring-php-cs-fixer&quot;&gt;Configuring php-cs-fixer&lt;/h2&gt;
&lt;p&gt;
    Everybody wants clean, readable and maintainable code.
    That is why the code of the modules should be validated against the desired PHP standards.
    In this case, we want to check our classes against the
    &lt;a href=&quot;https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md&quot; target=&quot;_blank&quot;&gt;PSR2&lt;/a&gt;
    standard.
    Per module, you should add a file called .php_cs in the root directory of the module.
    In this file you can tell the
    &lt;a href=&quot;https://github.com/fabpot/PHP-CS-Fixer&quot; target=&quot;_blank&quot;&gt;Php-CS-Fixer&lt;/a&gt;
    which paths to check and add some default configuration settings.
&lt;/p&gt;
&lt;p&gt;
    &lt;strong&gt;.php_cs&lt;/strong&gt;
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$finder&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\CS\Finder\DefaultFinder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;exclude&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'language'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;exclude&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'view'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;exclude&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'config'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;__DIR__&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/src'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;__DIR__&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/spec'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\CS\Config\Config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fixers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Symfony\CS\FixerInterface&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PSR2_LEVEL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;finder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$finder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    To test this configuration, you can run following commands:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./vendor/bin/php-cs-fixer fix module/Export &lt;span class=&quot;nt&quot;&gt;--dry-run&lt;/span&gt;
~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./vendor/bin/php-cs-fixer fix module/Import &lt;span class=&quot;nt&quot;&gt;--dry-run&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;automate-the-testing-process&quot;&gt;Automate the testing process&lt;/h2&gt;
&lt;p&gt;
    Before the automation, every time you change a file in your module,
    you need to run Phpspec and occasionally the Php-CS-Fixer to validate your code.
    Because you have to define which module to check every time you run the command,
    you will spend some time searching for the right command in your console.
    A better way is to automate this process, so that a file change will trigger the command to test your code.
    This will save you some time and will give you an indication of when and where you messed up.
    What was that tool again to automate tasks? Exactly:
    &lt;a href=&quot;http://gruntjs.com/&quot; target=&quot;_blank&quot;&gt;Grunt&lt;/a&gt;!
&lt;/p&gt;
&lt;p&gt;
    There are some grunt plugins that can be used to automate PHP validation.
    In this article we are using
    &lt;a href=&quot;https://npmjs.org/package/grunt-phpspec&quot; target=&quot;_blank&quot;&gt;Phpspec&lt;/a&gt;,
    but there are also plugins for other testing libraries like
    &lt;a href=&quot;https://npmjs.org/package/grunt-phpunit&quot; target=&quot;_blank&quot;&gt;Phpunit&lt;/a&gt;
    and
    &lt;a href=&quot;https://npmjs.org/package/grunt-parallel-behat&quot; target=&quot;_blank&quot;&gt;Behat&lt;/a&gt;.
    In the next part, I will tell you how to test your code on syntax errors,
    coding standard errors and bad functionality.
&lt;/p&gt;

&lt;h3 id=&quot;grunt-phpspec&quot;&gt;Grunt-Phpspec&lt;/h3&gt;
&lt;p&gt;
    For validating bad functionality we use
    &lt;a href=&quot;https://npmjs.org/package/grunt-phpspec&quot;&gt;grunt-phpspec&lt;/a&gt;.
    This tool will run Phpspec on our custom modules.
    For every PHP module we need to check, an entry in the configuration is required.
    Here is the sample configuration for the current project:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;phpspec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./vendor/bin/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;specs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;module/Export/src&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;specs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;module/Import/src&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    To run spec tests, you can use following commands:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt phpspec
~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt phpspec:export
~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt phpspec:import&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;grunt-php-cs-fixer&quot;&gt;Grunt-php-cs-fixer&lt;/h3&gt;
&lt;p&gt;
    The tool for validating PHP coding standards is
    &lt;a href=&quot;https://npmjs.org/package/grunt-php-cs-fixer&quot; target=&quot;_blank&quot;&gt;grunt-php-cs-fixer&lt;/a&gt;.
    As the name suggests: it does not only check for issues, it also fixes them.
    Therefore it must be possible to validate and fix errors with Grunt.
    This can be done by adding the parameter `--fixcs`.
    Here is the sample configuration for the current project:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Place this parameter before grunt.initConfig() method:&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fixCs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;option&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;fixcs&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Place this configuration in grunt.initConfig() method:&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;phpcsfixer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;bin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;vendor/bin/php-cs-fixer&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;verbose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;dryRun&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fixCs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ignoreExitCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fixCs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;psr2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;standard&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Zend&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;module/Export&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;module/Import&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    To run the cs fixer, you can use following commands:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;c&quot;&gt;# Validating:&lt;/span&gt;
~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt phpcsfixer
~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt phpcsfixer:export
~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt phpcsfixer:import

&lt;span class=&quot;c&quot;&gt;# Fixing:&lt;/span&gt;
~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt phpcsfixer &lt;span class=&quot;nt&quot;&gt;--fixcs&lt;/span&gt;
~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt phpcsfixer:export &lt;span class=&quot;nt&quot;&gt;--fixcs&lt;/span&gt;
~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt phpcsfixer:import &lt;span class=&quot;nt&quot;&gt;--fixcs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;grunt-phplint&quot;&gt;Grunt-Phplint&lt;/h3&gt;
&lt;p&gt;
    To validate PHP files for syntax errors you can use the commnd `php -l`.
    For automation, there is also a Grunt plugin available named
    &lt;a href=&quot;https://npmjs.org/package/grunt-phplint&quot; target=&quot;_blank&quot;&gt;grunt-phplint&lt;/a&gt;.
    This tool is added to the test suite
    to make sure the CS-fixer and spec tests only run when there is no syntax error.
    Here is the sample configuration for the current project:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;phplint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;module/Export/**/*.php&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;module/Import/**/*.php&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    To run PHP lint, you can use following commands:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt phplint
~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt phplint:export
~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt phplint:import&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;grunt-watch&quot;&gt;Grunt-watch&lt;/h3&gt;
&lt;p&gt;
    Now that we configured all tasks to validate the PHP code,
    we want the tests to run every time we change a class or spec test in our module.
    This is where
    &lt;a href=&quot;https://github.com/gruntjs/grunt-contrib-watch&quot; target=&quot;_blank&quot;&gt;grunt-contrib-watch&lt;/a&gt;
    comes in to play.
    This task will listen for file changes and will configured tasks for these files.
    When one of the tasks fail, the other tasks will not run.
    This is why I decided to run the tests in the order: lint, csfixer, phpspec.
    Here is the sample configuration for the current project:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;module/Export/**/*.php&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;tasks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;phplint:export&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;phpcsfixer:export&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;phpspec:export&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;module/Import/**/*.php&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;tasks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;phplint:import&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;phpcsfixer:import&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;phpspec:import&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    To start the watcher and automate the tests, you only have to use one command:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt watch&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;run-all-tests-in-one&quot;&gt;Run all tests in one&lt;/h3&gt;
&lt;p&gt;
    For Continious Integration it would be nice if all tests could be run in one command.
    Well off course this is possible! It is just one line of configuration:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;registerTask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;phplint&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;phpcsfixer&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;phpspec&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    To start the complete test, you can use following command:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;
    As you can see there are some tools to configure.
    Once the tools are configured, this set-up will save you some valuable time while testing your code.
    I highly recommend you to use a similar set-up because it is very easy to use yet very powerful.
    You won't regret!
&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>Grand Opening!</title>
        <link href="http://veewee.github.io/blog/grand-opening/"/>
        <updated>2014-01-14T00:00:00+01:00</updated>
        <id>http://veewee.github.io/blog/grand-opening</id>
        <content type="html">&lt;p&gt;
    With a new year, come some new resolutions. I was already thinking of creating a blog for quite some time,
    but the new year forced me to finally get this site up and running. So why did I start this blog?
    Not to tell you who I am, but to inform you about some cool stuff I encounter during the development of web applications.
&lt;/p&gt;
&lt;p&gt;
    Just another blog you think? Ok that's true ... Except ...&lt;br /&gt;
    Last year I found myself digging in the latest subjects of Web Development.
    Some of these subjects are poor documented and are not handled by many blog articles.
    My goal is to help you fix the issues that I encountered while using open-source modules.
    That, and off course to tell you more about some cool tools / projects I found.
&lt;/p&gt;

&lt;p&gt;
    Let's not let my first blog article go to waste and add some technical information about this blog.
&lt;/p&gt;

&lt;h2 id=&quot;choose-the-right-platform&quot;&gt;Choose the right platform&lt;/h2&gt;

&lt;p&gt;
    The first problem while creating this blog, was deciding which platform to use.
    At first there were the obvious platforms like Wordpress or some well-known hosted services like Blogger.
    Because I rather didn't want to use these platforms, I went on a blog-platform-quest.
    After a while I bumped into &lt;a href=&quot;http://jekyllrb.com/&quot; target=&quot;_blank&quot;&gt;Jekyll&lt;/a&gt;.
    This Ruby based static site generator is easy to use and is perfect for building something as simple as this blog.
    Extra bonus: you can deploy to github pages instead of wasting your own web space!
&lt;/p&gt;
&lt;p&gt;
    Off course, there were dozens of people who already worked with Jekyll before me.
    That is Why I searched for some good articles about building a blog for GitHub pages.
    One of the results I found was the
    &lt;a href=&quot;http://erjjones.github.io/blog/How-I-built-my-blog-in-one-day/&quot; target=&quot;_blank&quot;&gt;&amp;quot;How to build a blog in one day&amp;quot;&lt;/a&gt;
    article by
    &lt;a href=&quot;http://erjjones.github.io/&quot; target=&quot;_blank&quot;&gt;Eric Jones&lt;/a&gt;.
    This was a good place to start, but after some boring repeated tasks like the configuration of tools,
    I found a great tool to build this site:
&lt;/p&gt;

&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;

&lt;p&gt;
    By installing the
    &lt;a href=&quot;https://github.com/robwierzbowski/generator-jekyllrb&quot; target=&quot;_blank&quot;&gt;jekyllrb&lt;/a&gt;
    generator for
    &lt;a href=&quot;http://yeoman.io/&quot; target=&quot;_blank&quot;&gt;yeoman&lt;/a&gt;, all the work was done for me. Following items were configured:
    &lt;ul&gt;
        &lt;li&gt;Files structure&lt;/li&gt;
        &lt;li&gt;Grunt configuration&lt;/li&gt;
        &lt;li&gt;Compass&lt;/li&gt;
        &lt;li&gt;File watcher - which is much better than the default Jekyll watcher!&lt;/li&gt;
        &lt;li&gt;LiveReload&lt;/li&gt;
        &lt;li&gt;Jekyll configuration options&lt;/li&gt;
        &lt;li&gt;Bower: Twitter Bootstrap / jQuery / ...&lt;/li&gt;
    &lt;/ul&gt;

    All that it took to let me focus on the lay-out and content, were 2 commands:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; generator-jekyllrb
~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;yo jekyllrb&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;development&quot;&gt;Development&lt;/h2&gt;
&lt;p&gt;
    The real power of this generator, is the integration with &lt;a href=&quot;gruntjs.com&quot;&gt;grunt&lt;/a&gt;.
    Several handy tasks are pre-configured for you to use. For example:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt serve&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    This command will launch the Jekyll server and will rebuild the static website on file changes.
    When the static site is build, the livereload task will refresh your browser, so you can validate your changes right away.
    Also your compass files will be automatically converted to usable CSS files.
&lt;/p&gt;

&lt;h2 id=&quot;publishing&quot;&gt;Publishing&lt;/h2&gt;
&lt;p&gt;
    So, you finished your blog and want to place it on github.io?
    I forgot to tell you there is one little problem left.
    Github.io uses the root of the master branch to find your index.html file.
    Because yeoman creates your site in a subfolder called &quot;app&quot;, github.io will not find your files.
    That is why we need to separate our development code from the final site.
    The distribution version will be placed on the 'master' branch and the main code will be placed on a separate branch named 'develop'.
    In GIT, this can be done by creating an &lt;a href=&quot;http://www.git-tower.com/files/applicationHelp/pgs/Refs_Branches_DetachedOrphaned.html&quot;&gt;'orphan'&lt;/a&gt; branch, in this case named 'develop'.
    When you finished your blog, the final site should be committed to 'master' and the source code should be committed to 'develop'.
    I hear you say: So much work to deploy my blog?
    Fortunately there is a grunt tool named &lt;a href=&quot;https://npmjs.org/package/grunt-gh-pages&quot;&gt;gh-pages&lt;/a&gt; which does the job.
    I used following configuration which will commit my 'dist' folder of the 'develop' branch to the 'master' branch in git.
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;gh-pages&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;dist&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;branch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;master&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Auto-generated build&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;**/*&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;registerTask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;github-deploy&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;gh-pages&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    Now, when you want to publish your site, it's just one simple command:
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt github-deploy&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
    This will first clean up all temporary files and validate your Jekyll site, javascript and compass files.
    When everything is good to go, it will build the static version of your website for distribution.
    The files in the distribution folder will be minimized and optimized for quick access.
    After all actions are done, the optimized version will be pushed to your master branch, using the gh-pages tool in grunt.
&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;
    With these easy to use, but incredibly powerful tools,
    I hope to focus myself on writing articles about some interesting topics.
    If you want to take a look at my configuration or want to re-use it for your own project,
    feel free to fork &lt;a href=&quot;http://github.com/veewee/veewee.github.io&quot;&gt;veewee.github.io&lt;/a&gt;
    from my &lt;a href=&quot;http://github.com/veewee/&quot; target=&quot;_blank&quot;&gt;GitHub&lt;/a&gt; account.
&lt;/p&gt;
</content>
    </entry>
    
</feed>